diff options
author | Phil Gosch <phil@saphirestudio.at> | 2017-09-29 23:52:29 +0300 |
---|---|---|
committer | Phil Gosch <phil@saphirestudio.at> | 2017-09-29 23:52:29 +0300 |
commit | 2b1ec9c18fadf6b5cd71a7d4122776f5d4b8ac33 (patch) | |
tree | 01b477f0ea027ab5908f332f6102db6a1d381b76 | |
parent | 5cdd4388ffaad5ade916dba3c18e2bc679e19747 (diff) | |
parent | e3546a5097b1b30a3c694ce0f6b98c2f7e70510c (diff) |
Merge remote-tracking branch 'origin/master' into soc-2016-uv_toolssoc-2016-uv_tools
925 files changed, 34503 insertions, 16340 deletions
diff --git a/.gitignore b/.gitignore index 977fd9c2627..814b7661bc6 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,6 @@ Desktop.ini # commonly used paths in blender /blender.bin -/user-config.py /BUILD_NOTES.txt # local patches @@ -34,8 +33,6 @@ Desktop.ini /doc/python_api/sphinx-in/ /doc/python_api/sphinx-out/ /doc/python_api/rst/bmesh.ops.rst -/doc/python_api/rst/in_menu.png -/doc/python_api/rst/menu_id.png -/doc/python_api/rst/op_prop.png -/doc/python_api/rst/run_script.png -/doc/python_api/rst/spacebar.png + +# in-source lib downloads +/build_files/build_environment/downloads diff --git a/CMakeLists.txt b/CMakeLists.txt index 04237812d87..1bb514b14b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -289,7 +289,7 @@ if(WITH_X11) endif() if(UNIX AND NOT APPLE) - option(WITH_SYSTEM_GLEW "Use GLEW OpenGL wrapper library provided by the operating system" ON) + option(WITH_SYSTEM_GLEW "Use GLEW OpenGL wrapper library provided by the operating system" OFF) option(WITH_SYSTEM_GLES "Use OpenGL ES library provided by the operating system" ON) else() # not an option for other OS's @@ -334,10 +334,6 @@ option(WITH_CODEC_SNDFILE "Enable libsndfile Support (http://www.mega-nerd option(WITH_ALEMBIC "Enable Alembic Support" OFF) option(WITH_ALEMBIC_HDF5 "Enable Legacy Alembic Support (not officially supported)" OFF) -if(APPLE) - option(WITH_CODEC_QUICKTIME "Enable Quicktime Support" OFF) -endif() - # 3D format support # Disable opencollada when we don't have precompiled libs option(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.org)" ${_init_OPENCOLLADA}) @@ -504,7 +500,12 @@ endif() # Experimental support of C11 and C++11 # # We default options to whatever default standard in the current compiler. -if(CMAKE_COMPILER_IS_GNUCC AND (NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "6.0") AND (NOT WITH_CXX11)) +if(APPLE) + set(_c11_init ON) + set(_cxx11_init ON) + set(WITH_C11 ON) + set(WITH_CXX11 ON) +elseif(CMAKE_COMPILER_IS_GNUCC AND (NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "6.0") AND (NOT WITH_CXX11)) set(_c11_init ON) set(_cxx11_init ON) else() @@ -738,10 +739,6 @@ if(WITH_AUDASPACE) endif() endif() -if(APPLE) - apple_check_quicktime() -endif() - #----------------------------------------------------------------------------- # Check for valid directories # ... a partial checkout may cause this. @@ -1480,6 +1477,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC") "/wd4800" # forcing value to bool 'true' or 'false' # errors: "/we4013" # 'function' undefined; assuming extern returning int + "/we4133" # incompatible pointer types "/we4431" # missing type specifier - int assumed ) @@ -1759,4 +1757,3 @@ endif() if(0) print_all_vars() endif() - diff --git a/GNUmakefile b/GNUmakefile index ba7f89c3097..1143ac6e1f1 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -43,6 +43,11 @@ ifndef BUILD_DIR BUILD_DIR:=$(shell dirname "$(BLENDER_DIR)")/build_$(OS_NCASE) endif +# Dependencies DIR's +DEPS_SOURCE_DIR:=$(BLENDER_DIR)/build_files/build_environment +DEPS_BUILD_DIR:=$(BUILD_DIR)/deps +DEPS_INSTALL_DIR:=$(shell dirname "$(BLENDER_DIR)")/lib/$(OS_NCASE) + # Allow to use alternative binary (pypy3, etc) ifndef PYTHON PYTHON:=python3 @@ -86,13 +91,7 @@ ifndef NPROCS ifeq ($(OS), Linux) NPROCS:=$(shell nproc) endif - ifeq ($(OS), Darwin) - NPROCS:=$(shell sysctl -n hw.ncpu) - endif - ifeq ($(OS), FreeBSD) - NPROCS:=$(shell sysctl -n hw.ncpu) - endif - ifeq ($(OS), NetBSD) + ifneq (,$(filter $(OS),Darwin FreeBSD NetBSD)) NPROCS:=$(shell sysctl -n hw.ncpu) endif endif @@ -146,6 +145,27 @@ cycles: all headless: all bpy: all +# ----------------------------------------------------------------------------- +# Build dependencies +DEPS_TARGET = install +ifneq "$(findstring clean, $(MAKECMDGOALS))" "" + DEPS_TARGET = clean +endif + +deps: .FORCE + @echo + @echo Configuring dependencies in \"$(DEPS_BUILD_DIR)\" + + @cmake -H"$(DEPS_SOURCE_DIR)" \ + -B"$(DEPS_BUILD_DIR)" \ + -DHARVEST_TARGET=$(DEPS_INSTALL_DIR) + + @echo + @echo Building dependencies ... + $(MAKE) -C "$(DEPS_BUILD_DIR)" -s -j $(NPROCS) $(DEPS_TARGET) + @echo + @echo Dependencies successfully built and installed to $(DEPS_INSTALL_DIR). + @echo # ----------------------------------------------------------------------------- # Configuration (save some cd'ing around) @@ -164,6 +184,7 @@ help: .FORCE @echo " * headless - build without an interface (renderfarm or server automation)" @echo " * cycles - build Cycles standalone only, without Blender" @echo " * bpy - build as a python module which can be loaded from python directly" + @echo " * deps - build library dependencies (intended only for platform maintainers)" @echo "" @echo " * config - run cmake configuration tool to set build options" @echo "" @@ -398,10 +419,16 @@ icons: .FORCE "$(BLENDER_DIR)/release/datafiles/prvicons_update.py" update: .FORCE + if [ "$(OS_NCASE)" == "darwin" ] && [ ! -d "../lib/$(OS_NCASE)" ]; then \ + svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/$(OS_NCASE) ../lib/$(OS_NCASE) ; \ + fi if [ -d "../lib" ]; then \ + svn cleanup ../lib/* ; \ svn update ../lib/* ; \ fi git pull --rebase + git submodule update --init --recursive + git submodule foreach git checkout master git submodule foreach git pull --rebase origin master diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt new file mode 100644 index 00000000000..9f7eb3c2c50 --- /dev/null +++ b/build_files/build_environment/CMakeLists.txt @@ -0,0 +1,132 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +#################################################################################################### +# +# This is a build system used by platform maintainers to build library dependencies on +# Windows and macOS. There is some support for Linux as well, but not ready for releases. +# +# Windows and macOS users should download the precompiled libraries in lib/, Linux users +# should run install_deps.sh for building dependencies. +# +# WINDOWS USAGE: +# Don't call this cmake file your self, use build_deps.cmd +# build_deps 2013 x64 / build_deps 2013 x86 +# build_deps 2015 x64 / build_deps 2015 x86 +# +# MAC OS X USAGE: +# Install with homebrew: brew install autoconf automake libtool yasm openssl xz +# Run "make deps" from main Blender directory +# +# LINUX USAGE: +# Install compiler, cmake, autoconf, automake, libtool, yasm +# Run "make deps" from main Blender directory +# +#################################################################################################### + +project("BlenderDependencies") +cmake_minimum_required(VERSION 3.5) + +include(ExternalProject) +include(cmake/options.cmake) +include(cmake/versions.cmake) +include(cmake/zlib.cmake) +include(cmake/blendthumb.cmake) +include(cmake/openal.cmake) +include(cmake/png.cmake) +include(cmake/jpeg.cmake) +include(cmake/boost.cmake) +include(cmake/blosc.cmake) +include(cmake/pthreads.cmake) +include(cmake/ilmbase.cmake) +include(cmake/openexr.cmake) +include(cmake/freetype.cmake) +include(cmake/freeglut.cmake) +include(cmake/glew.cmake) +include(cmake/hdf5.cmake) +include(cmake/alembic.cmake) +include(cmake/glfw.cmake) +include(cmake/clew.cmake) +include(cmake/cuew.cmake) +include(cmake/opensubdiv.cmake) +include(cmake/sdl.cmake) +include(cmake/opencollada.cmake) +include(cmake/opencolorio.cmake) +include(cmake/llvm.cmake) +include(cmake/clang.cmake) +include(cmake/openimageio.cmake) +include(cmake/tiff.cmake) +include(cmake/flexbison.cmake) +include(cmake/osl.cmake) +include(cmake/tbb.cmake) +include(cmake/openvdb.cmake) +include(cmake/python.cmake) +include(cmake/python_site_packages.cmake) +include(cmake/numpy.cmake) +if (WITH_WEBP) + include(cmake/webp.cmake) +endif() +if(WIN32) + include(cmake/hidapi.cmake) +endif() + +if(ENABLE_MINGW64) + if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + include(cmake/setup_mingw64.cmake) + else() + include(cmake/setup_mingw32.cmake) + endif() +else() + set(mingw_LIBDIR ${LIBDIR}) +endif() + +if(NOT WIN32 OR ENABLE_MINGW64) + include(cmake/openjpeg.cmake) + if(BUILD_MODE STREQUAL Release) + if(WIN32) + include(cmake/zlib_mingw.cmake) + endif() + include(cmake/lame.cmake) + include(cmake/ogg.cmake) + include(cmake/vorbis.cmake) + include(cmake/theora.cmake) + include(cmake/vpx.cmake) + include(cmake/orc.cmake) + include(cmake/schroedinger.cmake) + include(cmake/x264.cmake) + include(cmake/xvidcore.cmake) + include(cmake/faad.cmake) + include(cmake/ffmpeg.cmake) + include(cmake/fftw.cmake) + include(cmake/sndfile.cmake) + if(WIN32) + include(cmake/iconv.cmake) + include(cmake/lapack.cmake) + endif() + if(UNIX) + include(cmake/flac.cmake) + if(NOT APPLE) + include(cmake/spnav.cmake) + include(cmake/jemalloc.cmake) + include(cmake/xml2.cmake) + endif() + endif() + endif() +endif() + +include(cmake/harvest.cmake) diff --git a/build_files/build_environment/cmake/alembic.cmake b/build_files/build_environment/cmake/alembic.cmake new file mode 100644 index 00000000000..a49047ec102 --- /dev/null +++ b/build_files/build_environment/cmake/alembic.cmake @@ -0,0 +1,75 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(ALEMBIC_HDF5) + set(ALEMBIC_HDF5_HL) + # in debug mode we do not build HDF5_hdf5_hl_LIBRARY which makes cmake really + # unhappy, stub it with the debug mode lib. it's not linking it in at this + # point in time anyhow + if(BUILD_MODE STREQUAL Debug) + set(ALEMBIC_HDF5_HL -DHDF5_hdf5_hl_LIBRARY=${LIBDIR}/hdf5/lib/libhdf5_hl_D.${LIBEXT}) + endif() +endif() + +set(ALEMBIC_EXTRA_ARGS + -DBUILDSTATIC=ON + -DLINKSTATIC=ON + -DALEMBIC_LIB_USES_BOOST=ON + -DBoost_COMPILER:STRING=${BOOST_COMPILER_STRING} + -DBoost_USE_MULTITHREADED=ON + -DUSE_STATIC_BOOST=On + -DBoost_USE_STATIC_LIBS=ON + -DBoost_USE_STATIC_RUNTIME=ON + -DBoost_DEBUG=ON + -DBOOST_ROOT=${LIBDIR}/boost + -DBoost_NO_SYSTEM_PATHS=ON + -DILMBASE_ROOT=${LIBDIR}/ilmbase + -DALEMBIC_ILMBASE_INCLUDE_DIRECTORY=${LIBDIR}/ilmbase/include/OpenEXR + -DALEMBIC_ILMBASE_HALF_LIB=${LIBDIR}/ilmbase/lib/${LIBPREFIX}Half${LIBEXT} + -DALEMBIC_ILMBASE_IMATH_LIB=${LIBDIR}/ilmbase/lib/${LIBPREFIX}Imath-2_2${LIBEXT} + -DALEMBIC_ILMBASE_ILMTHREAD_LIB=${LIBDIR}/ilmbase/lib/${LIBPREFIX}IlmThread-2_2${LIBEXT} + -DALEMBIC_ILMBASE_IEX_LIB=${LIBDIR}/ilmbase/lib/${LIBPREFIX}Iex-2_2${LIBEXT} + -DUSE_PYILMBASE=0 + -DUSE_PYALEMBIC=0 + -DUSE_ARNOLD=0 + -DUSE_MAYA=0 + -DUSE_PRMAN=0 + -DUSE_HDF5=Off + -DUSE_STATIC_HDF5=Off + -DHDF5_ROOT=${LIBDIR}/hdf5 + -DUSE_TESTS=Off + -DALEMBIC_NO_OPENGL=1 + -DUSE_BINARIES=ON + -DALEMBIC_ILMBASE_LINK_STATIC=On + -DALEMBIC_SHARED_LIBS=OFF + -DGLUT_INCLUDE_DIR="" + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + ${ALEMBIC_HDF5_HL} +) + +ExternalProject_Add(external_alembic + URL ${ALEMBIC_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${ALEMBIC_MD5} + PREFIX ${BUILD_DIR}/alembic + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/alembic -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${ALEMBIC_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/alembic +) + +add_dependencies(external_alembic external_boost external_zlib external_ilmbase) diff --git a/build_files/build_environment/cmake/blendthumb.cmake b/build_files/build_environment/cmake/blendthumb.cmake new file mode 100644 index 00000000000..624869971c6 --- /dev/null +++ b/build_files/build_environment/cmake/blendthumb.cmake @@ -0,0 +1,61 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(BUILD_MODE STREQUAL Release) + if(WIN32) + set(THUMB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../release/windows/blendthumb) + + ExternalProject_Add(external_zlib_32 + URL ${ZLIB_URI} + CMAKE_GENERATOR ${GENERATOR_32} + URL_HASH MD5=${ZLIB_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/zlib32 + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/zlib32 ${DEFAULT_CMAKE_FLAGS} + INSTALL_DIR ${LIBDIR}/zlib32 + ) + + ExternalProject_Add(external_zlib_64 + URL ${ZLIB_URI} + CMAKE_GENERATOR ${GENERATOR_64} + URL_HASH MD5=${ZLIB_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/zlib64 + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/zlib64 ${DEFAULT_CMAKE_FLAGS} + INSTALL_DIR ${LIBDIR}/zlib64 + ) + + ExternalProject_Add(external_blendthumb_32 + CMAKE_GENERATOR ${GENERATOR_32} + SOURCE_DIR ${THUMB_DIR} + PREFIX ${BUILD_DIR}/blendthumb32 + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/blendThumb32 ${DEFAULT_CMAKE_FLAGS} -DZLIB_INCLUDE=${LIBDIR}/zlib32/include -DZLIB_LIBS=${LIBDIR}/zlib32/lib/zlibstatic.lib + INSTALL_DIR ${LIBDIR}/blendthumb32 + ) + add_dependencies(external_blendthumb_32 external_zlib_32) + + ExternalProject_Add(external_blendthumb_64 + CMAKE_GENERATOR ${GENERATOR_64} + SOURCE_DIR ${THUMB_DIR} + PREFIX ${BUILD_DIR}/blendthumb64 + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/blendThumb64 ${DEFAULT_CMAKE_FLAGS} -DZLIB_INCLUDE=${LIBDIR}/zlib64/include -DZLIB_LIBS=${LIBDIR}/zlib64/lib/zlibstatic.lib + INSTALL_DIR ${LIBDIR}/blendthumb64 + ) + add_dependencies(external_blendthumb_64 external_zlib_64) + endif() +endif() diff --git a/build_files/build_environment/cmake/blosc.cmake b/build_files/build_environment/cmake/blosc.cmake new file mode 100644 index 00000000000..68df525b802 --- /dev/null +++ b/build_files/build_environment/cmake/blosc.cmake @@ -0,0 +1,43 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(BLOSC_EXTRA_ARGS + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DBUILD_TESTS=OFF + -DBUILD_BENCHMARKS=OFF + -DCMAKE_DEBUG_POSTFIX=_d + -DThreads_FOUND=1 + -DPTHREAD_LIBS=${LIBDIR}/pthreads/lib/pthreadVC2.lib + -DPTHREAD_INCLUDE_DIR=${LIBDIR}/pthreads/inc +) + +ExternalProject_Add(external_blosc + URL ${BLOSC_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${BLOSC_HASH} + PREFIX ${BUILD_DIR}/blosc + PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/blosc/src/external_blosc < ${PATCH_DIR}/blosc.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/blosc ${DEFAULT_CMAKE_FLAGS} ${BLOSC_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/blosc +) + +add_dependencies(external_blosc external_zlib) +if(WIN32) + add_dependencies(external_blosc external_pthreads) +endif() diff --git a/build_files/build_environment/cmake/boost.cmake b/build_files/build_environment/cmake/boost.cmake new file mode 100644 index 00000000000..d98df30a38f --- /dev/null +++ b/build_files/build_environment/cmake/boost.cmake @@ -0,0 +1,107 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(PYTHON_ARCH x64) + set(PYTHON_ARCH2 win-AMD64) + set(PYTHON_OUTPUTDIR ${BUILD_DIR}/python/src/external_python/pcbuild/amd64/) + else() + set(PYTHON_ARCH x86) + set(PYTHON_ARCH2 win32) + set(PYTHON_OUTPUTDIR ${BUILD_DIR}/python/src/external_python/pcbuild/win32/) + endif() + if(MSVC12) + set(BOOST_TOOLSET toolset=msvc-12.0) + set(BOOST_COMPILER_STRING -vc120) + set(PYTHON_COMPILER_STRING v120) + endif() + if(MSVC14) + set(BOOST_TOOLSET toolset=msvc-14.0) + set(BOOST_COMPILER_STRING -vc140) + set(PYTHON_COMPILER_STRING v140) + endif() + set(JAM_FILE ${BUILD_DIR}/boost/src/external_boost/user-config.jam) + set(semi_path "${PATCH_DIR}/semi.txt") + FILE(TO_NATIVE_PATH ${semi_path} semi_path) + set(BOOST_CONFIGURE_COMMAND bootstrap.bat && + echo using python : ${PYTHON_OUTPUTDIR}\\python.exe > "${JAM_FILE}" && + echo. : ${BUILD_DIR}/python/src/external_python/include ${BUILD_DIR}/python/src/external_python/pc >> "${JAM_FILE}" && + echo. : ${BUILD_DIR}/python/src/external_python/pcbuild >> "${JAM_FILE}" && + type ${semi_path} >> "${JAM_FILE}" + ) + set(BOOST_BUILD_COMMAND bjam) + #--user-config=user-config.jam + set(BOOST_BUILD_OPTIONS runtime-link=static ) + #set(BOOST_WITH_PYTHON --with-python) + set(BOOST_HARVEST_CMD ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/boost/lib/ ${HARVEST_TARGET}/boost/lib/ ) + if(BUILD_MODE STREQUAL Release) + set(BOOST_HARVEST_CMD ${BOOST_HARVEST_CMD} && ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/boost/include/boost-1_60/ ${HARVEST_TARGET}/boost/include/) + endif() + +elseif(APPLE) + set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh) + set(BOOST_BUILD_COMMAND ./bjam) + set(BOOST_BUILD_OPTIONS toolset=clang cxxflags=${PLATFORM_CXXFLAGS} linkflags=${PLATFORM_LDFLAGS} --disable-icu boost.locale.icu=off) + set(BOOST_HARVEST_CMD echo .) +else() + set(BOOST_HARVEST_CMD echo .) + set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh) + set(BOOST_BUILD_COMMAND ./bjam) + set(BOOST_BUILD_OPTIONS cxxflags=${PLATFORM_CXXFLAGS} --disable-icu boost.locale.icu=off) +endif() + +set(BOOST_OPTIONS + --with-filesystem + --with-locale + --with-thread + --with-regex + --with-system + --with-date_time + --with-wave + --with-atomic + --with-serialization + --with-program_options + --with-iostreams + ${BOOST_WITH_PYTHON} + ${BOOST_TOOLSET} +) + +if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(BOOST_ADDRESS_MODEL 64) +else() + set(BOOST_ADDRESS_MODEL 32) +endif() + +string(TOLOWER ${BUILD_MODE} BOOST_BUILD_TYPE) + +ExternalProject_Add(external_boost + URL ${BOOST_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${BOOST_MD5} + PREFIX ${BUILD_DIR}/boost + UPDATE_COMMAND "" + CONFIGURE_COMMAND ${BOOST_CONFIGURE_COMMAND} + BUILD_COMMAND ${BOOST_BUILD_COMMAND} ${BOOST_BUILD_OPTIONS} -j${MAKE_THREADS} architecture=x86 address-model=${BOOST_ADDRESS_MODEL} variant=${BOOST_BUILD_TYPE} link=static threading=multi ${BOOST_OPTIONS} --prefix=${LIBDIR}/boost install + BUILD_IN_SOURCE 1 + INSTALL_COMMAND "${BOOST_HARVEST_CMD}" +) + +if(WIN32) + add_dependencies(external_boost Make_Python_Environment) +endif() diff --git a/build_files/build_environment/cmake/clang.cmake b/build_files/build_environment/cmake/clang.cmake new file mode 100644 index 00000000000..2c7f271b5fc --- /dev/null +++ b/build_files/build_environment/cmake/clang.cmake @@ -0,0 +1,51 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(CLANG_EXTRA_ARGS + -DCLANG_PATH_TO_LLVM_SOURCE=${BUILD_DIR}/ll/src/ll + -DCLANG_PATH_TO_LLVM_BUILD=${LIBDIR}/llvm + -DLLVM_USE_CRT_RELEASE=MT + -DLLVM_USE_CRT_DEBUG=MTd +) +ExternalProject_Add(external_clang + URL ${CLANG_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${CLANG_HASH} + PATCH_COMMAND ${PATCH_CMD} -p 2 -N -R -d ${BUILD_DIR}/clang/src/external_clang < ${PATCH_DIR}/clang.diff + PREFIX ${BUILD_DIR}/clang + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/clang ${DEFAULT_CMAKE_FLAGS} ${CLANG_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/clang +) + +if (MSVC) + if (BUILD_MODE STREQUAL Release) + set(CLANG_HARVEST_COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/clang/ ${HARVEST_TARGET}/llvm/ ) + else() + set(CLANG_HARVEST_COMMAND + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/clang/lib/ ${HARVEST_TARGET}/llvm/debug/lib/ && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/clang/bin/ ${HARVEST_TARGET}/llvm/debug/bin/ && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/clang/include/ ${HARVEST_TARGET}/llvm/debug/include/ + ) + endif() + ExternalProject_Add_Step(external_clang after_install + COMMAND ${CLANG_HARVEST_COMMAND} + DEPENDEES mkdir update patch download configure build install + ) +endif() + +add_dependencies(external_clang ll) diff --git a/build_files/build_environment/cmake/clew.cmake b/build_files/build_environment/cmake/clew.cmake new file mode 100644 index 00000000000..0dcc1f24db7 --- /dev/null +++ b/build_files/build_environment/cmake/clew.cmake @@ -0,0 +1,28 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(CLEW_EXTRA_ARGS) + +ExternalProject_Add(external_clew + URL ${CLEW_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${CLEW_HASH} + PREFIX ${BUILD_DIR}/clew + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/clew -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${CLEW_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/clew +) diff --git a/build_files/build_environment/cmake/cuew.cmake b/build_files/build_environment/cmake/cuew.cmake new file mode 100644 index 00000000000..99b7bb5c06d --- /dev/null +++ b/build_files/build_environment/cmake/cuew.cmake @@ -0,0 +1,29 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(CUEW_EXTRA_ARGS) + +ExternalProject_Add(external_cuew + URL ${CUEW_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${CUEW_HASH} + PREFIX ${BUILD_DIR}/cuew + PATCH_COMMAND ${PATCH_CMD} --verbose -p 0 -N -d ${BUILD_DIR}/cuew/src/external_cuew < ${PATCH_DIR}/cuew.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/cuew -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${CUEW_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/cuew +) diff --git a/build_files/build_environment/cmake/faad.cmake b/build_files/build_environment/cmake/faad.cmake new file mode 100644 index 00000000000..3dd90971b84 --- /dev/null +++ b/build_files/build_environment/cmake/faad.cmake @@ -0,0 +1,35 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(FAAD_EXTRA_ARGS) + +ExternalProject_Add(external_faad + URL ${FAAD_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${FAAD_HASH} + PREFIX ${BUILD_DIR}/faad + PATCH_COMMAND ${PATCH_CMD} --verbose -p 0 -N -d ${BUILD_DIR}/faad/src/external_faad < ${PATCH_DIR}/libfaad.diff + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/faad/src/external_faad/ && ${CONFIGURE_COMMAND} --disable-shared --enable-static --prefix=${LIBDIR}/faad + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/faad/src/external_faad/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/faad/src/external_faad/ && make install + INSTALL_DIR ${LIBDIR}/faad +) + +if(MSVC) + set_target_properties(external_faad PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/ffmpeg.cmake b/build_files/build_environment/cmake/ffmpeg.cmake new file mode 100644 index 00000000000..2a45849acf5 --- /dev/null +++ b/build_files/build_environment/cmake/ffmpeg.cmake @@ -0,0 +1,119 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(FFMPEG_CFLAGS "-I${mingw_LIBDIR}/lame/include -I${mingw_LIBDIR}/openjpeg/include/ -I${mingw_LIBDIR}/ogg/include -I${mingw_LIBDIR}/vorbis/include -I${mingw_LIBDIR}/theora/include -I${mingw_LIBDIR}/vpx/include -I${mingw_LIBDIR}/x264/include -I${mingw_LIBDIR}/xvidcore/include -I${mingw_LIBDIR}/dirac/include/dirac -I${mingw_LIBDIR}/schroedinger/include/schroedinger-1.0 -I${mingw_LIBDIR}/zlib/include") +set(FFMPEG_LDFLAGS "-L${mingw_LIBDIR}/lame/lib -L${mingw_LIBDIR}/openjpeg/lib -L${mingw_LIBDIR}/ogg/lib -L${mingw_LIBDIR}/vorbis/lib -L${mingw_LIBDIR}/theora/lib -L${mingw_LIBDIR}/vpx/lib -L${mingw_LIBDIR}/x264/lib -L${mingw_LIBDIR}/xvidcore/lib -L${mingw_LIBDIR}/dirac/lib -L${mingw_LIBDIR}/schroedinger/lib -L${mingw_LIBDIR}/orc/lib -L${mingw_LIBDIR}/zlib/lib") +set(FFMPEG_EXTRA_FLAGS --extra-cflags=${FFMPEG_CFLAGS} --extra-ldflags=${FFMPEG_LDFLAGS}) +set(FFMPEG_ENV PKG_CONFIG_PATH=${mingw_LIBDIR}/schroedinger/lib/pkgconfig:${mingw_LIBDIR}/orc/lib/pkgconfig:${mingw_LIBDIR}/x264/lib/pkgconfig:${mingw_LIBDIR}) + +if(WIN32) + set(FFMPEG_ENV set ${FFMPEG_ENV} &&) + set(FFMPEG_EXTRA_FLAGS + ${FFMPEG_EXTRA_FLAGS} + --disable-static + --enable-shared + --enable-w32threads + --disable-pthreads + --enable-libopenjpeg + ) +else() + set(FFMPEG_EXTRA_FLAGS + ${FFMPEG_EXTRA_FLAGS} + --enable-static + --disable-shared + --enable-libopenjpeg) +endif() + +if(APPLE) + set(FFMPEG_EXTRA_FLAGS + ${FFMPEG_EXTRA_FLAGS} + --target-os=darwin + ) +endif() + +ExternalProject_Add(external_ffmpeg + URL ${FFMPEG_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${FFMPEG_HASH} + PREFIX ${BUILD_DIR}/ffmpeg + CONFIGURE_COMMAND ${CONFIGURE_ENV_NO_PERL} && + cd ${BUILD_DIR}/ffmpeg/src/external_ffmpeg/ && + ${FFMPEG_ENV} ${CONFIGURE_COMMAND_NO_TARGET} ${FFMPEG_EXTRA_FLAGS} + --disable-lzma + --disable-avfilter + --disable-vdpau + --disable-bzlib + --disable-libgsm + --disable-libspeex + --enable-libvpx + --prefix=${LIBDIR}/ffmpeg + --enable-libschroedinger + --enable-libtheora + --enable-libvorbis + --enable-zlib + --enable-stripping + --enable-runtime-cpudetect + --disable-vaapi + --disable-nonfree + --enable-gpl + --disable-postproc + --disable-x11grab + --enable-libmp3lame + --disable-librtmp + --enable-libx264 + --enable-libxvid + --disable-libopencore-amrnb + --disable-libopencore-amrwb + --disable-libdc1394 + --disable-version3 + --disable-debug + --enable-optimizations + --disable-sse + --disable-ssse3 + --enable-ffplay + --disable-openssl + --disable-securetransport + --disable-indev=avfoundation + --disable-indev=qtkit + --disable-sdl + --disable-gnutls + --disable-vda + --disable-videotoolbox + --disable-libxcb + --disable-xlib + --disable-audiotoolbox + --disable-cuvid + --disable-nvenc + --disable-indev=jack + --disable-indev=alsa + --disable-outdev=alsa + PATCH_COMMAND ${PATCH_CMD} --verbose -p 0 -N -d ${BUILD_DIR}/ffmpeg/src/external_ffmpeg < ${PATCH_DIR}/ffmpeg.diff + BUILD_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/ffmpeg/src/external_ffmpeg/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/ffmpeg/src/external_ffmpeg/ && make install + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/ffmpeg ${DEFAULT_CMAKE_FLAGS} + INSTALL_DIR ${LIBDIR}/ffmpeg +) + +if(MSVC) + set_target_properties(external_ffmpeg PROPERTIES FOLDER Mingw) +endif(MSVC) + +add_dependencies(external_ffmpeg external_zlib external_faad external_openjpeg external_xvidcore external_x264 external_schroedinger external_vpx external_theora external_vorbis external_ogg external_lame) +if(WIN32) + add_dependencies(external_ffmpeg external_zlib_mingw) +endif() diff --git a/build_files/build_environment/cmake/fftw.cmake b/build_files/build_environment/cmake/fftw.cmake new file mode 100644 index 00000000000..e6e6165199c --- /dev/null +++ b/build_files/build_environment/cmake/fftw.cmake @@ -0,0 +1,40 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(FFTW_EXTRA_ARGS) + +if(WIN32) + set(FFTW3_ENV set CFLAGS=-fno-stack-check -fno-stack-protector -mno-stack-arg-probe -fno-lto &&) + set(FFTW3_PATCH_COMMAND ${PATCH_CMD} --verbose -p 0 -N -d ${BUILD_DIR}/fftw3/src/external_fftw3 < ${PATCH_DIR}/fftw3.diff) +endif() + +ExternalProject_Add(external_fftw3 + URL ${FFTW_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${FFTW_HASH} + PREFIX ${BUILD_DIR}/fftw3 + CONFIGURE_COMMAND ${CONFIGURE_ENV} && ${FFTW3_ENV} cd ${BUILD_DIR}/fftw3/src/external_fftw3/ && ${CONFIGURE_COMMAND} --enable-static --prefix=${mingw_LIBDIR}/fftw3 + PATCH_COMMAND ${FFTW3_PATCH_COMMAND} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3/ && make install + INSTALL_DIR ${LIBDIR}/fftw3 +) + +if(MSVC) + set_target_properties(external_fftw3 PROPERTIES FOLDER Mingw) +endif(MSVC) diff --git a/build_files/build_environment/cmake/flac.cmake b/build_files/build_environment/cmake/flac.cmake new file mode 100644 index 00000000000..74d222632d0 --- /dev/null +++ b/build_files/build_environment/cmake/flac.cmake @@ -0,0 +1,32 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +ExternalProject_Add(external_flac + URL ${FLAC_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA256=${FLAC_HASH} + PREFIX ${BUILD_DIR}/flac + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flac/src/external_flac/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/flac --disable-shared --enable-static + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flac/src/external_flac/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flac/src/external_flac/ && make install + INSTALL_DIR ${LIBDIR}/flac +) + +if(MSVC) + set_target_properties(external_flac PROPERTIES FOLDER Mingw) +endif(MSVC) diff --git a/build_files/build_environment/cmake/flexbison.cmake b/build_files/build_environment/cmake/flexbison.cmake new file mode 100644 index 00000000000..f2908e1ce2c --- /dev/null +++ b/build_files/build_environment/cmake/flexbison.cmake @@ -0,0 +1,31 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(FLEXBISON_EXTRA_ARGS) + +ExternalProject_Add(external_flexbison + URL ${FLEXBISON_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${FLEXBISON_HASH} + PREFIX ${BUILD_DIR}/flexbison + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/flexbison ${DEFAULT_CMAKE_FLAGS} ${FLEXBISON_EXTRA_ARGS} + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND COMMAND ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR}/flexbison/src/external_flexbison/ ${LIBDIR}/flexbison/ + INSTALL_DIR ${LIBDIR}/flexbison +) diff --git a/build_files/build_environment/cmake/freeglut.cmake b/build_files/build_environment/cmake/freeglut.cmake new file mode 100644 index 00000000000..043b382e8fd --- /dev/null +++ b/build_files/build_environment/cmake/freeglut.cmake @@ -0,0 +1,35 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + set(FREEGLUT_EXTRA_ARGS + -DFREEGLUT_BUILD_SHARED_LIBS=Off + -DFREEGLUT_BUILD_STATIC_LIBS=On + ) + + ExternalProject_Add(external_freeglut + URL ${FREEGLUT_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${FREEGLUT_HASH} + PREFIX ${BUILD_DIR}/freeglut + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/freeglut ${DEFAULT_C_FLAGS} ${DEFAULT_CXX_FLAGS} ${FREEGLUT_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/freeglut + ) + endif() +endif() diff --git a/build_files/build_environment/cmake/freetype.cmake b/build_files/build_environment/cmake/freetype.cmake new file mode 100644 index 00000000000..751b2b1f383 --- /dev/null +++ b/build_files/build_environment/cmake/freetype.cmake @@ -0,0 +1,28 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(FREETYPE_EXTRA_ARGS -DCMAKE_RELEASE_POSTFIX:STRING=2ST -DCMAKE_DEBUG_POSTFIX:STRING=2ST_d -DWITH_BZip2=OFF -DWITH_HarfBuzz=OFF) + +ExternalProject_Add(external_freetype + URL ${FREETYPE_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${FREETYPE_HASH} + PREFIX ${BUILD_DIR}/freetype + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/freetype ${DEFAULT_CMAKE_FLAGS} ${FREETYPE_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/freetype +) diff --git a/build_files/build_environment/cmake/glew.cmake b/build_files/build_environment/cmake/glew.cmake new file mode 100644 index 00000000000..b5d9e4d3310 --- /dev/null +++ b/build_files/build_environment/cmake/glew.cmake @@ -0,0 +1,32 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(GLEW_EXTRA_ARGS + -DBUILD_UTILS=Off + -DBUILD_SHARED_LIBS=Off +) + +ExternalProject_Add(external_glew + URL ${GLEW_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${GLEW_HASH} + PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_glew.txt ${BUILD_DIR}/glew/src/external_glew/CMakeLists.txt + PREFIX ${BUILD_DIR}/glew + CMAKE_ARGS -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${LIBDIR}/glew ${DEFAULT_CMAKE_FLAGS} ${GLEW_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/glew +) diff --git a/build_files/build_environment/cmake/glfw.cmake b/build_files/build_environment/cmake/glfw.cmake new file mode 100644 index 00000000000..ae80080525c --- /dev/null +++ b/build_files/build_environment/cmake/glfw.cmake @@ -0,0 +1,28 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(GLFW_EXTRA_ARGS) + +ExternalProject_Add(external_glfw + URL ${GLFW_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${GLFW_HASH} + PREFIX ${BUILD_DIR}/glfw + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/glfw -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${GLFW_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/glfw +) diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake new file mode 100644 index 00000000000..a430c4b33bf --- /dev/null +++ b/build_files/build_environment/cmake/harvest.cmake @@ -0,0 +1,279 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +######################################################################## +# Copy all generated files to the proper strucure as blender prefers +######################################################################## + +if(NOT DEFINED HARVEST_TARGET) + set(HARVEST_TARGET ${CMAKE_CURRENT_SOURCE_DIR}/Harvest) +endif() +message("HARVEST_TARGET = ${HARVEST_TARGET}") + +if(WIN32) + +if(BUILD_MODE STREQUAL Release) + add_custom_target(Harvest_Release_Results + # Zlib Rename the lib file and copy the include/bin folders + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/zlib/lib/zlibstatic.lib ${HARVEST_TARGET}/zlib/lib/libz_st.lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/zlib/include/ ${HARVEST_TARGET}/zlib/include/ && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/zlib/bin/ ${HARVEST_TARGET}/zlib/bin/ && + # jpeg rename libfile + copy include + ${CMAKE_COMMAND} -E copy ${LIBDIR}/jpg/lib/jpeg-static.lib ${HARVEST_TARGET}/jpeg/lib/libjpeg.lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/jpg/include/ ${HARVEST_TARGET}/jpeg/include/ && + # FreeType, straight up copy + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/freetype ${HARVEST_TARGET}/freetype && + # pthreads, rename include dir + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/pthreads/inc/ ${HARVEST_TARGET}/pthreads/include/ && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/pthreads/lib/ ${HARVEST_TARGET}/pthreads/lib && + # ffmpeg copy include+bin + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/ffmpeg/include ${HARVEST_TARGET}/ffmpeg/include && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/ffmpeg/bin ${HARVEST_TARGET}/ffmpeg/lib && + # sdl merge bin/lib folder, copy include + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/sdl/include/sdl2 ${HARVEST_TARGET}/sdl/include && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/sdl/lib ${HARVEST_TARGET}/sdl/lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/sdl/bin ${HARVEST_TARGET}/sdl/lib && + # openal + ${CMAKE_COMMAND} -E copy ${LIBDIR}/openal/lib/openal32.lib ${HARVEST_TARGET}/openal/lib/openal32.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/openal/bin/openal32.dll ${HARVEST_TARGET}/openal/lib/openal32.dll && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openal/include/ ${HARVEST_TARGET}/openal/include/ && + # OpenImageIO + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/OpenImageIO/include ${HARVEST_TARGET}/OpenImageIO/include && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/OpenImageIO/lib ${HARVEST_TARGET}/OpenImageIO/lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/OpenImageIO/bin/idiff.exe ${HARVEST_TARGET}/OpenImageIO/bin/idiff.exe && + # openEXR + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/ilmbase ${HARVEST_TARGET}/openexr && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openexr/lib ${HARVEST_TARGET}/openexr/lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openexr/include ${HARVEST_TARGET}/openexr/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/ && + # fftw3 + ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/lib/libfftw3.a ${HARVEST_TARGET}/fftw3/lib/libfftw.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/include/fftw3.h ${HARVEST_TARGET}/fftw3/include/fftw3.h && + # 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/ && + # glew-> opengl + ${CMAKE_COMMAND} -E copy ${LIBDIR}/glew/lib/libglew32.lib ${HARVEST_TARGET}/opengl/lib/glew.lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/glew/include/ ${HARVEST_TARGET}/opengl/include/ && + # sndfile + ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/lib/libsndfile.dll.a ${HARVEST_TARGET}/sndfile/lib/libsndfile-1.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/bin/libsndfile-1.dll ${HARVEST_TARGET}/sndfile/lib/libsndfile-1.dll && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/include/sndfile.h ${HARVEST_TARGET}/sndfile/include/sndfile.h && + # tiff + ${CMAKE_COMMAND} -E copy ${LIBDIR}/tiff/lib/tiff.lib ${HARVEST_TARGET}/tiff/lib/libtiff.lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/tiff/include/ ${HARVEST_TARGET}/tiff/include/ && + # iconv + ${CMAKE_COMMAND} -E copy ${LIBDIR}/iconv/lib/libiconv.a ${HARVEST_TARGET}/iconv/lib/iconv.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/iconv/include/iconv.h ${HARVEST_TARGET}/iconv/include/iconv.h && + # opencolorIO + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/OpenColorIO/ ${HARVEST_TARGET}/opencolorio && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/OpenColorIO/lib/OpenColorIO.dll ${HARVEST_TARGET}/opencolorio/bin/OpenColorIO.dll && + # Osl + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/osl/ ${HARVEST_TARGET}/osl && + # OpenVDB + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openVDB/ ${HARVEST_TARGET}/openVDB && + # blosc + ${CMAKE_COMMAND} -E copy ${LIBDIR}/blosc/lib/libblosc.lib ${HARVEST_TARGET}/blosc/lib/libblosc.lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/blosc/include/ ${HARVEST_TARGET}/blosc/include/ && + # tbb + ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_static.lib ${HARVEST_TARGET}/tbb/lib/tbb.lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/tbb/include/ ${HARVEST_TARGET}/tbb/include/ && + # opencollada + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/opencollada/ ${HARVEST_TARGET}/opencollada/ && + # opensubdiv + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/opensubdiv ${HARVEST_TARGET}/opensubdiv && + # python + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/python/ ${HARVEST_TARGET}/python/ && + # alembic + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/alembic ${HARVEST_TARGET}/alembic && + # hdf5 + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/hdf5 ${HARVEST_TARGET}/hdf5 && + # BlendThumb + ${CMAKE_COMMAND} -E copy ${LIBDIR}/BlendThumb64/bin/blendthumb.dll ${HARVEST_TARGET}/ThumbHandler/lib/BlendThumb64.dll && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/BlendThumb32/bin/blendthumb.dll ${HARVEST_TARGET}/ThumbHandler/lib/BlendThumb.dll && + # python + ${CMAKE_COMMAND} -E copy ${LIBDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}.tar.gz ${HARVEST_TARGET}/Release/python${PYTHON_SHORT_VERSION_NO_DOTS}.tar.gz && + # numpy + ${CMAKE_COMMAND} -E copy ${LIBDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}_numpy_${NUMPY_SHORT_VERSION}.tar.gz ${HARVEST_TARGET}/Release/python${PYTHON_SHORT_VERSION_NO_DOTS}_numpy_${NUMPY_SHORT_VERSION}.tar.gz && + # hidapi + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/hidapi/ ${HARVEST_TARGET}/hidapi/ && + # webp, straight up copy + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/webp ${HARVEST_TARGET}/webp + DEPENDS +) +endif(BUILD_MODE STREQUAL Release) + +if(BUILD_MODE STREQUAL Debug) + add_custom_target(Harvest_Debug_Results + # OpenImageIO + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openimageio/lib/OpenImageIO.lib ${HARVEST_TARGET}/openimageio/lib/OpenImageIO_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/openimageio/lib/OpenImageIO_Util.lib ${HARVEST_TARGET}/openimageio/lib/OpenImageIO_Util_d.lib && + # ilmbase+openexr + ${CMAKE_COMMAND} -E copy ${LIBDIR}/ilmbase/lib/Half.lib ${HARVEST_TARGET}/openexr/lib/Half_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/ilmbase/lib/Iex-2_2.lib ${HARVEST_TARGET}/openexr/lib/Iex-2_2_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/ilmbase/lib/IexMath-2_2.lib ${HARVEST_TARGET}/openexr/lib/IexMath-2_2_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/ilmbase/lib/IlmThread-2_2.lib ${HARVEST_TARGET}/openexr/lib/IlmThread-2_2_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/ilmbase/lib/Imath-2_2.lib ${HARVEST_TARGET}/openexr/lib/Imath-2_2_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/openexr/lib/IlmImf-2_2.lib ${HARVEST_TARGET}/openexr/lib/IlmImf-2_2_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/openexr/lib/IlmImfUtil-2_2.lib ${HARVEST_TARGET}/openexr/lib/IlmImfUtil-2_2_d.lib && + # opencollada + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/buffer.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/buffer_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/ftoa.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/ftoa_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/GeneratedSaxParser.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/GeneratedSaxParser_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/MathMLSolver.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/MathMLSolver_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADABaseUtils.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADABaseUtils_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADAFramework.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADAFramework_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADASaxFrameworkLoader.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADASaxFrameworkLoader_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADAStreamWriter.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADAStreamWriter_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/pcre.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/pcre_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/UTF.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/UTF_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/xml.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/xml_d.lib && + # blosc + ${CMAKE_COMMAND} -E copy ${LIBDIR}/blosc/lib/libblosc_d.lib ${HARVEST_TARGET}/blosc/lib/libblosc_d.lib && + # osl + ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslcomp.lib ${HARVEST_TARGET}/osl/lib/oslcomp_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslexec.lib ${HARVEST_TARGET}/osl/lib/oslexec_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslquery.lib ${HARVEST_TARGET}/osl/lib/oslquery_d.lib && + # opensubdiv + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opensubdiv/lib/osdCPU.lib ${HARVEST_TARGET}/opensubdiv/lib/osdCPU_d.lib && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/opensubdiv/lib/osdGPU.lib ${HARVEST_TARGET}/opensubdiv/lib/osdGPU_d.lib && + # tbb + ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_static.lib ${HARVEST_TARGET}/tbb/lib/tbb_debug.lib && + # openvdb + ${CMAKE_COMMAND} -E copy ${LIBDIR}/openvdb/lib/openvdb.lib ${HARVEST_TARGET}/openvdb/lib/openvdb_d.lib && + # python + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/python/ ${HARVEST_TARGET}/python/ && + # alembic + ${CMAKE_COMMAND} -E copy ${LIBDIR}/alembic/lib/alembic.lib ${HARVEST_TARGET}/alembic/lib/alembic_d.lib && + # hdf5 + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/hdf5/lib ${HARVEST_TARGET}/hdf5/lib && + # numpy + ${CMAKE_COMMAND} -E copy ${LIBDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}_numpy_${NUMPY_SHORT_VERSION}d.tar.gz ${HARVEST_TARGET}/Release/python${PYTHON_SHORT_VERSION_NO_DOTS}_numpy_${NUMPY_SHORT_VERSION}d.tar.gz && + # python + ${CMAKE_COMMAND} -E copy ${LIBDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}_d.tar.gz ${HARVEST_TARGET}/Release/python${PYTHON_SHORT_VERSION_NO_DOTS}_d.tar.gz + DEPENDS Package_Python +) +endif(BUILD_MODE STREQUAL Debug) + +else(WIN32) + +function(harvest from to) + set(pattern "") + foreach(f ${ARGN}) + set(pattern ${f}) + endforeach() + + if(pattern STREQUAL "") + get_filename_component(dirpath ${to} DIRECTORY) + get_filename_component(filename ${to} NAME) + install( + FILES ${LIBDIR}/${from} + DESTINATION ${HARVEST_TARGET}/${dirpath} + RENAME ${filename}) + else() + install( + DIRECTORY ${LIBDIR}/${from}/ + DESTINATION ${HARVEST_TARGET}/${to} + USE_SOURCE_PERMISSIONS + FILES_MATCHING PATTERN ${pattern} + PATTERN "pkgconfig" EXCLUDE + PATTERN "cmake" EXCLUDE + PATTERN "clang" EXCLUDE + PATTERN "__pycache__" EXCLUDE + PATTERN "tests" EXCLUDE) + endif() +endfunction() + +harvest(alembic/include alembic/include "*.h") +harvest(alembic/lib/libAlembic.a alembic/lib/libAlembic.a) +harvest(alembic/bin alembic/bin "*") +harvest(blosc/lib openvdb/lib "*.a") +harvest(boost/include boost/include "*") +harvest(boost/lib boost/lib "*.a") +harvest(ffmpeg/include ffmpeg/include "*.h") +harvest(ffmpeg/lib ffmpeg/lib "*.a") +harvest(fftw3/include fftw3/include "*.h") +harvest(fftw3/lib fftw3/lib "*.a") +harvest(flac/lib sndfile/lib "libFLAC.a") +harvest(freetype/include freetype/include "*.h") +harvest(freetype/lib/libfreetype2ST.a freetype/lib/libfreetype.a) +harvest(glew/include glew/include "*.h") +harvest(glew/lib glew/lib "*.a") +harvest(ilmbase openexr "*") +harvest(ilmbase/include openexr/include "*.h") +harvest(jemalloc/include jemalloc/include "*.h") +harvest(jemalloc/lib jemalloc/lib "*.a") +harvest(jpg/include jpeg/include "*.h") +harvest(jpg/lib jpeg/lib "libjpeg.a") +harvest(lame/lib ffmpeg/lib "*.a") +harvest(llvm/bin llvm/bin "llvm-config") +harvest(llvm/lib llvm/lib "libLLVM*.a") +harvest(ogg/lib ffmpeg/lib "*.a") +harvest(openal/include openal/include "*.h") +if(UNIX AND NOT APPLE) + harvest(openal/lib openal/lib "*.a") +endif() +harvest(opencollada/include/opencollada opencollada/include "*.h") +harvest(opencollada/lib/opencollada opencollada/lib "*.a") +harvest(opencolorio/include opencolorio/include "*.h") +harvest(opencolorio/lib opencolorio/lib "*.a") +harvest(openexr/include openexr/include "*.h") +harvest(openexr/lib openexr/lib "*.a") +harvest(openimageio/bin openimageio/bin "idiff") +harvest(openimageio/bin openimageio/bin "maketx") +harvest(openimageio/bin openimageio/bin "oiiotool") +harvest(openimageio/include openimageio/include "*") +harvest(openimageio/lib openimageio/lib "*.a") +harvest(openjpeg/include/openjpeg-1.5 openjpeg/include "*.h") +harvest(openjpeg/lib openjpeg/lib "*.a") +harvest(opensubdiv/include opensubdiv/include "*.h") +harvest(opensubdiv/lib opensubdiv/lib "*.a") +harvest(openvdb/include/openvdb/openvdb openvdb/include/openvdb "*.h") +harvest(openvdb/lib openvdb/lib "*.a") +harvest(orc/lib/liborc-0.4.a ffmpeg/lib/liborc.a) +harvest(osl/bin osl/bin "oslc") +harvest(osl/include osl/include "*.h") +harvest(osl/lib osl/lib "*.a") +harvest(osl/shaders osl/shaders "*.h") +harvest(png/include png/include "*.h") +harvest(png/lib png/lib "*.a") +harvest(python/bin python/bin "python${PYTHON_SHORT_VERSION}m") +harvest(python/include python/include "*h") +harvest(python/lib python/lib "*") +harvest(schroedinger/lib/libschroedinger-1.0.a ffmpeg/lib/libschroedinger.a) +harvest(sdl/include/SDL2 sdl/include "*.h") +harvest(sdl/lib sdl/lib "libSDL2.a") +harvest(sndfile/include sndfile/include "*.h") +harvest(sndfile/lib sndfile/lib "*.a") +harvest(spnav/include spnav/include "*.h") +harvest(spnav/lib spnav/lib "*.a") +harvest(tbb/include tbb/include "*.h") +harvest(tbb/lib/libtbb_static.a tbb/lib/libtbb.a) +harvest(theora/lib ffmpeg/lib "*.a") +harvest(tiff/include tiff/include "*.h") +harvest(tiff/lib tiff/lib "*.a") +harvest(vorbis/lib ffmpeg/lib "*.a") +harvest(vpx/lib ffmpeg/lib "*.a") +harvest(webp/lib ffmpeg/lib "*.a") +harvest(x264/lib ffmpeg/lib "*.a") +harvest(xml2/lib opencollada/lib "*.a") +harvest(xvidcore/lib ffmpeg/lib "*.a") + +endif(WIN32) diff --git a/build_files/build_environment/cmake/hdf5.cmake b/build_files/build_environment/cmake/hdf5.cmake new file mode 100644 index 00000000000..09d40d0605f --- /dev/null +++ b/build_files/build_environment/cmake/hdf5.cmake @@ -0,0 +1,42 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(HDF5_EXTRA_ARGS + -DHDF5_ENABLE_THREADSAFE=Off + -DHDF5_BUILD_CPP_LIB=Off + -DBUILD_TESTING=Off + -DHDF5_BUILD_TOOLS=Off + -DHDF5_BUILD_EXAMPLES=Off + -DHDF5_BUILD_HL_LIB=On + -DBUILD_STATIC_CRT_LIBS=On + -DBUILD_SHARED_LIBS=On +) + +if(WIN32) + set(HDF5_PATCH ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/hdf5/src/external_hdf5 < ${PATCH_DIR}/hdf5.diff) +endif() + +ExternalProject_Add(external_hdf5 + URL ${HDF5_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${HDF5_HASH} + PREFIX ${BUILD_DIR}/hdf5 + PATCH_COMMAND ${HDF5_PATCH} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/hdf5 ${HDF5_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/hdf5 +) diff --git a/build_files/build_environment/cmake/hidapi.cmake b/build_files/build_environment/cmake/hidapi.cmake new file mode 100644 index 00000000000..cfa4cc53d2d --- /dev/null +++ b/build_files/build_environment/cmake/hidapi.cmake @@ -0,0 +1,29 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(HIDAPI_EXTRA_ARGS) + +ExternalProject_Add(external_hidapi + URL ${HIDAPI_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${HIDAPI_HASH} + PREFIX ${BUILD_DIR}/hidapi + PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_hidapi.txt ${BUILD_DIR}/hidapi/src/external_hidapi/cmakelists.txt && ${PATCH_CMD} -p 0 -d ${BUILD_DIR}/hidapi/src/external_hidapi < ${PATCH_DIR}/hidapi.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/hidapi -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${HIDAPI_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/hidapi +) diff --git a/build_files/build_environment/cmake/iconv.cmake b/build_files/build_environment/cmake/iconv.cmake new file mode 100644 index 00000000000..cd6cf9547df --- /dev/null +++ b/build_files/build_environment/cmake/iconv.cmake @@ -0,0 +1,34 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(ICONV_EXTRA_ARGS) + +ExternalProject_Add(external_iconv + URL ${ICONV_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${ICONV_HASH} + PREFIX ${BUILD_DIR}/iconv + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/iconv/src/external_iconv/ && ${CONFIGURE_COMMAND} --enable-static --prefix=${mingw_LIBDIR}/iconv + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/iconv/src/external_iconv/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/iconv/src/external_iconv/ && make install + INSTALL_DIR ${LIBDIR}/iconv +) + +if(MSVC) + set_target_properties(external_iconv PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/ilmbase.cmake b/build_files/build_environment/cmake/ilmbase.cmake new file mode 100644 index 00000000000..0639848346f --- /dev/null +++ b/build_files/build_environment/cmake/ilmbase.cmake @@ -0,0 +1,35 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + set(ILMBASE_CMAKE_CXX_STANDARD_LIBRARIES "kernel32${LIBEXT} user32${LIBEXT} gdi32${LIBEXT} winspool${LIBEXT} shell32${LIBEXT} ole32${LIBEXT} oleaut32${LIBEXT} uuid${LIBEXT} comdlg32${LIBEXT} advapi32${LIBEXT} psapi${LIBEXT}") +endif() + +set(ILMBASE_EXTRA_ARGS + -DBUILD_SHARED_LIBS=OFF + -DCMAKE_CXX_STANDARD_LIBRARIES=${ILMBASE_CMAKE_CXX_STANDARD_LIBRARIES} +) + +ExternalProject_Add(external_ilmbase + URL ${ILMBASE_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${ILMBASE_HASH} + PREFIX ${BUILD_DIR}/ilmbase + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/ilmbase ${DEFAULT_CMAKE_FLAGS} ${ILMBASE_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/openexr +) diff --git a/build_files/build_environment/cmake/jemalloc.cmake b/build_files/build_environment/cmake/jemalloc.cmake new file mode 100644 index 00000000000..c39ba448917 --- /dev/null +++ b/build_files/build_environment/cmake/jemalloc.cmake @@ -0,0 +1,28 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +ExternalProject_Add(external_jemalloc + URL ${JEMALLOC_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${JEMALLOC_HASH} + PREFIX ${BUILD_DIR}/jemalloc + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/jemalloc/src/external_jemalloc/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/jemalloc --disable-shared --enable-static --with-pic + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/jemalloc/src/external_jemalloc/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/jemalloc/src/external_jemalloc/ && make install + INSTALL_DIR ${LIBDIR}/jemalloc +) diff --git a/build_files/build_environment/cmake/jpeg.cmake b/build_files/build_environment/cmake/jpeg.cmake new file mode 100644 index 00000000000..1f2b04387f0 --- /dev/null +++ b/build_files/build_environment/cmake/jpeg.cmake @@ -0,0 +1,65 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + # cmake for windows + set(JPEG_EXTRA_ARGS -DWITH_JPEG8=ON -DCMAKE_DEBUG_POSTFIX=d) + + ExternalProject_Add(external_jpeg + URL ${JPEG_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${JPEG_HASH} + PREFIX ${BUILD_DIR}/jpg + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/jpg ${DEFAULT_CMAKE_FLAGS} ${JPEG_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/jpg + ) + + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_jpeg after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/jpg/lib/jpegd${LIBEXT} ${LIBDIR}/jpg/lib/jpeg${LIBEXT} + DEPENDEES install + ) + endif() + + if(BUILD_MODE STREQUAL Release) + set(JPEG_LIBRARY jpeg-static${LIBEXT}) + else() + set(JPEG_LIBRARY jpeg-staticd${LIBEXT}) + endif() +else(WIN32) + # autoconf for unix + if(APPLE) + set(JPEG_EXTRA_ARGS --host x86_64-apple-darwin --with-jpeg8) + else() + set(JPEG_EXTRA_ARGS --with-jpeg8) + endif() + + ExternalProject_Add(external_jpeg + URL ${JPEG_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${JPEG_HASH} + CONFIGURE_COMMAND ${CONFIGURE_ENV} && autoreconf -fiv && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/jpg NASM=yasm ${JPEG_EXTRA_ARGS} + BUILD_IN_SOURCE 1 + BUILD_COMMAND ${CONFIGURE_ENV} && make install + PREFIX ${BUILD_DIR}/jpg + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/jpg ${DEFAULT_CMAKE_FLAGS} ${JPEG_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/jpg + ) + + set(JPEG_LIBRARY libjpeg${LIBEXT}) +endif(WIN32) diff --git a/build_files/build_environment/cmake/lame.cmake b/build_files/build_environment/cmake/lame.cmake new file mode 100644 index 00000000000..a489b2302ce --- /dev/null +++ b/build_files/build_environment/cmake/lame.cmake @@ -0,0 +1,47 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(LAME_EXTRA_ARGS) +if(MSVC) + if("${CMAKE_SIZEOF_VOID_P}" EQUAL "4") + set(LAME_EXTRA_ARGS CFLAGS=-msse) + endif() +endif() + +ExternalProject_Add(external_lame + URL ${LAME_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${LAME_HASH} + PREFIX ${BUILD_DIR}/lame + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lame/src/external_lame/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/lame --disable-shared --enable-static ${LAME_EXTRA_ARGS} + --enable-export=full + --with-fileio=sndfile + --without-vorbis + --with-pic + --disable-mp3x + --disable-mp3rtp + --disable-gtktest + --enable-export=full + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lame/src/external_lame/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lame/src/external_lame/ && make install + INSTALL_DIR ${LIBDIR}/lame +) + +if(MSVC) + set_target_properties(external_lame PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/lapack.cmake b/build_files/build_environment/cmake/lapack.cmake new file mode 100644 index 00000000000..3110503db52 --- /dev/null +++ b/build_files/build_environment/cmake/lapack.cmake @@ -0,0 +1,43 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(LAPACK_EXTRA_ARGS) + +if(WIN32) + if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(LAPACK_EXTRA_ARGS -G "MSYS Makefiles" -DCMAKE_Fortran_COMPILER=${DOWNLOAD_DIR}/mingw/mingw64/bin/gfortran.exe) + else() + set(LAPACK_EXTRA_ARGS -G "MSYS Makefiles" -DCMAKE_Fortran_COMPILER=${DOWNLOAD_DIR}/mingw/mingw32/bin/gfortran.exe) + endif() +endif() + +ExternalProject_Add(external_lapack + URL ${LAPACK_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${LAPACK_HASH} + PREFIX ${BUILD_DIR}/lapack + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lapack/src/external_lapack/ && ${CMAKE_COMMAND} ${LAPACK_EXTRA_ARGS} -DBUILD_TESTING=Off -DCMAKE_INSTALL_PREFIX=${LIBDIR}/lapack . + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lapack/src/external_lapack/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lapack/src/external_lapack/ && make install + + INSTALL_DIR ${LIBDIR}/lapack +) + +if(MSVC) + set_target_properties(external_lapack PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/llvm.cmake b/build_files/build_environment/cmake/llvm.cmake new file mode 100644 index 00000000000..f04fe609cb3 --- /dev/null +++ b/build_files/build_environment/cmake/llvm.cmake @@ -0,0 +1,61 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(LLVM_EXTRA_ARGS + -DLLVM_USE_CRT_RELEASE=MT + -DLLVM_USE_CRT_DEBUG=MTd + -DLLVM_INCLUDE_TESTS=OFF + -DLLVM_TARGETS_TO_BUILD=X86 + -DLLVM_INCLUDE_EXAMPLES=OFF + -DLLVM_ENABLE_TERMINFO=OFF +) + +if(WIN32) + set(LLVM_GENERATOR "NMake Makefiles") +else() + set(LLVM_GENERATOR "Unix Makefiles") +endif() + +# short project name due to long filename issues on windows +ExternalProject_Add(ll + URL ${LLVM_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${LLVM_HASH} + CMAKE_GENERATOR ${LLVM_GENERATOR} + PREFIX ${BUILD_DIR}/ll + PATCH_COMMAND ${PATCH_CMD} -p 0 -d ${BUILD_DIR}/ll/src/ll < ${PATCH_DIR}/llvm-alloca-fix.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/llvm ${DEFAULT_CMAKE_FLAGS} ${LLVM_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/llvm +) + +if (MSVC) + if (BUILD_MODE STREQUAL Release) + set(LLVM_HARVEST_COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/llvm/ ${HARVEST_TARGET}/llvm/ ) + else() + set(LLVM_HARVEST_COMMAND + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/llvm/lib/ ${HARVEST_TARGET}/llvm/debug/lib/ && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/llvm/bin/ ${HARVEST_TARGET}/llvm/debug/bin/ && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/llvm/include/ ${HARVEST_TARGET}/llvm/debug/include/ + ) + endif() + ExternalProject_Add_Step(ll after_install + COMMAND ${LLVM_HARVEST_COMMAND} + DEPENDEES mkdir update patch download configure build install + ) +endif() + diff --git a/build_files/build_environment/cmake/numpy.cmake b/build_files/build_environment/cmake/numpy.cmake new file mode 100644 index 00000000000..107947dabd3 --- /dev/null +++ b/build_files/build_environment/cmake/numpy.cmake @@ -0,0 +1,57 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(MSVC) + if(BUILD_MODE STREQUAL Debug) + set(NUMPY_DIR_POSTFIX -pydebug) + set(NUMPY_ARCHIVE_POSTFIX d) + set(NUMPY_BUILD_OPTION --debug) + else() + set(NUMPY_DIR_POSTFIX) + set(NUMPY_ARCHIVE_POSTFIX) + set(NUMPY_BUILD_OPTION) + endif(BUILD_MODE STREQUAL Debug) +endif() + +set(NUMPY_POSTFIX) + +if(WIN32) + set(NUMPY_INSTALL + ${CMAKE_COMMAND} -E copy_directory "${BUILD_DIR}/python/src/external_python/run/lib/site-packages/numpy/core/include/numpy" "${LIBDIR}/python/include/python${PYTHON_SHORT_VERSION}/numpy" && + ${CMAKE_COMMAND} -E chdir "${BUILD_DIR}/numpy/src/external_numpy/build/lib.${PYTHON_ARCH2}-${PYTHON_SHORT_VERSION}${NUMPY_DIR_POSTFIX}" + ${CMAKE_COMMAND} -E tar "cfvz" "${LIBDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}_numpy_${NUMPY_SHORT_VERSION}${NUMPY_ARCHIVE_POSTFIX}.tar.gz" "." + ) + set(NUMPY_PATCH ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/numpy/src/external_numpy < ${PATCH_DIR}/numpy.diff ) +else() + set(NUMPY_INSTALL echo .) + set(NUMPY_PATCH echo .) +endif() + +ExternalProject_Add(external_numpy + URL ${NUMPY_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${NUMPY_HASH} + PREFIX ${BUILD_DIR}/numpy + PATCH_COMMAND ${NUMPY_PATCH} + CONFIGURE_COMMAND "" + LOG_BUILD 1 + BUILD_COMMAND ${PYTHON_BINARY} ${BUILD_DIR}/numpy/src/external_numpy/setup.py build ${NUMPY_BUILD_OPTION} install --old-and-unmanageable + INSTALL_COMMAND ${NUMPY_INSTALL} +) + +add_dependencies(external_numpy Make_Python_Environment) diff --git a/build_files/build_environment/cmake/ogg.cmake b/build_files/build_environment/cmake/ogg.cmake new file mode 100644 index 00000000000..1f69cee0996 --- /dev/null +++ b/build_files/build_environment/cmake/ogg.cmake @@ -0,0 +1,32 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +ExternalProject_Add(external_ogg + URL ${OGG_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA256=${OGG_HASH} + PREFIX ${BUILD_DIR}/ogg + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ogg/src/external_ogg/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/ogg --disable-shared --enable-static + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ogg/src/external_ogg/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ogg/src/external_ogg/ && make install + INSTALL_DIR ${LIBDIR}/ogg +) + +if(MSVC) + set_target_properties(external_ogg PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/openal.cmake b/build_files/build_environment/cmake/openal.cmake new file mode 100644 index 00000000000..d63c4443ca0 --- /dev/null +++ b/build_files/build_environment/cmake/openal.cmake @@ -0,0 +1,42 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(BUILD_MODE STREQUAL Release) + set(OPENAL_EXTRA_ARGS + -DALSOFT_UTILS=Off + -DALSOFT_NO_CONFIG_UTIL=On + -DALSOFT_EXAMPLES=Off + -DALSOFT_TESTS=Off + -DALSOFT_CONFIG=Off + -DALSOFT_HRTF_DEFS=Off + -DALSOFT_INSTALL=On + ) + + if(UNIX) + set(OPENAL_EXTRA_ARGS ${OPENAL_EXTRA_ARGS} -DLIBTYPE=STATIC) + endif() + + ExternalProject_Add(external_openal + URL ${OPENAL_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${OPENAL_HASH} + PREFIX ${BUILD_DIR}/openal + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openal ${DEFAULT_CMAKE_FLAGS} ${OPENAL_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/openal + ) +endif() diff --git a/build_files/build_environment/cmake/opencollada.cmake b/build_files/build_environment/cmake/opencollada.cmake new file mode 100644 index 00000000000..9b2a2d9dc4d --- /dev/null +++ b/build_files/build_environment/cmake/opencollada.cmake @@ -0,0 +1,37 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(UNIX AND NOT APPLE) + set(OPENCOLLADA_EXTRA_ARGS + -DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2 + -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2.a) +endif() + +ExternalProject_Add(external_opencollada + URL ${OPENCOLLADA_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${OPENCOLLADA_HASH} + PREFIX ${BUILD_DIR}/opencollada + PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/opencollada/src/external_opencollada < ${PATCH_DIR}/opencollada.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/opencollada ${DEFAULT_CMAKE_FLAGS} ${OPENCOLLADA_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/opencollada +) + +if(UNIX AND NOT APPLE) + add_dependencies(external_opencollada external_xml2) +endif() diff --git a/build_files/build_environment/cmake/opencolorio.cmake b/build_files/build_environment/cmake/opencolorio.cmake new file mode 100644 index 00000000000..14fb62af672 --- /dev/null +++ b/build_files/build_environment/cmake/opencolorio.cmake @@ -0,0 +1,70 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(OPENCOLORIO_EXTRA_ARGS + -DBoost_COMPILER:STRING=${BOOST_COMPILER_STRING} + -DBoost_USE_MULTITHREADED=ON + -DBoost_USE_STATIC_LIBS=ON + -DBoost_USE_STATIC_RUNTIME=ON + -DBOOST_ROOT=${LIBDIR}/boost + -DBOOST_INCLUDEDIR=${LIBDIR}/boost/include/boost_1_60/boost + -DBoost_NO_SYSTEM_PATHS=ON + -DBoost_DEBUG=ON + -DBoost_MAJOR_VERSION=1 + -DBoost_MINOR_VERSION=60 + -DOCIO_BUILD_APPS=OFF + -DOCIO_BUILD_PYGLUE=OFF + -DOCIO_BUILD_NUKE=OFF +) + +if(WIN32) + set(OPENCOLORIO_EXTRA_ARGS + ${OPENCOLORIO_EXTRA_ARGS} + -DOCIO_USE_BOOST_PTR=ON + -DOCIO_BUILD_STATIC=OFF + -DOCIO_BUILD_SHARED=ON + ) +else() + set(OPENCOLORIO_EXTRA_ARGS + ${OPENCOLORIO_EXTRA_ARGS} + -DOCIO_USE_BOOST_PTR=OFF + -DOCIO_BUILD_STATIC=ON + -DOCIO_BUILD_SHARED=OFF + ) +endif() + +ExternalProject_Add(external_opencolorio + URL ${OPENCOLORIO_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${OPENCOLORIO_HASH} + PREFIX ${BUILD_DIR}/opencolorio + PATCH_COMMAND ${PATCH_CMD} -p 0 -N -d ${BUILD_DIR}/opencolorio/src/external_opencolorio < ${PATCH_DIR}/opencolorio.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/opencolorio ${DEFAULT_CMAKE_FLAGS} ${OPENCOLORIO_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/opencolorio +) + +if(NOT WIN32) + add_custom_command( + OUTPUT ${LIBDIR}/opencolorio/lib/libtinyxml.a + COMMAND cp ${BUILD_DIR}/opencolorio/src/external_opencolorio-build/ext/dist/lib/libtinyxml.a ${LIBDIR}/opencolorio/lib/libtinyxml.a + COMMAND cp ${BUILD_DIR}/opencolorio/src/external_opencolorio-build/ext/dist/lib/libyaml-cpp.a ${LIBDIR}/opencolorio/lib/libyaml-cpp.a + ) + add_custom_target(external_opencolorio_extra ALL DEPENDS external_opencolorio ${LIBDIR}/opencolorio/lib/libtinyxml.a) +endif() + +add_dependencies(external_opencolorio external_boost) diff --git a/build_files/build_environment/cmake/openexr.cmake b/build_files/build_environment/cmake/openexr.cmake new file mode 100644 index 00000000000..53a1bc4c146 --- /dev/null +++ b/build_files/build_environment/cmake/openexr.cmake @@ -0,0 +1,41 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + set(OPENEXR_CMAKE_CXX_STANDARD_LIBRARIES "kernel32${LIBEXT} user32${LIBEXT} gdi32${LIBEXT} winspool${LIBEXT} shell32${LIBEXT} ole32${LIBEXT} oleaut32${LIBEXT} uuid${LIBEXT} comdlg32${LIBEXT} advapi32${LIBEXT} psapi${LIBEXT}") +endif() + +set(OPENEXR_EXTRA_ARGS + -DBUILD_SHARED_LIBS=OFF + -DCMAKE_CXX_STANDARD_LIBRARIES=${OPENEXR_CMAKE_CXX_STANDARD_LIBRARIES} + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + -DILMBASE_PACKAGE_PREFIX=${LIBDIR}/ilmbase +) + +ExternalProject_Add(external_openexr + URL ${OPENEXR_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${OPENEXR_HASH} + PREFIX ${BUILD_DIR}/openexr + PATCH_COMMAND ${PATCH_CMD} -p 0 -d ${BUILD_DIR}/openexr/src/external_openexr < ${PATCH_DIR}/openexr.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openexr ${DEFAULT_CMAKE_FLAGS} ${OPENEXR_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/openexr +) + +add_dependencies(external_openexr external_zlib external_ilmbase) diff --git a/build_files/build_environment/cmake/openimageio.cmake b/build_files/build_environment/cmake/openimageio.cmake new file mode 100644 index 00000000000..96b221388da --- /dev/null +++ b/build_files/build_environment/cmake/openimageio.cmake @@ -0,0 +1,132 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(BUILD_MODE STREQUAL Release) + set(OIIO_TOOLS ON) +else() + set(OIIO_TOOLS OFF) +endif() + +if(UNIX AND NOT APPLE) + # This causes linking to static pthread libraries which gives link errors. + # Since we manually specify library paths it should static link other libs. + set(OPENIMAGEIO_LINKSTATIC -DLINKSTATIC=OFF) +else() + set(OPENIMAGEIO_LINKSTATIC -DLINKSTATIC=ON) +endif() + +if(WIN32) + set(PNG_LIBNAME libpng16_static${LIBEXT}) + set(OIIO_SIMD_FLAGS -DUSE_SIMD=sse2 -DOPJ_STATIC=1) + set(OPENJPEG_POSTFIX _msvc) +else() + set(PNG_LIBNAME libpng${LIBEXT}) + set(OIIO_SIMD_FLAGS) +endif() + +if (WITH_WEBP) + set(WEBP_ARGS -DWEBP_INCLUDE_DIR=${LIBDIR}/webp/include + -DWEBP_LIBRARY=${LIBDIR}/webp/lib/${LIBPREFIX}webp${LIBEXT} ) + set(WEBP_DEP external_webp) +endif() + +if (MSVC) +set(OPENJPEG_FLAGS -DOPENJPEG_HOME=${LIBDIR}/openjpeg_msvc + -DOPENJPEG_INCLUDE_DIR=${LIBDIR}/openjpeg_msvc/include/openjpeg-${OPENJPEG_SHORT_VERSION} + -DOPENJPEG_LIBRARY=${LIBDIR}/openjpeg_msvc/lib/openjpeg${LIBEXT} + -DOPENJPEG_LIBRARY_DEBUG=${LIBDIR}/openjpeg_msvc/lib/openjpeg${LIBEXT} + ) +else() +set(OPENJPEG_FLAGS -DOPENJPEG_INCLUDE_DIR=${LIBDIR}/openjpeg/include/openjpeg-${OPENJPEG_SHORT_VERSION} + -DOPENJPEG_LIBRARY=${LIBDIR}/openjpeg/lib/${OPENJPEG_LIBRARY} + ) +endif() + +set(OPENIMAGEIO_EXTRA_ARGS + -DBUILDSTATIC=ON + ${OPENIMAGEIO_LINKSTATIC} + -DOPENEXR_INCLUDE_DIR=${LIBDIR}/openexr/include/openexr/ + -DOPENEXR_ILMIMF_LIBRARIES=${LIBDIR}/openexr/lib/IlmImf-2_2${LIBEXT} + -DBoost_COMPILER:STRING=${BOOST_COMPILER_STRING} + -DBoost_USE_MULTITHREADED=ON + -DBoost_USE_STATIC_LIBS=ON + -DBoost_USE_STATIC_RUNTIME=ON + -DBOOST_ROOT=${LIBDIR}/boost + -DBOOST_LIBRARYDIR=${LIBDIR}/boost/lib/ + -DBoost_NO_SYSTEM_PATHS=ON + -OIIO_BUILD_CPP11=ON + -DUSE_OPENGL=OFF + -DUSE_TBB=OFF + -DUSE_FIELD3D=OFF + -DUSE_QT=OFF + -DUSE_PYTHON=OFF + -DUSE_GIF=OFF + -DUSE_OPENCV=OFF + -DUSE_OPENSSL=OFF + -DUSE_OPENJPEG=ON + -DUSE_FFMPEG=OFF + -DUSE_PTEX=OFF + -DUSE_FREETYPE=OFF + -DUSE_LIBRAW=OFF + -DUSE_PYTHON=OFF + -DUSE_PYTHON3=OFF + -DUSE_OCIO=OFF + -DOIIO_BUILD_TOOLS=${OIIO_TOOLS} + -DOIIO_BUILD_TESTS=OFF + -DBUILD_TESTING=OFF + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include + -DPNG_LIBRARY=${LIBDIR}/png/lib/${PNG_LIBNAME} + -DPNG_PNG_INCLUDE_DIR=${LIBDIR}/png/include + -DTIFF_LIBRARY=${LIBDIR}/tiff/lib/${LIBPREFIX}tiff${LIBEXT} + -DTIFF_INCLUDE_DIR=${LIBDIR}/tiff/include + -DJPEG_LIBRARY=${LIBDIR}/jpg/lib/${JPEG_LIBRARY} + -DJPEG_INCLUDE_DIR=${LIBDIR}/jpg/include + ${OPENJPEG_FLAGS} + -DOCIO_PATH=${LIBDIR}/opencolorio/ + -DOpenEXR_USE_STATIC_LIBS=On + -DOPENEXR_HOME=${LIBDIR}/openexr/ + -DILMBASE_INCLUDE_PATH=${LIBDIR}/ilmbase/ + -DILMBASE_PACKAGE_PREFIX=${LIBDIR}/ilmbase/ + -DILMBASE_INCLUDE_DIR=${LIBDIR}/ilmbase/include/ + -DOPENEXR_HALF_LIBRARY=${LIBDIR}/ilmbase/lib/${LIBPREFIX}Half${LIBEXT} + -DOPENEXR_IMATH_LIBRARY=${LIBDIR}/ilmbase/lib/${LIBPREFIX}Imath-2_2${LIBEXT} + -DOPENEXR_ILMTHREAD_LIBRARY=${LIBDIR}/ilmbase/lib/${LIBPREFIX}IlmThread-2_2${LIBEXT} + -DOPENEXR_IEX_LIBRARY=${LIBDIR}/ilmbase/lib/${LIBPREFIX}Iex-2_2${LIBEXT} + -DOPENEXR_INCLUDE_DIR=${LIBDIR}/openexr/include/ + -DOPENEXR_ILMIMF_LIBRARY=${LIBDIR}/openexr/lib/${LIBPREFIX}IlmImf-2_2${LIBEXT} + -DSTOP_ON_WARNING=OFF + ${WEBP_FLAGS} + ${OIIO_SIMD_FLAGS} +) + +ExternalProject_Add(external_openimageio + URL ${OPENIMAGEIO_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${OPENIMAGEIO_HASH} + PREFIX ${BUILD_DIR}/openimageio + PATCH_COMMAND ${PATCH_CMD} -p 0 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/src/include < ${PATCH_DIR}/openimageio_gdi.diff && + ${PATCH_CMD} -p 0 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/openimageio_staticexr.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openimageio ${DEFAULT_CMAKE_FLAGS} ${OPENIMAGEIO_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/openimageio +) + +add_dependencies(external_openimageio external_png external_zlib external_ilmbase external_openexr external_jpeg external_boost external_tiff external_opencolorio external_openjpeg${OPENJPEG_POSTFIX} ${WEBP_DEP}) +if(NOT WIN32) + add_dependencies(external_openimageio external_opencolorio_extra) +endif() diff --git a/build_files/build_environment/cmake/openjpeg.cmake b/build_files/build_environment/cmake/openjpeg.cmake new file mode 100644 index 00000000000..406badf31fe --- /dev/null +++ b/build_files/build_environment/cmake/openjpeg.cmake @@ -0,0 +1,57 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +# Note the encoder/decoder may use png/tiff/lcms system libraries, but the +# library itself does not depend on them, so should give no problems. + +set(OPENJPEG_EXTRA_ARGS -DBUILD_SHARED_LIBS=OFF) + +if(WIN32) + set(OPENJPEG_EXTRA_ARGS -G "MSYS Makefiles") +else() + set(OPENJPEG_EXTRA_ARGS ${DEFAULT_CMAKE_FLAGS}) +endif() + +ExternalProject_Add(external_openjpeg + URL ${OPENJPEG_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA256=${OPENJPEG_HASH} + PREFIX ${BUILD_DIR}/openjpeg + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/openjpeg/src/external_openjpeg-build && ${CMAKE_COMMAND} ${OPENJPEG_EXTRA_ARGS} -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openjpeg -DBUILD_SHARED_LIBS=Off -DBUILD_THIRDPARTY=OFF ${BUILD_DIR}/openjpeg/src/external_openjpeg + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/openjpeg/src/external_openjpeg-build/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/openjpeg/src/external_openjpeg-build/ && make install + INSTALL_DIR ${LIBDIR}/openjpeg +) + +#on windows ffmpeg wants a mingw build, while oiio needs a msvc build +if (MSVC) + set(OPENJPEG_EXTRA_ARGS ${DEFAULT_CMAKE_FLAGS}) +ExternalProject_Add(external_openjpeg_msvc + URL ${OPENJPEG_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA256=${OPENJPEG_HASH} + PREFIX ${BUILD_DIR}/openjpeg_msvc + CMAKE_ARGS ${OPENJPEG_EXTRA_ARGS} -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openjpeg_msvc -DBUILD_SHARED_LIBS=Off -DBUILD_THIRDPARTY=OFF + INSTALL_DIR ${LIBDIR}/openjpeg_msvc +) +endif() + + set(OPENJPEG_LIBRARY libopenjpeg${LIBEXT}) +if(MSVC) + set_target_properties(external_openjpeg PROPERTIES FOLDER Mingw) +endif(MSVC) diff --git a/build_files/build_environment/cmake/opensubdiv.cmake b/build_files/build_environment/cmake/opensubdiv.cmake new file mode 100644 index 00000000000..5a3a4d142fa --- /dev/null +++ b/build_files/build_environment/cmake/opensubdiv.cmake @@ -0,0 +1,71 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(OPENSUBDIV_EXTRA_ARGS + -DNO_EXAMPLES=ON + -DNO_REGRESSION=ON + -DNO_PYTHON=ON + -DNO_MAYA=ON + -DNO_PTEX=ON + -DNO_DOC=ON + -DNO_CLEW=OFF + -DNO_OPENCL=OFF + -DNO_TUTORIALS=ON + -DGLEW_INCLUDE_DIR=${LIBDIR}/glew/include + -DGLEW_LIBRARY=${LIBDIR}/glew/lib/libGLEW${LIBEXT} + -DGLFW_INCLUDE_DIR=${LIBDIR}/glfw/include + -DGLFW_LIBRARIES=${LIBDIR}/glfw/lib/glfw3${LIBEXT} +) + +if(WIN32) + #no cuda support for vc15 yet + if(msvc15) + set(OPENSUBDIV_CUDA ON) + else() + set(OPENSUBDIV_CUDA ON) + endif() + + set(OPENSUBDIV_EXTRA_ARGS + ${OPENSUBDIV_EXTRA_ARGS} + -DNO_CUDA=${OPENSUBDIV_CUDA} + -DCLEW_INCLUDE_DIR=${LIBDIR}/clew/include/cl + -DCLEW_LIBRARY=${LIBDIR}/clew/lib/clew${LIBEXT} + -DCUEW_INCLUDE_DIR=${LIBDIR}/cuew/include + -DCUEW_LIBRARY=${LIBDIR}/cuew/lib/cuew${LIBEXT} + -DCMAKE_EXE_LINKER_FLAGS_RELEASE=libcmt.lib + ) +else() + set(OPENSUBDIV_EXTRA_ARGS + ${OPENSUBDIV_EXTRA_ARGS} + -DNO_CUDA=ON + -DCUEW_INCLUDE_DIR=${LIBDIR}/cuew/include + -DCLEW_LIBRARY=${LIBDIR}/clew/lib/static/${LIBPREFIX}clew${LIBEXT} + ) +endif() + +ExternalProject_Add(external_opensubdiv + URL ${OPENSUBDIV_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${OPENSUBDIV_Hash} + PREFIX ${BUILD_DIR}/opensubdiv + PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/opensubdiv/src/external_opensubdiv < ${PATCH_DIR}/opensubdiv.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/opensubdiv -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${OPENSUBDIV_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/opensubdiv +) + +add_dependencies(external_opensubdiv external_glew external_glfw external_clew external_cuew) diff --git a/build_files/build_environment/cmake/openvdb.cmake b/build_files/build_environment/cmake/openvdb.cmake new file mode 100644 index 00000000000..a71598c1a3b --- /dev/null +++ b/build_files/build_environment/cmake/openvdb.cmake @@ -0,0 +1,71 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(BUILD_MODE STREQUAL Debug) + set(BLOSC_POST _d) +endif() + +set(OPENVDB_EXTRA_ARGS + -DILMBASE_HOME=${LIBDIR}/ilmbase/ + -DILMBASE_CUSTOM=ON + -DILMBASE_CUSTOM_LIBRARIES=Half;Imath-2_2;IlmThread-2_2;Iex-2_2 + -DILMBASE_INCLUDE_DIR=${LIBDIR}/ilmbase/include/ + -DILMBASE_HALF_LIBRARIES=${LIBDIR}/ilmbase/lib/Half${LIBEXT} + -DILMBASE_IMATH_LIBRARIES=${LIBDIR}/ilmbase/lib/${LIBPREFIX}Imath-2_2${LIBEXT} + -DILMBASE_ILMTHREAD_LIBRARIES=${LIBDIR}/ilmbase/lib/${LIBPREFIX}IlmThread-2_2${LIBEXT} + -DILMBASE_IEX_LIBRARIES=${LIBDIR}/ilmbase/lib/${LIBPREFIX}Iex-2_2${LIBEXT} + -DOPENEXR_HOME=${LIBDIR}/openexr/ + -DOPENEXR_USE_STATIC_LIBS=ON + -DOPENEXR_CUSTOM=ON + -DOPENEXR_CUSTOM_LIBRARY=IlmImf-2_2 + -DOPENEXR_INCLUDE_DIR=${LIBDIR}/openexr/include/ + -DOPENEXR_ILMIMF_LIBRARIES=${LIBDIR}/openexr/lib/${LIBPREFIX}IlmImf-2_2${LIBEXT} + -DTBB_ROOT_DIR=${LIBDIR}/tbb/ + -DTBB_INCLUDE_DIRS=${LIBDIR}/tbb/include + -DTBB_LIBRARY=${LIBDIR}/tbb/lib/tbb_static${LIBEXT} + -DBoost_COMPILER:STRING=${BOOST_COMPILER_STRING} + -DBoost_USE_MULTITHREADED=ON + -DBoost_USE_STATIC_LIBS=ON + -DBoost_USE_STATIC_RUNTIME=ON + -DBOOST_ROOT=${LIBDIR}/boost + -DBoost_NO_SYSTEM_PATHS=ON + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + -DWITH_BLOSC=ON + -DBLOSC_INCLUDE_DIR=${LIBDIR}/blosc/include/ + -DBLOSC_LIBRARY=${LIBDIR}/blosc/lib/libblosc${BLOSC_POST}${LIBEXT} +) + +set(OPENVDB_EXTRA_ARGS ${OPENVDB_EXTRA_ARGS}) + +# CMake script for OpenVDB based on https://raw.githubusercontent.com/diekev/openvdb-cmake/master/CMakeLists.txt +# can't be in external_openvdb because of how the includes are setup. + +ExternalProject_Add(openvdb + URL ${OPENVDB_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${OPENVDB_HASH} + PREFIX ${BUILD_DIR}/openvdb + PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_openvdb.txt ${BUILD_DIR}/openvdb/src/openvdb/CMakeLists.txt && + ${CMAKE_COMMAND} -E copy_directory ${PATCH_DIR}/cmake/ ${BUILD_DIR}/openvdb/src/openvdb/cmake/ && + ${PATCH_CMD} --verbose -p 0 -N -d ${BUILD_DIR}/openvdb/src/openvdb < ${PATCH_DIR}/openvdb_vc2013.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openvdb ${DEFAULT_CMAKE_FLAGS} ${OPENVDB_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/openvdb +) + +add_dependencies(openvdb external_tbb external_boost external_ilmbase external_openexr external_zlib external_blosc) diff --git a/build_files/build_environment/cmake/options.cmake b/build_files/build_environment/cmake/options.cmake new file mode 100644 index 00000000000..9979a682614 --- /dev/null +++ b/build_files/build_environment/cmake/options.cmake @@ -0,0 +1,210 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + option(ENABLE_MINGW64 "Enable building of ffmpeg/iconv/libsndfile/lapack/fftw3 by installing mingw64" ON) +endif() +option(WITH_WEBP "Enable building of oiio with webp support" OFF) +set(MAKE_THREADS 1 CACHE STRING "Number of threads to run make with") + +if(NOT BUILD_MODE) + set(BUILD_MODE "Release") + message(STATUS "Build type not specified: defaulting to a release build.") +endif() +Message("BuildMode = ${BUILD_MODE}") + +if(BUILD_MODE STREQUAL "Debug") + set(LIBDIR ${CMAKE_CURRENT_BINARY_DIR}/Debug) +ELSE(BUILD_MODE STREQUAL "Debug") + set(LIBDIR ${CMAKE_CURRENT_BINARY_DIR}/Release) +ENDIF(BUILD_MODE STREQUAL "Debug") + +option(DOWNLOAD_DIR "Path for downloaded files" ${CMAKE_CURRENT_SOURCE_DIR}/downloads) +file(TO_CMAKE_PATH ${DOWNLOAD_DIR} DOWNLOAD_DIR) +set(PATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR}/patches) +set(BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/build) + +message("LIBDIR = ${LIBDIR}") +message("DOWNLOAD_DIR = ${DOWNLOAD_DIR}") +message("PATCH_DIR = ${PATCH_DIR}") +message("BUILD_DIR = ${BUILD_DIR}") + +if(WIN32) + if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(PATCH_CMD ${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/patch.exe) + else() + set(PATCH_CMD ${DOWNLOAD_DIR}/mingw/mingw32/msys/1.0/bin/patch.exe) + endif() + set(LIBEXT ".lib") + set(LIBPREFIX "") + + # For OIIO and OSL + set(COMMON_DEFINES /DPSAPI_VERSION=1 /DOIIO_STATIC_BUILD /DTINYFORMAT_ALLOW_WCHAR_STRINGS) + + # TODO FIXME highly MSVC specific + if(WITH_OPTIMIZED_DEBUG) + set(BLENDER_CMAKE_C_FLAGS_DEBUG "/MTd /O2 /Ob2 /DNDEBUG /DPSAPI_VERSION=1 /DOIIO_STATIC_BUILD /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + else() + set(BLENDER_CMAKE_C_FLAGS_DEBUG "/MTd /Zi /Ob0 /Od /RTC1 /D_DEBUG /DPSAPI_VERSION=1 /DOIIO_STATIC_BUILD /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + endif() + set(BLENDER_CMAKE_C_FLAGS_MINSIZEREL "/MT /O1 /Ob1 /D NDEBUG /DPSAPI_VERSION=1 /DOIIO_STATIC_BUILD /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + set(BLENDER_CMAKE_C_FLAGS_RELEASE "/MT /O2 /Ob2 /DNDEBUG /DPSAPI_VERSION=1 /DOIIO_STATIC_BUILD /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + set(BLENDER_CMAKE_C_FLAGS_RELWITHDEBINFO "/MT /Zi /O2 /Ob1 /D NDEBUG /DPSAPI_VERSION=1 /DOIIO_STATIC_BUILD /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + + if(WITH_OPTIMIZED_DEBUG) + set(BLENDER_CMAKE_CXX_FLAGS_DEBUG "/MTd /O2 /Ob2 /D NDEBUG /D PLATFORM_WINDOWS /DPSAPI_VERSION=1 /DOIIO_STATIC_BUILD /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + else() + set(BLENDER_CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /D PLATFORM_WINDOWS /MTd /Zi /Ob0 /Od /RTC1 /DPSAPI_VERSION=1 /DOIIO_STATIC_BUILD /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + endif() + set(BLENDER_CMAKE_CXX_FLAGS_MINSIZEREL "/MT /O1 /Ob1 /D NDEBUG /D PLATFORM_WINDOWS /DPSAPI_VERSION=1 /DOIIO_STATIC_BUILD /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + set(BLENDER_CMAKE_CXX_FLAGS_RELEASE "/MT /O2 /Ob2 /D NDEBUG /D PLATFORM_WINDOWS /DPSAPI_VERSION=1 /DOIIO_STATIC_BUILD /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + set(BLENDER_CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MT /Zi /O2 /Ob1 /D NDEBUG /D PLATFORM_WINDOWS /DPSAPI_VERSION=1 /DOIIO_STATIC_BUILD /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + + set(PLATFORM_FLAGS) + set(PLATFORM_CXX_FLAGS) + set(PLATFORM_CMAKE_FLAGS) + + if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(MINGW_PATH ${DOWNLOAD_DIR}/mingw/mingw64) + set(MINGW_SHELL ming64sh.cmd) + set(PERL_SHELL ${DOWNLOAD_DIR}/perl/portableshell.bat) + set(MINGW_HOST x86_64-w64-mingw32) + else() + set(MINGW_PATH ${DOWNLOAD_DIR}/mingw/mingw32) + set(MINGW_SHELL ming32sh.cmd) + set(PERL_SHELL ${DOWNLOAD_DIR}/perl32/portableshell.bat) + set(MINGW_HOST i686-w64-mingw32) + endif() + + set(CONFIGURE_ENV + cd ${MINGW_PATH} && + call ${MINGW_SHELL} && + call ${PERL_SHELL} && + set path && + set CFLAGS=-g && + set LDFLAGS=-Wl,--as-needed -static-libgcc + ) + + set(CONFIGURE_ENV_NO_PERL + cd ${MINGW_PATH} && + call ${MINGW_SHELL} && + set path && + set CFLAGS=-g && + set LDFLAGS=-Wl,--as-needed -static-libgcc + ) + + set(CONFIGURE_COMMAND sh ./configure) + set(CONFIGURE_COMMAND_NO_TARGET ${CONFIGURE_COMMAND}) +else() + set(PATCH_CMD patch) + set(LIBEXT ".a") + set(LIBPREFIX "lib") + + if(APPLE) +# Let's get the current Xcode dir, to support xcode-select + execute_process( + COMMAND xcode-select --print-path + OUTPUT_VARIABLE XCODE_DEV_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) + set(OSX_ARCHITECTURES x86_64) + set(OSX_DEPLOYMENT_TARGET 10.9) + set(OSX_SDK_VERSION 10.12) + set(OSX_SYSROOT ${XCODE_DEV_PATH}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX${OSX_SDK_VERSION}.sdk) + + set(PLATFORM_CFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET}") + set(PLATFORM_CXXFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET} -std=c++11 -stdlib=libc++") + set(PLATFORM_LDFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET}") + set(PLATFORM_BUILD_TARGET --build=x86_64-apple-darwin13.0.0) # OS X 10.9 + set(PLATFORM_CMAKE_FLAGS + -DCMAKE_OSX_ARCHITECTURES:STRING=${OSX_ARCHITECTURES} + -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${OSX_DEPLOYMENT_TARGET} + -DCMAKE_OSX_SYSROOT:PATH=${OSX_SYSROOT} + ) + else() + set(PLATFORM_CFLAGS "-fPIC") + set(PLATFORM_CXXFLAGS "-std=c++11 -fPIC") + set(PLATFORM_LDFLAGS) + set(PLATFORM_BUILD_TARGET) + set(PLATFORM_CMAKE_FLAGS) + endif() + + if(WITH_OPTIMIZED_DEBUG) + set(BLENDER_CMAKE_C_FLAGS_DEBUG "-O2 -DNDEBUG") + else() + set(BLENDER_CMAKE_C_FLAGS_DEBUG "-g") + endif() + set(BLENDER_CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG") + set(BLENDER_CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG") + set(BLENDER_CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG") + + if(WITH_OPTIMIZED_DEBUG) + set(BLENDER_CMAKE_CXX_FLAGS_DEBUG "-O2 -DNDEBUG ${PLATFORM_CXXFLAGS}") + else() + set(BLENDER_CMAKE_CXX_FLAGS_DEBUG "-g ${PLATFORM_CXXFLAGS}") + endif() + + set(BLENDER_CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG ${PLATFORM_CXXFLAGS}") + set(BLENDER_CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG ${PLATFORM_CXXFLAGS}") + set(BLENDER_CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG ${PLATFORM_CXXFLAGS}") + + set(CONFIGURE_ENV + export MACOSX_DEPLOYMENT_TARGET=${OSX_DEPLOYMENT_TARGET} && + export CFLAGS=${PLATFORM_CFLAGS} && + export CXXFLAGS=${PLATFORM_CXXFLAGS} && + export LDFLAGS=${PLATFORM_LDFLAGS} + ) + set(CONFIGURE_ENV_NO_PERL ${CONFIGURE_ENV}) + set(CONFIGURE_COMMAND ./configure ${PLATFORM_BUILD_TARGET}) + set(CONFIGURE_COMMAND_NO_TARGET ./configure) +endif() + +set(DEFAULT_CMAKE_FLAGS + -DCMAKE_BUILD_TYPE=${BUILD_MODE} + -DCMAKE_C_FLAGS_DEBUG=${BLENDER_CMAKE_C_FLAGS_DEBUG} + -DCMAKE_C_FLAGS_MINSIZEREL=${BLENDER_CMAKE_C_FLAGS_MINSIZEREL} + -DCMAKE_C_FLAGS_RELEASE=${BLENDER_CMAKE_C_FLAGS_RELEASE} + -DCMAKE_C_FLAGS_RELWITHDEBINFO=${BLENDER_CMAKE_C_FLAGS_RELWITHDEBINFO} + -DCMAKE_CXX_FLAGS_DEBUG=${BLENDER_CMAKE_CXX_FLAGS_DEBUG} + -DCMAKE_CXX_FLAGS_MINSIZEREL=${BLENDER_CMAKE_CXX_FLAGS_MINSIZEREL} + -DCMAKE_CXX_FLAGS_RELEASE=${BLENDER_CMAKE_CXX_FLAGS_RELEASE} + -DCMAKE_CXX_FLAGS_RELWITHDEBINFO=${CMAKE_CXX_FLAGS_RELWITHDEBINFO} + ${PLATFORM_CMAKE_FLAGS} +) + +if(WIN32) + #we need both flavors to build the thumbnail dlls + if(MSVC12) + set(GENERATOR_32 "Visual Studio 12 2013") + set(GENERATOR_64 "Visual Studio 12 2013 Win64") + elseif(MSVC14) + set(GENERATOR_32 "Visual Studio 14 2015") + set(GENERATOR_64 "Visual Studio 14 2015 Win64") + endif() +endif() + + +if(WIN32) + set(ZLIB_LIBRARY zlibstatic${LIBEXT}) +else() + set(ZLIB_LIBRARY libz${LIBEXT}) +endif() + +if(MSVC) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) +endif() + +set(CMAKE_INSTALL_MESSAGE LAZY) diff --git a/build_files/build_environment/cmake/orc.cmake b/build_files/build_environment/cmake/orc.cmake new file mode 100644 index 00000000000..aac7884f49e --- /dev/null +++ b/build_files/build_environment/cmake/orc.cmake @@ -0,0 +1,32 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +ExternalProject_Add(external_orc + URL ${ORC_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA256=${ORC_HASH} + PREFIX ${BUILD_DIR}/orc + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/orc/src/external_orc/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/orc --disable-shared --enable-static + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/orc/src/external_orc/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/orc/src/external_orc/ && make install + INSTALL_DIR ${LIBDIR}/orc +) + +if(MSVC) + set_target_properties(external_orc PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/osl.cmake b/build_files/build_environment/cmake/osl.cmake new file mode 100644 index 00000000000..5ddb981c604 --- /dev/null +++ b/build_files/build_environment/cmake/osl.cmake @@ -0,0 +1,87 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + set(OSL_CMAKE_CXX_STANDARD_LIBRARIES "kernel32${LIBEXT} user32${LIBEXT} gdi32${LIBEXT} winspool${LIBEXT} shell32${LIBEXT} ole32${LIBEXT} oleaut32${LIBEXT} uuid${LIBEXT} comdlg32${LIBEXT} advapi32${LIBEXT} psapi${LIBEXT}") + set(OSL_FLEX_BISON -DFLEX_EXECUTABLE=${LIBDIR}/flexbison/win_flex.exe -DFLEX_EXTRA_OPTIONS="--wincompat" -DBISON_EXECUTABLE=${LIBDIR}/flexbison/win_bison.exe) + set(OSL_OPENIMAGEIO_LIBRARY "${LIBDIR}/openimageio/lib/${LIBPREFIX}OpenImageIO${LIBEXT};${LIBDIR}/openimageio/lib/${LIBPREFIX}OpenImageIO_Util${LIBEXT};${LIBDIR}/png/lib/libpng16${LIBEXT};${LIBDIR}/jpg/lib/${LIBPREFIX}jpeg${LIBEXT};${LIBDIR}/tiff/lib/${LIBPREFIX}tiff${LIBEXT};${LIBDIR}/openexr/lib/${LIBPREFIX}IlmImf-2_2${LIBEXT}") + if("${CMAKE_SIZEOF_VOID_P}" EQUAL "4") + set(OSL_SIMD_FLAGS -DOIIO_NOSIMD=1 -DOIIO_SIMD=0) + else() + set(OSL_SIMD_FLAGS -DOIIO_NOSIMD=1 -DOIIO_SIMD=sse2) + endif() +else() + set(OSL_CMAKE_CXX_STANDARD_LIBRARIES) + set(OSL_FLEX_BISON) + set(OSL_OPENIMAGEIO_LIBRARY "${LIBDIR}/openimageio/lib/${LIBPREFIX}OpenImageIO${LIBEXT};${LIBDIR}/openimageio/lib/${LIBPREFIX}OpenImageIO_Util${LIBEXT};${LIBDIR}/png/lib/${LIBPREFIX}png16${LIBEXT};${LIBDIR}/jpg/lib/${LIBPREFIX}jpeg${LIBEXT};${LIBDIR}/tiff/lib/${LIBPREFIX}tiff${LIBEXT};${LIBDIR}/openexr/lib/${LIBPREFIX}IlmImf-2_2${LIBEXT}") +endif() + +set(OSL_ILMBASE_CUSTOM_LIBRARIES "${LIBDIR}/ilmbase/lib/Imath-2_2.lib^^${LIBDIR}/ilmbase/lib/Half.lib^^${LIBDIR}/ilmbase/lib/IlmThread-2_2.lib^^${LIBDIR}/ilmbase/lib/Iex-2_2.lib") +set(OSL_LLVM_LIBRARY "${LIBDIR}/llvm/lib/LLVMAnalysis${LIBEXT};${LIBDIR}/llvm/lib/LLVMAsmParser${LIBEXT};${LIBDIR}/llvm/lib/LLVMAsmPrinter${LIBEXT};${LIBDIR}/llvm/lib/LLVMBitReader${LIBEXT};${LIBDIR}/llvm/lib/LLVMBitWriter${LIBEXT};${LIBDIR}/llvm/lib/LLVMCodeGen${LIBEXT};${LIBDIR}/llvm/lib/LLVMCore${LIBEXT};${LIBDIR}/llvm/lib/LLVMDebugInfo${LIBEXT};${LIBDIR}/llvm/lib/LLVMExecutionEngine${LIBEXT};${LIBDIR}/llvm/lib/LLVMInstCombine${LIBEXT};${LIBDIR}/llvm/lib/LLVMInstrumentation${LIBEXT};${LIBDIR}/llvm/lib/LLVMInterpreter${LIBEXT};${LIBDIR}/llvm/lib/LLVMJIT${LIBEXT};${LIBDIR}/llvm/lib/LLVMLinker${LIBEXT};${LIBDIR}/llvm/lib/LLVMMC${LIBEXT};${LIBDIR}/llvm/lib/LLVMMCDisassembler${LIBEXT};${LIBDIR}/llvm/lib/LLVMMCJIT${LIBEXT};${LIBDIR}/llvm/lib/LLVMMCParser${LIBEXT};${LIBDIR}/llvm/lib/LLVMObject${LIBEXT};${LIBDIR}/llvm/lib/LLVMRuntimeDyld${LIBEXT};${LIBDIR}/llvm/lib/LLVMScalarOpts${LIBEXT};${LIBDIR}/llvm/lib/LLVMSelectionDAG${LIBEXT};${LIBDIR}/llvm/lib/LLVMSupport${LIBEXT};${LIBDIR}/llvm/lib/LLVMTableGen${LIBEXT};${LIBDIR}/llvm/lib/LLVMTarget${LIBEXT};${LIBDIR}/llvm/lib/LLVMTransformUtils${LIBEXT};${LIBDIR}/llvm/lib/LLVMVectorize${LIBEXT};${LIBDIR}/llvm/lib/LLVMX86AsmParser${LIBEXT};${LIBDIR}/llvm/lib/LLVMX86AsmPrinter${LIBEXT};${LIBDIR}/llvm/lib/LLVMX86CodeGen${LIBEXT};${LIBDIR}/llvm/lib/LLVMX86Desc${LIBEXT};${LIBDIR}/llvm/lib/LLVMX86Disassembler${LIBEXT};${LIBDIR}/llvm/lib/LLVMX86Info${LIBEXT};${LIBDIR}/llvm/lib/LLVMX86Utils${LIBEXT};${LIBDIR}/llvm/lib/LLVMipa${LIBEXT};${LIBDIR}/llvm/lib/LLVMipo${LIBEXT}") + +set(OSL_EXTRA_ARGS + -DBoost_COMPILER:STRING=${BOOST_COMPILER_STRING} + -DBoost_USE_MULTITHREADED=ON + -DBoost_USE_STATIC_LIBS=ON + -DBoost_USE_STATIC_RUNTIME=ON + -DBOOST_ROOT=${LIBDIR}/boost + -DBOOST_LIBRARYDIR=${LIBDIR}/boost/lib/ + -DBoost_NO_SYSTEM_PATHS=ON + -DLLVM_DIRECTORY=${LIBDIR}/llvm + -DLLVM_INCLUDES=${LIBDIR}/llvm/include + -DLLVM_LIB_DIR=${LIBDIR}/llvm/lib + -DLLVM_VERSION=3.4 + -DLLVM_LIBRARY=${OSL_LLVM_LIBRARY} + -DOPENEXR_HOME=${LIBDIR}/openexr/ + -DILMBASE_HOME=${LIBDIR}/ilmbase/ + -DILMBASE_INCLUDE_DIR=${LIBDIR}/ilmbase/include/ + -DOPENEXR_IMATH_LIBRARY=${LIBDIR}/ilmbase/lib/${LIBPREFIX}Imath-2_2${LIBEXT} + -DOPENEXR_ILMTHREAD_LIBRARY=${LIBDIR}/ilmbase/lib/${LIBPREFIX}IlmThread-2_2${LIBEXT} + -DOPENEXR_IEX_LIBRARY=${LIBDIR}/ilmbase/lib/${LIBPREFIX}Iex-2_2${LIBEXT} + -DOPENEXR_INCLUDE_DIR=${LIBDIR}/openexr/include/ + -DOPENEXR_ILMIMF_LIBRARY=${LIBDIR}/openexr/lib/${LIBPREFIX}IlmImf-2_2${LIBEXT} + -DOSL_BUILD_TESTS=OFF + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + -DOPENIMAGEIOHOME=${LIBDIR}/openimageio/ + -DOPENIMAGEIO_LIBRARY=${OSL_OPENIMAGEIO_LIBRARY} + -DOPENIMAGEIO_INCLUDES=${LIBDIR}/openimageio/include + ${OSL_FLEX_BISON} + -DCMAKE_CXX_STANDARD_LIBRARIES=${OSL_CMAKE_CXX_STANDARD_LIBRARIES} + -DBUILDSTATIC=ON + -DLINKSTATIC=ON + -DOSL_BUILD_PLUGINS=Off + -DSTOP_ON_WARNING=OFF + -DOSL_BUILD_CPP11=ON + -DUSE_LLVM_BITCODE=OFF + ${OSL_SIMD_FLAGS} +) + +ExternalProject_Add(external_osl + URL ${OSL_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + LIST_SEPARATOR ^^ + URL_HASH MD5=${OSL_HASH} + PREFIX ${BUILD_DIR}/osl + PATCH_COMMAND ${PATCH_CMD} -p 3 -d ${BUILD_DIR}/osl/src/external_osl < ${PATCH_DIR}/osl.diff && + ${PATCH_CMD} -p 0 -d ${BUILD_DIR}/osl/src/external_osl < ${PATCH_DIR}/osl_simd_oiio.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/osl -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} ${DEFAULT_CMAKE_FLAGS} ${OSL_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/osl +) + +add_dependencies(external_osl external_boost ll external_clang external_ilmbase external_openexr external_zlib external_flexbison external_openimageio) diff --git a/build_files/build_environment/cmake/png.cmake b/build_files/build_environment/cmake/png.cmake new file mode 100644 index 00000000000..8d6fee871f9 --- /dev/null +++ b/build_files/build_environment/cmake/png.cmake @@ -0,0 +1,41 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(PNG_EXTRA_ARGS + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + -DPNG_STATIC=ON +) + +ExternalProject_Add(external_png + URL ${PNG_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${PNG_HASH} + PREFIX ${BUILD_DIR}/png + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/png ${DEFAULT_CMAKE_FLAGS} ${PNG_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/png +) + +add_dependencies(external_png external_zlib) + +if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_png after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/png/lib/libpng16_staticd${LIBEXT} ${LIBDIR}/png/lib/libpng16${LIBEXT} + DEPENDEES install + ) +endif() diff --git a/build_files/build_environment/cmake/pthreads.cmake b/build_files/build_environment/cmake/pthreads.cmake new file mode 100644 index 00000000000..f4301b95f3a --- /dev/null +++ b/build_files/build_environment/cmake/pthreads.cmake @@ -0,0 +1,45 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + set(PTHREAD_XCFLAGS /MD) + + if(MSVC14) # vs2015 has timespec + set(PTHREAD_CPPFLAGS "/I. /DHAVE_PTW32_CONFIG_H /D_TIMESPEC_DEFINED ") + else() # everything before doesn't + set(PTHREAD_CPPFLAGS "/I. /DHAVE_PTW32_CONFIG_H ") + endif() + + set(PTHREADS_BUILD cd ${BUILD_DIR}/pthreads/src/external_pthreads/ && cd && nmake VC /e CPPFLAGS=${PTHREAD_CPPFLAGS} /e XCFLAGS=${PTHREAD_XCFLAGS} /e XLIBS=/NODEFAULTLIB:msvcr) + + ExternalProject_Add(external_pthreads + URL ${PTHREADS_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA512=${PTHREADS_SHA512} + PREFIX ${BUILD_DIR}/pthreads + CONFIGURE_COMMAND echo . + PATCH_COMMAND ${PATCH_CMD} --verbose -p 0 -N -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/pthreadVC2.dll ${LIBDIR}/pthreads/lib/pthreadVC2.dll && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/pthreadVC2${LIBEXT} ${LIBDIR}/pthreads/lib/pthreadVC2${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 + INSTALL_DIR ${LIBDIR}/pthreads + ) +endif() diff --git a/build_files/build_environment/cmake/python.cmake b/build_files/build_environment/cmake/python.cmake new file mode 100644 index 00000000000..98d9d4ae63e --- /dev/null +++ b/build_files/build_environment/cmake/python.cmake @@ -0,0 +1,138 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(PYTHON_POSTFIX) +if(BUILD_MODE STREQUAL Debug) + set(PYTHON_POSTFIX _d) +endif() + +if(WIN32) + set(PYTHON_BINARY ${BUILD_DIR}/python/src/external_python/run/python${PYTHON_POSTFIX}.exe) + + macro(cmake_to_dos_path MsysPath ResultingPath) + string(REPLACE "/" "\\" ${ResultingPath} "${MsysPath}") + endmacro() + + set(PYTHON_EXTERNALS_FOLDER ${BUILD_DIR}/python/src/external_python/externals) + set(DOWNLOADS_EXTERNALS_FOLDER ${DOWNLOAD_DIR}/externals) + + cmake_to_dos_path(${PYTHON_EXTERNALS_FOLDER} PYTHON_EXTERNALS_FOLDER_DOS) + cmake_to_dos_path(${DOWNLOADS_EXTERNALS_FOLDER} DOWNLOADS_EXTERNALS_FOLDER_DOS) + + message("Python externals = ${PYTHON_EXTERNALS_FOLDER}") + message("Python externals_dos = ${PYTHON_EXTERNALS_FOLDER_DOS}") + message("Python DOWNLOADS_EXTERNALS_FOLDER = ${DOWNLOADS_EXTERNALS_FOLDER}") + message("Python DOWNLOADS_EXTERNALS_FOLDER_DOS = ${DOWNLOADS_EXTERNALS_FOLDER_DOS}") + + ExternalProject_Add(external_python + URL ${PYTHON_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${PYTHON_HASH} + PREFIX ${BUILD_DIR}/python + PATCH_COMMAND echo mklink /D "${PYTHON_EXTERNALS_FOLDER_DOS}" "${DOWNLOADS_EXTERNALS_FOLDER_DOS}" && + mklink /D "${PYTHON_EXTERNALS_FOLDER_DOS}" "${DOWNLOADS_EXTERNALS_FOLDER_DOS}" && + ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/python/src/external_python < ${PATCH_DIR}/python.diff && + ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/python/src/external_python/pc < ${PATCH_DIR}/pyshell.diff + CONFIGURE_COMMAND "" + BUILD_COMMAND cd ${BUILD_DIR}/python/src/external_python/pcbuild/ && set IncludeTkinter=false && call build.bat -e -p ${PYTHON_ARCH} -c ${BUILD_MODE} -k ${PYTHON_COMPILER_STRING} + INSTALL_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${PYTHON_OUTPUTDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.dll ${LIBDIR}/python/lib/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.dll && + ${CMAKE_COMMAND} -E copy ${PYTHON_OUTPUTDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.lib ${LIBDIR}/python/lib/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.lib && + ${CMAKE_COMMAND} -E copy ${PYTHON_OUTPUTDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.exp ${LIBDIR}/python/lib/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.exp && + ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR}/python/src/external_python/include ${LIBDIR}/python/include/Python${PYTHON_SHORT_VERSION} && + ${CMAKE_COMMAND} -E copy "${BUILD_DIR}/python/src/external_python/PC/pyconfig.h" ${LIBDIR}/python/include/Python${PYTHON_SHORT_VERSION}/pyconfig.h + ) + Message("PythinRedist = ${BUILD_DIR}/python/src/external_python/redist") + Message("POutput = ${PYTHON_OUTPUTDIR}") +else() + if(APPLE) + # we need to manually add homebrew headers to get ssl module building + set(PYTHON_CFLAGS "-I/usr/local/opt/openssl/include -I${OSX_SYSROOT}/usr/include ${PLATFORM_CFLAGS}") + set(PYTHON_LDFLAGS "-L/usr/local/opt/openssl/lib ${PLATFORM_LDFLAGS}") + set(PYTHON_CONFIGURE_ENV ${CONFIGURE_ENV} && export CFLAGS=${PYTHON_CFLAGS} && export LDFLAGS=${PYTHON_LDFLAGS}) + set(PYTHON_BINARY ${BUILD_DIR}/python/src/external_python/python.exe) + set(PYTHON_PATCH ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/python/src/external_python < ${PATCH_DIR}/python_apple.diff) + else() + set(PYTHON_CONFIGURE_ENV ${CONFIGURE_ENV}) + set(PYTHON_BINARY ${BUILD_DIR}/python/src/external_python/python) + endif() + + ExternalProject_Add(external_python + URL ${PYTHON_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${PYTHON_HASH} + PREFIX ${BUILD_DIR}/python + PATCH_COMMAND ${PYTHON_PATCH} + CONFIGURE_COMMAND ${PYTHON_CONFIGURE_ENV} && cd ${BUILD_DIR}/python/src/external_python/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/python + BUILD_COMMAND ${PYTHON_CONFIGURE_ENV} && cd ${BUILD_DIR}/python/src/external_python/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${PYTHON_CONFIGURE_ENV} && cd ${BUILD_DIR}/python/src/external_python/ && make install + INSTALL_DIR ${LIBDIR}/python) + + add_custom_target(Make_Python_Environment ALL DEPENDS external_python) +endif() + +if(MSVC) + add_custom_command( + OUTPUT ${LIBDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.tar.gz + OUTPUT ${BUILD_DIR}/python/src/external_python/redist/bin/python${PYTHON_POSTFIX}.exe + COMMAND ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR}/python/src/external_python/lib ${BUILD_DIR}/python/src/external_python/redist/lib + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/python${PYTHON_POSTFIX}.exe" ${BUILD_DIR}/python/src/external_python/redist/bin/python${PYTHON_POSTFIX}.exe + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_bz2${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_bz2${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_hashlib${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_hashlib${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_lzma${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_lzma${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_sqlite3${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_sqlite3${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_ssl${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_ssl${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/pyexpat${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/pyexpat${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/select${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/select${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/unicodedata${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/unicodedata${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/winsound${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/winsound${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_ctypes${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_ctypes${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_ctypes_test${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_ctypes_test${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_decimal${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_decimal${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_elementtree${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_elementtree${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_msi${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_msi${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_multiprocessing${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_multiprocessing${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_overlapped${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_overlapped${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_socket${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_socket${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_testbuffer${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_testbuffer${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_testcapi${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_testcapi${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_testimportmultiple${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_testimportmultiple${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/_testmultiphase${PYTHON_POSTFIX}.pyd" ${BUILD_DIR}/python/src/external_python/redist/lib/_testmultiphase${PYTHON_POSTFIX}.pyd + COMMAND ${CMAKE_COMMAND} -E chdir "${BUILD_DIR}/python/src/external_python/redist" ${CMAKE_COMMAND} -E tar "cfvz" "${LIBDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.tar.gz" "." + ) + + add_custom_target(Package_Python ALL DEPENDS external_python ${LIBDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.tar.gz ${BUILD_DIR}/python/src/external_python/redist/bin/python${PYTHON_POSTFIX}.exe) + + if(MSVC12) + set(PYTHON_DISTUTIL_PATCH ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/python/src/external_python/run/lib/distutils < ${PATCH_DIR}/python_runtime_vc2013.diff) + else() + set(PYTHON_DISTUTIL_PATCH echo "No patch needed") + endif() + + add_custom_command(OUTPUT ${BUILD_DIR}/python/src/external_python/run/python${PYTHON_POSTFIX}.exe + COMMAND ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR}/python/src/external_python/redist ${BUILD_DIR}/python/src/external_python/run + COMMAND ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR}/python/src/external_python/include ${BUILD_DIR}/python/src/external_python/run/include + COMMAND ${CMAKE_COMMAND} -E copy "${BUILD_DIR}/python/src/external_python/PC/pyconfig.h" ${BUILD_DIR}/python/src/external_python/run/include/pyconfig.h + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.dll" ${BUILD_DIR}/python/src/external_python/run/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.dll + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.lib" ${BUILD_DIR}/python/src/external_python/run/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}.lib #missing postfix on purpose, distutils is not expecting it + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.lib" ${BUILD_DIR}/python/src/external_python/run/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.lib #other things like numpy still want it though. + COMMAND ${CMAKE_COMMAND} -E copy "${PYTHON_OUTPUTDIR}/python${PYTHON_POSTFIX}.exe" ${BUILD_DIR}/python/src/external_python/run/python${PYTHON_POSTFIX}.exe + COMMAND ${BUILD_DIR}/python/src/external_python/run/python${PYTHON_POSTFIX}.exe -m ensurepip --upgrade + COMMAND ${PYTHON_DISTUTIL_PATCH} + ) + add_custom_target(Make_Python_Environment ALL DEPENDS ${BUILD_DIR}/python/src/external_python/run/python${PYTHON_POSTFIX}.exe Package_Python) +endif(MSVC) diff --git a/build_files/build_environment/cmake/python_site_packages.cmake b/build_files/build_environment/cmake/python_site_packages.cmake new file mode 100644 index 00000000000..530bae4c958 --- /dev/null +++ b/build_files/build_environment/cmake/python_site_packages.cmake @@ -0,0 +1,38 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** +if(WIN32) + set(HARVEST_CMD cmd /C FOR /d /r ${BUILD_DIR}/python/src/external_python/run/lib/site-packages %d IN (__pycache__) DO @IF EXIST "%d" rd /s /q "%d" && + ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR}/python/src/external_python/run/lib/site-packages/idna ${HARVEST_TARGET}/Release/site-packages/idna && + ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR}/python/src/external_python/run/lib/site-packages/chardet ${HARVEST_TARGET}/Release/site-packages/chardet && + ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR}/python/src/external_python/run/lib/site-packages/urllib3 ${HARVEST_TARGET}/Release/site-packages/urllib3 && + ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR}/python/src/external_python/run/lib/site-packages/certifi ${HARVEST_TARGET}/Release/site-packages/certifi && + ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR}/python/src/external_python/run/lib/site-packages/requests ${HARVEST_TARGET}/Release/site-packages/requests + ) +else() + set(HARVEST_CMD echo .) +endif() + +ExternalProject_Add(external_python_site_packages + DOWNLOAD_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + PREFIX ${BUILD_DIR}/site_packages + INSTALL_COMMAND ${PYTHON_BINARY} -m pip install idna==${IDNA_VERSION} chardet==${CHARDET_VERSION} urllib3==${URLLIB3_VERSION} certifi==${CERTIFI_VERSION} requests==${REQUESTS_VERSION} --no-binary :all: && ${HARVEST_CMD} +) + +add_dependencies(external_python_site_packages Make_Python_Environment) diff --git a/build_files/build_environment/cmake/schroedinger.cmake b/build_files/build_environment/cmake/schroedinger.cmake new file mode 100644 index 00000000000..54a20db5b5e --- /dev/null +++ b/build_files/build_environment/cmake/schroedinger.cmake @@ -0,0 +1,45 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + set(SCHROEDINGER_EXTRA_FLAGS "CFLAGS=-g -I./ -I${LIBDIR}/orc/include/orc-0.4" "LDFLAGS=-Wl,--as-needed -static-libgcc -L${LIBDIR}/orc/lib" ORC_CFLAGS=-I${LIBDIR}/orc/include/orc-0.4 ORC_LDFLAGS=-L${LIBDIR}/orc/lib ORC_LIBS=${LIBDIR}/orc/lib/liborc-0.4.a ORCC=${LIBDIR}/orc/bin/orcc.exe) +else() + set(SCHROEDINGER_CFLAGS "${PLATFORM_CFLAGS} -I./ -I${LIBDIR}/orc/include/orc-0.4") + set(SCHROEDINGER_LDFLAGS "${PLATFORM_LDFLAGS} -L${LIBDIR}/orc/lib") + set(SCHROEDINGER_EXTRA_FLAGS CFLAGS=${SCHROEDINGER_CFLAGS} LDFLAGS=${SCHROEDINGER_LDFLAGS} ORC_CFLAGS=-I${LIBDIR}/orc/include/orc-0.4 ORC_LDFLAGS=-L${LIBDIR}/orc/lib ORCC=${LIBDIR}/orc/bin/orcc) # ORC_LIBS=${LIBDIR}/orc/lib/liborc-0.4.a +endif() + +ExternalProject_Add(external_schroedinger + URL ${SCHROEDINGER_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA256=${SCHROEDINGER_HASH} + PREFIX ${BUILD_DIR}/schroedinger + PATCH_COMMAND ${PATCH_CMD} --verbose -p 0 -N -d ${BUILD_DIR}/schroedinger/src/external_schroedinger < ${PATCH_DIR}/schroedinger.diff + CONFIGURE_COMMAND ${CONFIGURE_ENV} && + cd ${BUILD_DIR}/schroedinger/src/external_schroedinger/ && + ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/schroedinger --disable-shared --enable-static ${SCHROEDINGER_EXTRA_FLAGS} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/schroedinger/src/external_schroedinger/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/schroedinger/src/external_schroedinger/ && make install + INSTALL_DIR ${LIBDIR}/schroedinger +) + +add_dependencies(external_schroedinger external_orc) + +if(MSVC) + set_target_properties(external_schroedinger PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/sdl.cmake b/build_files/build_environment/cmake/sdl.cmake new file mode 100644 index 00000000000..0fbfa078eb1 --- /dev/null +++ b/build_files/build_environment/cmake/sdl.cmake @@ -0,0 +1,39 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + set(SDL_EXTRA_ARGS + -DSDL_STATIC=Off + ) +else() + set(SDL_EXTRA_ARGS + -DSDL_STATIC=ON + -DSDL_SHARED=OFF + -DSDL_VIDEO=OFF + ) +endif() + +ExternalProject_Add(external_sdl + URL ${SDL_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${SDL_HASH} + PREFIX ${BUILD_DIR}/sdl + PATCH_COMMAND ${PATCH_CMD} -p 0 -N -d ${BUILD_DIR}/sdl/src/external_sdl < ${PATCH_DIR}/sdl.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/sdl ${DEFAULT_CMAKE_FLAGS} ${SDL_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/sdl +) diff --git a/build_files/build_environment/cmake/setup_mingw32.cmake b/build_files/build_environment/cmake/setup_mingw32.cmake new file mode 100644 index 00000000000..f0d99356da0 --- /dev/null +++ b/build_files/build_environment/cmake/setup_mingw32.cmake @@ -0,0 +1,219 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +#################################################################################################################### +# Mingw32 Builds +#################################################################################################################### +# This installs mingw32+msys to compile ffmpeg/iconv/libsndfile/lapack/fftw3 +#################################################################################################################### + +message("LIBDIR = ${LIBDIR}") +macro(cmake_to_msys_path MsysPath ResultingPath) + string(REPLACE ":" "" TmpPath "${MsysPath}") + string(SUBSTRING ${TmpPath} 0 1 Drive) + string(SUBSTRING ${TmpPath} 1 255 PathPart) + string(TOLOWER ${Drive} LowerDrive) + string(CONCAT ${ResultingPath} "/" ${LowerDrive} ${PathPart}) +endmacro() +cmake_to_msys_path(${LIBDIR} mingw_LIBDIR) +message("mingw_LIBDIR = ${mingw_LIBDIR}") + +message("Checking for mingw32") +# download mingw32 +if(NOT EXISTS "${DOWNLOAD_DIR}/i686-w64-mingw32-gcc-4.8.0-win32_rubenvb.7z") + message("Downloading mingw32") + file(DOWNLOAD "https://nchc.dl.sourceforge.net/project/mingw-w64/Toolchains%20targetting%20Win32/Personal%20Builds/rubenvb/gcc-4.8-release/i686-w64-mingw32-gcc-4.8.0-win32_rubenvb.7z" "${DOWNLOAD_DIR}/i686-w64-mingw32-gcc-4.8.0-win32_rubenvb.7z") +endif() + +# make mingw root directory +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw") + execute_process( + COMMAND ${CMAKE_COMMAND} -E make_directory ${DOWNLOAD_DIR}/mingw + WORKING_DIRECTORY ${DOWNLOAD_DIR} + ) +endif() + +# extract mingw32 +if((NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/mingw32env.cmd") AND (EXISTS "${DOWNLOAD_DIR}/i686-w64-mingw32-gcc-4.8.0-win32_rubenvb.7z")) + message("Extracting mingw32") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf ${DOWNLOAD_DIR}/i686-w64-mingw32-gcc-4.8.0-win32_rubenvb.7z + WORKING_DIRECTORY ${DOWNLOAD_DIR}/mingw + ) +endif() + +message("Checking for pkg-config") +if(NOT EXISTS "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1_bin-win32.zip") + message("Downloading pkg-config") + file(DOWNLOAD "https://nchc.dl.sourceforge.net/project/pkgconfiglite/0.28-1/pkg-config-lite-0.28-1_bin-win32.zip" "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1_bin-win32.zip") +endif() + +# extract pkgconfig +if((NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/bin/pkg-config.exe") AND (EXISTS "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1_bin-win32.zip")) + message("Extracting pkg-config") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1_bin-win32.zip" + WORKING_DIRECTORY ${DOWNLOAD_DIR}/ + ) + + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1/bin/pkg-config.exe" "${DOWNLOAD_DIR}/mingw/mingw32/bin/pkg-config.exe" + ) + +endif() + +message("Checking for nasm") +if(NOT EXISTS "${DOWNLOAD_DIR}/nasm-2.12.01-win32.zip") + message("Downloading nasm") + file(DOWNLOAD "http://www.nasm.us/pub/nasm/releasebuilds/2.12.01/win32/nasm-2.12.01-win32.zip" "${DOWNLOAD_DIR}/nasm-2.12.01-win32.zip") +endif() + +# extract nasm +if((NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/bin/nasm.exe") AND (EXISTS "${DOWNLOAD_DIR}/nasm-2.12.01-win32.zip")) + message("Extracting nasm") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf "${DOWNLOAD_DIR}/nasm-2.12.01-win32.zip" + WORKING_DIRECTORY ${DOWNLOAD_DIR}/ + ) + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/nasm-2.12.01/nasm.exe" "${DOWNLOAD_DIR}/mingw/mingw32/bin/nasm.exe" + ) + +endif() + +message("Checking for mingwGet") +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip") + message("Downloading mingw-get") + file(DOWNLOAD "https://nchc.dl.sourceforge.net/project/mingw/Installer/mingw-get/mingw-get-0.6.2-beta-20131004-1/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip" "${DOWNLOAD_DIR}/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip") +endif() + +# extract mingw_get +if((NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/bin/mingw-get.exe") AND (EXISTS "${DOWNLOAD_DIR}/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip")) + message("Extracting mingw-get") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf "${DOWNLOAD_DIR}/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip" + WORKING_DIRECTORY ${DOWNLOAD_DIR}/mingw/mingw32/ + ) +endif() + +if((EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/bin/mingw-get.exe") AND (NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/msys/1.0/bin/make.exe")) + message("Installing MSYS") + execute_process( + COMMAND ${DOWNLOAD_DIR}/mingw/mingw32/bin/mingw-get install msys msys-patch + WORKING_DIRECTORY ${DOWNLOAD_DIR}/mingw/mingw32/bin/ + ) +endif() + +message("Checking for CoreUtils") +# download old core_utils for pr.exe (ffmpeg needs it to build) +if(NOT EXISTS "${DOWNLOAD_DIR}/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2") + message("Downloading CoreUtils 5.97") + file(DOWNLOAD "https://nchc.dl.sourceforge.net/project/mingw/MSYS/Base/msys-core/_obsolete/coreutils-5.97-MSYS-1.0.11-2/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2" "${DOWNLOAD_DIR}/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2") +endif() + +if((EXISTS "${DOWNLOAD_DIR}/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2") AND (NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/msys/1.0/bin/pr.exe")) + message("Installing pr from CoreUtils 5.97") + execute_process( + COMMAND ${CMAKE_COMMAND} -E make_directory ${DOWNLOAD_DIR}/tmp_coreutils + WORKING_DIRECTORY ${DOWNLOAD_DIR} + ) + + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf ${DOWNLOAD_DIR}/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2 + WORKING_DIRECTORY ${DOWNLOAD_DIR}/tmp_coreutils/ + ) + + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy ${DOWNLOAD_DIR}/tmp_coreutils/coreutils-5.97/bin/pr.exe "${DOWNLOAD_DIR}/mingw/mingw32/msys/1.0/bin/pr.exe" + WORKING_DIRECTORY ${DOWNLOAD_DIR}/tmp_coreutils/ + ) +endif() + +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/ming32sh.cmd") + message("Installing ming32sh.cmd") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/ming32sh.cmd ${DOWNLOAD_DIR}/mingw/mingw32/ming32sh.cmd + ) +endif() + +message("Checking for perl") +# download perl for libvpx +if(NOT EXISTS "${DOWNLOAD_DIR}/strawberry-perl-5.22.1.3-32bit-portable.zip") + message("Downloading perl") + file(DOWNLOAD "http://strawberryperl.com/download/5.22.1.3/strawberry-perl-5.22.1.3-32bit-portable.zip" "${DOWNLOAD_DIR}/strawberry-perl-5.22.1.3-32bit-portable.zip") +endif() + +# make perl root directory +if(NOT EXISTS "${DOWNLOAD_DIR}/perl32") + execute_process( + COMMAND ${CMAKE_COMMAND} -E make_directory ${DOWNLOAD_DIR}/perl32 + WORKING_DIRECTORY ${DOWNLOAD_DIR} + ) +endif() + +# extract perl +if((NOT EXISTS "${DOWNLOAD_DIR}/perl32/portable.perl") AND (EXISTS "${DOWNLOAD_DIR}/strawberry-perl-5.22.1.3-32bit-portable.zip")) + message("Extracting perl") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf ${DOWNLOAD_DIR}/strawberry-perl-5.22.1.3-32bit-portable.zip + WORKING_DIRECTORY ${DOWNLOAD_DIR}/perl32 + ) +endif() + +# get yasm for vpx +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/bin/yasm.exe") + message("Downloading yasm") + file(DOWNLOAD "http://www.tortall.net/projects/yasm/releases/yasm-1.3.0-win32.exe" "${DOWNLOAD_DIR}/mingw/mingw32/bin/yasm.exe") +endif() + +message("checking i686-w64-mingw32-strings") +# copy strings.exe to i686-w64-mingw32-strings for x264 +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/bin/i686-w64-mingw32-strings.exe") + message("fixing i686-w64-mingw32-strings.exe") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/mingw/mingw32/bin/strings.exe" "${DOWNLOAD_DIR}/mingw/mingw32/bin/i686-w64-mingw32-strings.exe" + ) +endif() + +message("checking i686-w64-mingw32-ar.exe") +# copy ar.exe to i686-w64-mingw32-ar.exe for x264 +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/bin/i686-w64-mingw32-ar.exe") + message("fixing i686-w64-mingw32-ar.exe") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/mingw/mingw32/bin/ar.exe" "${DOWNLOAD_DIR}/mingw/mingw32/bin/i686-w64-mingw32-ar.exe" + ) +endif() + +message("checking i686-w64-mingw32-strip.exe") +# copy strip.exe to i686-w64-mingw32-strip.exe for x264 +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/bin/i686-w64-mingw32-strip.exe") + message("fixing i686-w64-mingw32-strip.exe") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/mingw/mingw32/bin/strip.exe" "${DOWNLOAD_DIR}/mingw/mingw32/bin/i686-w64-mingw32-strip.exe" + ) +endif() + +message("checking i686-w64-mingw32-ranlib.exe") +# copy ranlib.exe to i686-w64-mingw32-ranlib.exe for x264 +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw32/bin/i686-w64-mingw32-ranlib.exe") + message("fixing i686-w64-mingw32-ranlib.exe") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/mingw/mingw32/bin/ranlib.exe" "${DOWNLOAD_DIR}/mingw/mingw32/bin/i686-w64-mingw32-ranlib.exe" + ) +endif() + diff --git a/build_files/build_environment/cmake/setup_mingw64.cmake b/build_files/build_environment/cmake/setup_mingw64.cmake new file mode 100644 index 00000000000..14f75d410b4 --- /dev/null +++ b/build_files/build_environment/cmake/setup_mingw64.cmake @@ -0,0 +1,219 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +#################################################################################################################### +# Mingw64 Builds +#################################################################################################################### +# This installs mingw64+msys to compile ffmpeg/iconv/libsndfile/lapack/fftw3 +#################################################################################################################### + +message("LIBDIR = ${LIBDIR}") +macro(cmake_to_msys_path MsysPath ResultingPath) + string(REPLACE ":" "" TmpPath "${MsysPath}") + string(SUBSTRING ${TmpPath} 0 1 Drive) + string(SUBSTRING ${TmpPath} 1 255 PathPart) + string(TOLOWER ${Drive} LowerDrive) + string(CONCAT ${ResultingPath} "/" ${LowerDrive} ${PathPart}) +endmacro() +cmake_to_msys_path(${LIBDIR} mingw_LIBDIR) +message("mingw_LIBDIR = ${mingw_LIBDIR}") + +message("Checking for mingw64") +# download ming64 +if(NOT EXISTS "${DOWNLOAD_DIR}/x86_64-w64-mingw32-gcc-4.8.0-win64_rubenvb.7z") + message("Downloading mingw64") + file(DOWNLOAD "https://nchc.dl.sourceforge.net/project/mingw-w64/Toolchains%20targetting%20Win64/Personal%20Builds/rubenvb/gcc-4.8-release/x86_64-w64-mingw32-gcc-4.8.0-win64_rubenvb.7z" "${DOWNLOAD_DIR}/x86_64-w64-mingw32-gcc-4.8.0-win64_rubenvb.7z") +endif() + +# make mingw root directory +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw") + execute_process( + COMMAND ${CMAKE_COMMAND} -E make_directory ${DOWNLOAD_DIR}/mingw + WORKING_DIRECTORY ${DOWNLOAD_DIR} + ) +endif() + +# extract mingw64 +if((NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/mingw64env.cmd") AND (EXISTS "${DOWNLOAD_DIR}/x86_64-w64-mingw32-gcc-4.8.0-win64_rubenvb.7z")) + message("Extracting mingw64") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf ${DOWNLOAD_DIR}/x86_64-w64-mingw32-gcc-4.8.0-win64_rubenvb.7z + WORKING_DIRECTORY ${DOWNLOAD_DIR}/mingw + ) +endif() + +message("Checking for pkg-config") +if(NOT EXISTS "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1_bin-win32.zip") + message("Downloading pkg-config") + file(DOWNLOAD "https://nchc.dl.sourceforge.net/project/pkgconfiglite/0.28-1/pkg-config-lite-0.28-1_bin-win32.zip" "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1_bin-win32.zip") +endif() + +# extract pkgconfig +if((NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/pkg-config.exe") AND (EXISTS "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1_bin-win32.zip")) + message("Extracting pkg-config") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1_bin-win32.zip" + WORKING_DIRECTORY ${DOWNLOAD_DIR}/ + ) + + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1/bin/pkg-config.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/pkg-config.exe" + ) + +endif() + +message("Checking for nasm") +if(NOT EXISTS "${DOWNLOAD_DIR}/nasm-2.12.01-win64.zip") + message("Downloading nasm") + file(DOWNLOAD "http://www.nasm.us/pub/nasm/releasebuilds/2.12.01/win64/nasm-2.12.01-win64.zip" "${DOWNLOAD_DIR}/nasm-2.12.01-win64.zip") +endif() + +# extract nasm +if((NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/nasm.exe") AND (EXISTS "${DOWNLOAD_DIR}/nasm-2.12.01-win64.zip")) + message("Extracting nasm") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf "${DOWNLOAD_DIR}/nasm-2.12.01-win64.zip" + WORKING_DIRECTORY ${DOWNLOAD_DIR}/ + ) + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/nasm-2.12.01/nasm.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/nasm.exe" + ) + +endif() + +message("Checking for mingwGet") +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip") + message("Downloading mingw-get") + file(DOWNLOAD "https://nchc.dl.sourceforge.net/project/mingw/Installer/mingw-get/mingw-get-0.6.2-beta-20131004-1/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip" "${DOWNLOAD_DIR}/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip") +endif() + +# extract mingw_get +if((NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/mingw-get.exe") AND (EXISTS "${DOWNLOAD_DIR}/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip")) + message("Extracting mingw-get") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf "${DOWNLOAD_DIR}/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip" + WORKING_DIRECTORY ${DOWNLOAD_DIR}/mingw/mingw64/ + ) +endif() + +if((EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/mingw-get.exe") AND (NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/make.exe")) + message("Installing MSYS") + execute_process( + COMMAND ${DOWNLOAD_DIR}/mingw/mingw64/bin/mingw-get install msys msys-patch + WORKING_DIRECTORY ${DOWNLOAD_DIR}/mingw/mingw64/bin/ + ) +endif() + +message("Checking for CoreUtils") +# download old core_utils for pr.exe (ffmpeg needs it to build) +if(NOT EXISTS "${DOWNLOAD_DIR}/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2") + message("Downloading CoreUtils 5.97") + file(DOWNLOAD "https://nchc.dl.sourceforge.net/project/mingw/MSYS/Base/msys-core/_obsolete/coreutils-5.97-MSYS-1.0.11-2/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2" "${DOWNLOAD_DIR}/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2") +endif() + +if((EXISTS "${DOWNLOAD_DIR}/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2") AND (NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/pr.exe")) + message("Installing pr from CoreUtils 5.97") + execute_process( + COMMAND ${CMAKE_COMMAND} -E make_directory ${DOWNLOAD_DIR}/tmp_coreutils + WORKING_DIRECTORY ${DOWNLOAD_DIR} + ) + + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf ${DOWNLOAD_DIR}/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2 + WORKING_DIRECTORY ${DOWNLOAD_DIR}/tmp_coreutils/ + ) + + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy ${DOWNLOAD_DIR}/tmp_coreutils/coreutils-5.97/bin/pr.exe "${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/pr.exe" + WORKING_DIRECTORY ${DOWNLOAD_DIR}/tmp_coreutils/ + ) +endif() + +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/ming64sh.cmd") + message("Installing ming64sh.cmd") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/ming64sh.cmd ${DOWNLOAD_DIR}/mingw/mingw64/ming64sh.cmd + ) +endif() + +message("Checking for perl") +# download perl for libvpx +if(NOT EXISTS "${DOWNLOAD_DIR}/strawberry-perl-5.22.1.3-64bit-portable.zip") + message("Downloading perl") + file(DOWNLOAD "http://strawberryperl.com/download/5.22.1.3/strawberry-perl-5.22.1.3-64bit-portable.zip" "${DOWNLOAD_DIR}/strawberry-perl-5.22.1.3-64bit-portable.zip") +endif() + +# make perl root directory +if(NOT EXISTS "${DOWNLOAD_DIR}/perl") + execute_process( + COMMAND ${CMAKE_COMMAND} -E make_directory ${DOWNLOAD_DIR}/perl + WORKING_DIRECTORY ${DOWNLOAD_DIR} + ) +endif() + +# extract perl +if((NOT EXISTS "${DOWNLOAD_DIR}/perl/portable.perl") AND (EXISTS "${DOWNLOAD_DIR}/strawberry-perl-5.22.1.3-64bit-portable.zip")) + message("Extracting perl") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf ${DOWNLOAD_DIR}/strawberry-perl-5.22.1.3-64bit-portable.zip + WORKING_DIRECTORY ${DOWNLOAD_DIR}/perl + ) +endif() + +# get yasm for vpx +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/yasm.exe") + message("Downloading yasm") + file(DOWNLOAD "http://www.tortall.net/projects/yasm/releases/yasm-1.3.0-win64.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/yasm.exe") +endif() + +message("checking x86_64-w64-mingw32-strings.exe") +# copy strings.exe to x86_64-w64-mingw32-strings.exe for x264 +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-strings.exe") + message("fixing x86_64-w64-mingw32-strings.exe") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/mingw/mingw64/bin/strings.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-strings.exe" + ) +endif() + +message("checking x86_64-w64-mingw32-ar.exe") +# copy ar.exe to x86_64-w64-mingw32-ar.exe for x264 +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-ar.exe") + message("fixing x86_64-w64-mingw32-ar.exe") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/mingw/mingw64/bin/ar.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-ar.exe" + ) +endif() + +message("checking x86_64-w64-mingw32-strip.exe") +# copy strip.exe to x86_64-w64-mingw32-strip.exe for x264 +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-strip.exe") + message("fixing x86_64-w64-mingw32-strip.exe") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/mingw/mingw64/bin/strip.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-strip.exe" + ) +endif() + +message("checking x86_64-w64-mingw32-ranlib.exe") +# copy ranlib.exe to x86_64-w64-mingw32-ranlib.exe for x264 +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-ranlib.exe") + message("fixing x86_64-w64-mingw32-ranlib.exe") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/mingw/mingw64/bin/ranlib.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-ranlib.exe" + ) +endif() + diff --git a/build_files/build_environment/cmake/sndfile.cmake b/build_files/build_environment/cmake/sndfile.cmake new file mode 100644 index 00000000000..ce10f07c133 --- /dev/null +++ b/build_files/build_environment/cmake/sndfile.cmake @@ -0,0 +1,55 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(SNDFILE_EXTRA_ARGS) +set(SNDFILE_ENV PKG_CONFIG_PATH=${mingw_LIBDIR}/ogg/lib/pkgconfig:${mingw_LIBDIR}/vorbis/lib/pkgconfig:${mingw_LIBDIR}/flac/lib/pkgconfig:${mingw_LIBDIR}) + +if(WIN32) + set(SNDFILE_ENV set ${SNDFILE_ENV} &&) + #shared for windows because static libs will drag in a libgcc dependency. + set(SNDFILE_OPTIONS --disable-static --enable-shared ) +else() + set(SNDFILE_OPTIONS --enable-static --disable-shared ) +endif() + +if(APPLE) + set(SNDFILE_PATCH_CMD ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/sndfile/src/external_sndfile < ${PATCH_DIR}/sndfile.diff) +else() + set(SNDFILE_PATCH_CMD) +endif() + +ExternalProject_Add(external_sndfile + URL ${SNDFILE_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${SNDFILE_HASH} + PREFIX ${BUILD_DIR}/sndfile + PATCH_COMMAND ${SNDFILE_PATCH_CMD} + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && ${SNDFILE_ENV} ${CONFIGURE_COMMAND} ${SNDFILE_OPTIONS} --prefix=${mingw_LIBDIR}/sndfile + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && make install + INSTALL_DIR ${LIBDIR}/sndfile +) + +if(MSVC) + set_target_properties(external_sndfile PROPERTIES FOLDER Mingw) +endif() + +add_dependencies(external_sndfile external_ogg external_vorbis) +if(UNIX) + add_dependencies(external_sndfile external_flac) +endif() diff --git a/build_files/build_environment/cmake/spnav.cmake b/build_files/build_environment/cmake/spnav.cmake new file mode 100644 index 00000000000..0dec9799715 --- /dev/null +++ b/build_files/build_environment/cmake/spnav.cmake @@ -0,0 +1,28 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +ExternalProject_Add(external_spnav + URL ${SPNAV_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${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 + 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 +) diff --git a/build_files/build_environment/cmake/tbb.cmake b/build_files/build_environment/cmake/tbb.cmake new file mode 100644 index 00000000000..c4055d55648 --- /dev/null +++ b/build_files/build_environment/cmake/tbb.cmake @@ -0,0 +1,36 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(TBB_EXTRA_ARGS + -DTBB_BUILD_SHARED=Off + -DTBB_BUILD_TBBMALLOC=Off + -DTBB_BUILD_TBBMALLOC_PROXY=Off + -DTBB_BUILD_STATIC=On +) + +# CMake script for TBB from https://github.com/wjakob/tbb/blob/master/CMakeLists.txt +ExternalProject_Add(external_tbb + URL ${TBB_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${TBB_HASH} + PREFIX ${BUILD_DIR}/tbb + PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_tbb.txt ${BUILD_DIR}/tbb/src/external_tbb/CMakeLists.txt && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/tbb/src/external_tbb/build/vs2010/version_string.ver ${BUILD_DIR}/tbb/src/external_tbb/src/tbb/version_string.ver + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/tbb ${DEFAULT_CMAKE_FLAGS} ${TBB_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/tbb +) diff --git a/build_files/build_environment/cmake/theora.cmake b/build_files/build_environment/cmake/theora.cmake new file mode 100644 index 00000000000..03aad42f2db --- /dev/null +++ b/build_files/build_environment/cmake/theora.cmake @@ -0,0 +1,40 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +ExternalProject_Add(external_theora + URL ${THEORA_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA256=${THEORA_HASH} + PREFIX ${BUILD_DIR}/theora + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/theora/src/external_theora/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/theora + --disable-shared + --enable-static + --with-pic + --with-ogg=${LIBDIR}/ogg + --with-vorbis=${LIBDIR}/vorbis + --disable-examples + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/theora/src/external_theora/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/theora/src/external_theora/ && make install + INSTALL_DIR ${LIBDIR}/theora +) + +add_dependencies(external_theora external_vorbis external_ogg) + +if(MSVC) + set_target_properties(external_theora PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/tiff.cmake b/build_files/build_environment/cmake/tiff.cmake new file mode 100644 index 00000000000..2c01341eb21 --- /dev/null +++ b/build_files/build_environment/cmake/tiff.cmake @@ -0,0 +1,44 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(TIFF_EXTRA_ARGS + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include + -DPNG_STATIC=ON + -DBUILD_SHARED_LIBS=OFF + -Dlzma=OFF + -Djbig=OFF +) + +ExternalProject_Add(external_tiff + URL ${TIFF_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${TIFF_HASH} + PREFIX ${BUILD_DIR}/tiff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/tiff ${DEFAULT_CMAKE_FLAGS} ${TIFF_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/tiff +) + +add_dependencies(external_tiff external_zlib) + +if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_tiff after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tiff/lib/tiffd${LIBEXT} ${LIBDIR}/tiff/lib/tiff${LIBEXT} + DEPENDEES install + ) +endif() diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake new file mode 100644 index 00000000000..e53beeddf4a --- /dev/null +++ b/build_files/build_environment/cmake/versions.cmake @@ -0,0 +1,250 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(ZLIB_VERSION 1.2.8) +set(ZLIB_URI https://netcologne.dl.sourceforge.net/project/libpng/zlib/${ZLIB_VERSION}/zlib-${ZLIB_VERSION}.tar.gz) +set(ZLIB_HASH 44d667c142d7cda120332623eab69f40) + +set(OPENAL_VERSION 1.17.2) +set(OPENAL_URI http://kcat.strangesoft.net/openal-releases/openal-soft-${OPENAL_VERSION}.tar.bz2) +set(OPENAL_HASH 1764e0d8fec499589b47ebc724e0913d) + +set(PNG_VERSION 1.6.21) +set(PNG_URI http://prdownloads.sourceforge.net/libpng/libpng-${PNG_VERSION}.tar.gz) +set(PNG_HASH aca36ec8e0a3b406a5912243bc243717) + +set(JPEG_VERSION 1.4.2) +set(JPEG_URI https://github.com/libjpeg-turbo/libjpeg-turbo/archive/${JPEG_VERSION}.tar.gz) +set(JPEG_HASH f9804884c1c41eb7f4febb9353a2cb27) + +set(BOOST_VERSION 1.60.0) +set(BOOST_VERSION_NODOTS 1_60_0) +set(BOOST_URI http://sourceforge.net/projects/boost/files/boost/${BOOST_VERSION}/boost_${BOOST_VERSION_NODOTS}.tar.bz2/download) +set(BOOST_MD5 65a840e1a0b13a558ff19eeb2c4f0cbe) + +set(BLOSC_VERSION 1.7.1) +set(BLOSC_URI https://github.com/Blosc/c-blosc/archive/v${BLOSC_VERSION}.zip) +set(BLOSC_HASH ff5cc729a5a25934ef714217218eed26) + +set(PTHREADS_VERSION 2-9-1) +set(PTHREADS_URI ftp://sourceware.org/pub/pthreads-win32/pthreads-w32-${PTHREADS_VERSION}-release.tar.gz) +set(PTHREADS_SHA512 9c06e85310766834370c3dceb83faafd397da18a32411ca7645c8eb6b9495fea54ca2872f4a3e8d83cb5fdc5dea7f3f0464be5bb9af3222a6534574a184bd551) + +set(ILMBASE_VERSION 2.2.0) +set(ILMBASE_URI http://download.savannah.nongnu.org/releases/openexr/ilmbase-${ILMBASE_VERSION}.tar.gz) +set(ILMBASE_HASH b540db502c5fa42078249f43d18a4652) + +set(OPENEXR_VERSION 2.2.0) +set(OPENEXR_URI http://download.savannah.nongnu.org/releases/openexr/openexr-2.2.0.tar.gz) +set(OPENEXR_HASH b64e931c82aa3790329c21418373db4e) + +set(FREETYPE_VERSION 263) +set(FREETYPE_URI http://download.savannah.gnu.org/releases/freetype/ft${FREETYPE_VERSION}.zip) +set(FREETYPE_HASH 0db2a43301572e5c2b4a0864f237aeeb) + +set(GLEW_VERSION 1.13.0) +set(GLEW_URI http://prdownloads.sourceforge.net/glew/glew/${GLEW_VERSION}/glew-${GLEW_VERSION}.tgz) +set(GLEW_HASH 7cbada3166d2aadfc4169c4283701066) + +set(FREEGLUT_VERSION 3.0.0) +set(FREEGLUT_URI http://pilotfiber.dl.sourceforge.net/project/freeglut/freeglut/${FREEGLUT_VERSION}/freeglut-${FREEGLUT_VERSION}.tar.gz) +set(FREEGLUT_HASH 90c3ca4dd9d51cf32276bc5344ec9754) + +set(HDF5_VERSION 1.8.17) +set(HDF5_URI https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.8/hdf5-${HDF5_VERSION}/src/hdf5-${HDF5_VERSION}.tar.gz) +set(HDF5_HASH 7d572f8f3b798a628b8245af0391a0ca) + +set(ALEMBIC_VERSION 1.7.1) +set(ALEMBIC_URI https://github.com/alembic/alembic/archive/${ALEMBIC_VERSION}.zip) +set(ALEMBIC_MD5 cf7705055501d5ea0cb8256866496f79) + +## hash is for 3.1.2 +set(GLFW_GIT_UID 30306e54705c3adae9fe082c816a3be71963485c) +set(GLFW_URI https://github.com/glfw/glfw/archive/${GLFW_GIT_UID}.zip) +set(GLFW_HASH 20cacb1613da7eeb092f3ac4f6b2b3d0) + +#latest uid in git as of 2016-04-01 +set(CLEW_GIT_UID 277db43f6cafe8b27c6f1055f69dc67da4aeb299) +set(CLEW_URI https://github.com/OpenCLWrangler/clew/archive/${CLEW_GIT_UID}.zip) +set(CLEW_HASH 2c699d10ed78362e71f56fae2a4c5f98) + +#latest uid in git as of 2016-04-01 +set(CUEW_GIT_UID 1744972026de9cf27c8a7dc39cf39cd83d5f922f) +set(CUEW_URI https://github.com/CudaWrangler/cuew/archive/${CUEW_GIT_UID}.zip) +set(CUEW_HASH 86760d62978ebfd96cd93f5aa1abaf4a) + +set(OPENSUBDIV_VERSION v3_1_1) +set(OPENSUBDIV_Hash 25a9a6a94136b0eb85ce69e9c8cb6ab3) +set(OPENSUBDIV_URI https://github.com/PixarAnimationStudios/OpenSubdiv/archive/${OPENSUBDIV_VERSION}.zip) + +set(SDL_VERSION 2.0.4) +set(SDL_URI https://www.libsdl.org/release/SDL2-${SDL_VERSION}.tar.gz) +set(SDL_HASH 44fc4a023349933e7f5d7a582f7b886e) + +set(OPENCOLLADA_VERSION v1.6.51) +set(OPENCOLLADA_URI https://github.com/KhronosGroup/OpenCOLLADA/archive/${OPENCOLLADA_VERSION}.tar.gz) +set(OPENCOLLADA_HASH 23db5087faed4bc4cc1dfe456c0d4701) + +set(OPENCOLORIO_URI https://github.com/imageworks/OpenColorIO/archive/6de971097c7f552300f669ed69ca0b6cf5a70843.zip) +set(OPENCOLORIO_HASH c9de0fd98f26ce6f2e08d617ca68b8e4) + +set(LLVM_VERSION 3.4.2) +set(LLVM_URI http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.gz) +set(LLVM_HASH a20669f75967440de949ac3b1bad439c) + +set(CLANG_URI http://llvm.org/releases/${LLVM_VERSION}/cfe-${LLVM_VERSION}.src.tar.gz) +set(CLANG_HASH 87945973b7c73038871c5f849a818588) + +set(OPENIMAGEIO_VERSION 1.7.15) +set(OPENIMAGEIO_URI https://github.com/OpenImageIO/oiio/archive/Release-${OPENIMAGEIO_VERSION}.zip) +set(OPENIMAGEIO_HASH_178 e156e3669af0e1373142ab5e8f13de66) +set(OPENIMAGEIO_HASH_179 4121cb0e0433bda6a7ef32c8628a149f) +set(OPENIMAGEIO_HASH_1713 42a662775b834161ba88c6abdb299360) +set(OPENIMAGEIO_HASH_1715 e2ece0f62c013d64c478f82265988b0b) +set(OPENIMAGEIO_HASH ${OPENIMAGEIO_HASH_1715}) + + +set(TIFF_VERSION 4.0.6) +set(TIFF_URI http://download.osgeo.org/libtiff/tiff-${TIFF_VERSION}.tar.gz) +set(TIFF_HASH d1d2e940dea0b5ad435f21f03d96dd72) + +set(FLEXBISON_VERSION 2.5.5) +set(FLEXBISON_URI http://prdownloads.sourceforge.net/winflexbison//win_flex_bison-2.5.5.zip) +set(FLEXBISON_HASH d87a3938194520d904013abef3df10ce) + +set(OSL_VERSION 1.7.5) +set(OSL_URI https://github.com/imageworks/OpenShadingLanguage/archive/Release-${OSL_VERSION}.zip) +set(OSL_HASH 6924dd5d453159e7b6eb106a08c358cf) + +set(PYTHON_VERSION 3.6.2) +set(PYTHON_SHORT_VERSION 3.6) +set(PYTHON_SHORT_VERSION_NO_DOTS 36) +set(PYTHON_URI https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tar.xz) +set(PYTHON_HASH 2c68846471994897278364fc18730dd9) + +set(TBB_VERSION 44_20160128) +set(TBB_URI https://www.threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb${TBB_VERSION}oss_src_0.tgz) +set(TBB_HASH 9d8a4cdf43496f1b3f7c473a5248e5cc) + +set(OPENVDB_VERSION 3.1.0) +set(OPENVDB_URI https://github.com/dreamworksanimation/openvdb/archive/v${OPENVDB_VERSION}.tar.gz) +set(OPENVDB_HASH 30a7e9571a03ab7bcf1a39fb62aa436f) + +set(IDNA_VERSION 2.6) +set(CHARDET_VERSION 3.0.2) +set(URLLIB3_VERSION 1.22) +set(CERTIFI_VERSION 2017.7.27.1) +set(REQUESTS_VERSION 2.18.4) + +set(NUMPY_VERSION v1.13.1) +set(NUMPY_SHORT_VERSION 1.13) +set(NUMPY_URI https://pypi.python.org/packages/c0/3a/40967d9f5675fbb097ffec170f59c2ba19fc96373e73ad47c2cae9a30aed/numpy-1.13.1.zip) +set(NUMPY_HASH 2c3c0f4edf720c3a7b525dacc825b9ae) + +set(LAME_VERSION 3.99.5) +set(LAME_URI http://downloads.sourceforge.net/project/lame/lame/3.99/lame-${LAME_VERSION}.tar.gz) +set(LAME_HASH 84835b313d4a8b68f5349816d33e07ce) + +set(OGG_VERSION 1.3.2) +set(OGG_URI http://downloads.xiph.org/releases/ogg/libogg-${OGG_VERSION}.tar.gz) +set(OGG_HASH e19ee34711d7af328cb26287f4137e70630e7261b17cbe3cd41011d73a654692) + +set(VORBIS_VERSION 1.3.5) +set(VORBIS_URI http://downloads.xiph.org/releases/vorbis/libvorbis-${VORBIS_VERSION}.tar.gz) +set(VORBIS_HASH 6efbcecdd3e5dfbf090341b485da9d176eb250d893e3eb378c428a2db38301ce) + +set(THEORA_VERSION 1.1.1) +set(THEORA_URI http://downloads.xiph.org/releases/theora/libtheora-${THEORA_VERSION}.tar.bz2) +set(THEORA_HASH b6ae1ee2fa3d42ac489287d3ec34c5885730b1296f0801ae577a35193d3affbc) + +set(FLAC_VERSION 1.3.1) +set(FLAC_URI http://downloads.xiph.org/releases/flac/flac-${FLAC_VERSION}.tar.xz) +set(FLAC_HASH 4773c0099dba767d963fd92143263be338c48702172e8754b9bc5103efe1c56c) + +set(VPX_VERSION 1.5.0) +set(VPX_URI http://storage.googleapis.com/downloads.webmproject.org/releases/webm/libvpx-${VPX_VERSION}.tar.bz2) +set(VPX_HASH 306d67908625675f8e188d37a81fbfafdf5068b09d9aa52702b6fbe601c76797) + +set(ORC_VERSION 0.4.25) +set(ORC_URI https://gstreamer.freedesktop.org/src/orc/orc-${ORC_VERSION}.tar.xz) +set(ORC_HASH c1b1d54a58f26d483f0b3881538984789fe5d5460ab8fab74a1cacbd3d1c53d1) + +set(SCHROEDINGER_VERSION 1.0.11) +set(SCHROEDINGER_URI https://download.videolan.org/contrib/schroedinger/schroedinger-${SCHROEDINGER_VERSION}.tar.gz) +set(SCHROEDINGER_HASH 1e572a0735b92aca5746c4528f9bebd35aa0ccf8619b22fa2756137a8cc9f912) + +set(X264_URI http://download.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-20160401-2245-stable.tar.bz2) +set(X264_HASH 1e9a7b835e80313aade53a9b6ff353e099de3856bf5f30a4d8dfc91281f786f5) + +set(XVIDCORE_VERSION 1.3.4) +set(XVIDCORE_URI http://downloads.xvid.org/downloads/xvidcore-${XVIDCORE_VERSION}.tar.gz) +set(XVIDCORE_HASH 4e9fd62728885855bc5007fe1be58df42e5e274497591fec37249e1052ae316f) + +#this has to be in sync with the version in blenders /extern folder +set(OPENJPEG_VERSION 1.5.2) +set(OPENJPEG_SHORT_VERSION 1.5) +set(OPENJPEG_URI https://github.com/uclouvain/openjpeg/archive/version.${OPENJPEG_VERSION}.tar.gz) +set(OPENJPEG_HASH 3734e95edd0bef6e056815591755efd822228dc3cd866894e00a2c929026b16d) + +set(FAAD_VERSION 2-2.7) +set(FAAD_URI http://downloads.sourceforge.net/faac/faad${FAAD_VERSION}.tar.bz2) +set(FAAD_HASH 4c332fa23febc0e4648064685a3d4332) + +set(FFMPEG_VERSION 3.2.1) +set(FFMPEG_URI http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2) +set(FFMPEG_HASH cede174178e61f882844f5870c35ce72) + +set(FFTW_VERSION 3.3.4) +set(FFTW_URI http://www.fftw.org/fftw-${FFTW_VERSION}.tar.gz) +set(FFTW_HASH 2edab8c06b24feeb3b82bbb3ebf3e7b3) + +set(ICONV_VERSION 1.14) +set(ICONV_URI http://ftp.gnu.org/pub/gnu/libiconv/libiconv-${ICONV_VERSION}.tar.gz) +set(ICONV_HASH e34509b1623cec449dfeb73d7ce9c6c6) + +set(LAPACK_VERSION 3.6.0) +set(LAPACK_URI http://www.netlib.org/lapack/lapack-${LAPACK_VERSION}.tgz) +set(LAPACK_HASH f2f6c67134e851fe189bb3ca1fbb5101) + +set(SNDFILE_VERSION 1.0.28) +set(SNDFILE_URI http://www.mega-nerd.com/libsndfile/files/libsndfile-${SNDFILE_VERSION}.tar.gz) +set(SNDFILE_HASH 646b5f98ce89ac60cdb060fcd398247c) + +#set(HIDAPI_VERSION 0.8.0-rc1) +#set(HIDAPI_URI https://github.com/signal11/hidapi/archive/hidapi-${HIDAPI_VERSION}.tar.gz) +#set(HIDAPI_HASH 069f9dd746edc37b6b6d0e3656f47199) + +set(HIDAPI_UID 89a6c75dc6f45ecabd4ddfbd2bf5ba6ad8ba38b5) +set(HIDAPI_URI https://github.com/TheOnlyJoey/hidapi/archive/${HIDAPI_UID}.zip) +set(HIDAPI_HASH b6e22f6b514f8bcf594989f20ffc46fb) + +set(WEBP_VERSION 0.5.1) +set(WEBP_URI https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-${WEBP_VERSION}.tar.gz) +set(WEBP_HASH 3d7db92ebba5b4f679413d25c6040881) + +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(JEMALLOC_VERSION 5.0.1) +set(JEMALLOC_URI https://github.com/jemalloc/jemalloc/releases/download/${JEMALLOC_VERSION}/jemalloc-${JEMALLOC_VERSION}.tar.bz2) +set(JEMALLOC_HASH 507f7b6b882d868730d644510491d18f) + +set(XML2_VERSION 2.9.4) +set(XML2_URI ftp://xmlsoft.org/libxml2/libxml2-${XML2_VERSION}.tar.gz) +set(XML2_HASH ae249165c173b1ff386ee8ad676815f5) diff --git a/build_files/build_environment/cmake/vorbis.cmake b/build_files/build_environment/cmake/vorbis.cmake new file mode 100644 index 00000000000..d16c7c6a1bc --- /dev/null +++ b/build_files/build_environment/cmake/vorbis.cmake @@ -0,0 +1,38 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +ExternalProject_Add(external_vorbis + URL ${VORBIS_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA256=${VORBIS_HASH} + PREFIX ${BUILD_DIR}/vorbis + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vorbis/src/external_vorbis/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/vorbis + --disable-shared + --enable-static + --with-pic + --with-ogg=${LIBDIR}/ogg + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vorbis/src/external_vorbis/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vorbis/src/external_vorbis/ && make install + INSTALL_DIR ${LIBDIR}/vorbis +) + +add_dependencies(external_vorbis external_ogg) + +if(MSVC) + set_target_properties(external_vorbis PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/vpx.cmake b/build_files/build_environment/cmake/vpx.cmake new file mode 100644 index 00000000000..9d155be1c6c --- /dev/null +++ b/build_files/build_environment/cmake/vpx.cmake @@ -0,0 +1,60 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(VPX_EXTRA_FLAGS --target=x86_64-win64-gcc) + else() + set(VPX_EXTRA_FLAGS --target=x86-win32-gcc) + endif() +else() + if(APPLE) + set(VPX_EXTRA_FLAGS --target=x86_64-darwin13-gcc) + else() + set(VPX_EXTRA_FLAGS --target=generic-gnu) + endif() +endif() + +ExternalProject_Add(external_vpx + URL ${VPX_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA256=${VPX_HASH} + PREFIX ${BUILD_DIR}/vpx + CONFIGURE_COMMAND ${CONFIGURE_ENV} && + cd ${BUILD_DIR}/vpx/src/external_vpx/ && + ${CONFIGURE_COMMAND_NO_TARGET} --prefix=${LIBDIR}/vpx + --disable-shared + --enable-static + --disable-install-bins + --disable-install-srcs + --disable-sse4_1 + --disable-sse3 + --disable-ssse3 + --disable-avx + --disable-avx2 + --disable-unit-tests + --disable-examples + ${VPX_EXTRA_FLAGS} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vpx/src/external_vpx/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vpx/src/external_vpx/ && make install + INSTALL_DIR ${LIBDIR}/vpx +) + +if(MSVC) + set_target_properties(external_vpx PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/webp.cmake b/build_files/build_environment/cmake/webp.cmake new file mode 100644 index 00000000000..0504988a088 --- /dev/null +++ b/build_files/build_environment/cmake/webp.cmake @@ -0,0 +1,50 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +# Note the utility apps may use png/tiff/gif system libraries, but the +# library itself does not depend on them, so should give no problems. + +set(WEBP_EXTRA_ARGS + -DWEBP_HAVE_SSE2=ON + -DWEBP_HAVE_SSE41=OFF + -DWEBP_HAVE_AVX2=OFF +) + +if(WIN32) + set(WEBP_BUILD_DIR ${BUILD_MODE}/) +else() + set(WEBP_BUILD_DIR) +endif() + +ExternalProject_Add(external_webp + URL ${WEBP_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${WEBP_HASH} + PREFIX ${BUILD_DIR}/webp + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/webp -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${WEBP_EXTRA_ARGS} + INSTALL_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/webp/src/external_webp-build/${WEBP_BUILD_DIR}${LIBPREFIX}webp${LIBEXT} ${LIBDIR}/webp/lib/${LIBPREFIX}webp${LIBEXT} && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/webp/src/external_webp/src/webp/decode.h ${LIBDIR}/webp/include/webp/decode.h && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/webp/src/external_webp/src/webp/encode.h ${LIBDIR}/webp/include/webp/encode.h && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/webp/src/external_webp/src/webp/demux.h ${LIBDIR}/webp/include/webp/demux.h && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/webp/src/external_webp/src/webp/extras.h ${LIBDIR}/webp/include/webp/extras.h && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/webp/src/external_webp/src/webp/format_constants.h ${LIBDIR}/webp/include/webp/format_constants.h && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/webp/src/external_webp/src/webp/mux.h ${LIBDIR}/webp/include/webp/mux.h && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/webp/src/external_webp/src/webp/mux_types.h ${LIBDIR}/webp/include/webp/mux_types.h && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/webp/src/external_webp/src/webp/types.h ${LIBDIR}/webp/include/webp/types.h + INSTALL_DIR ${LIBDIR}/webp +) diff --git a/build_files/build_environment/cmake/x264.cmake b/build_files/build_environment/cmake/x264.cmake new file mode 100644 index 00000000000..64029ca1b5e --- /dev/null +++ b/build_files/build_environment/cmake/x264.cmake @@ -0,0 +1,40 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + set(X264_EXTRA_ARGS --enable-win32thread --cross-prefix=${MINGW_HOST}- --host=${MINGW_HOST}) +endif() + +ExternalProject_Add(external_x264 + URL ${X264_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA256=${X264_HASH} + PREFIX ${BUILD_DIR}/x264 + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/x264/src/external_x264/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/x264 + --enable-static + --enable-pic + --disable-lavf + ${X264_EXTRA_ARGS} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/x264/src/external_x264/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/x264/src/external_x264/ && make install + INSTALL_DIR ${LIBDIR}/x264 +) + +if(MSVC) + set_target_properties(external_x264 PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/xml2.cmake b/build_files/build_environment/cmake/xml2.cmake new file mode 100644 index 00000000000..a8f87a67ad4 --- /dev/null +++ b/build_files/build_environment/cmake/xml2.cmake @@ -0,0 +1,36 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +ExternalProject_Add(external_xml2 + URL ${XML2_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${XML2_HASH} + PREFIX ${BUILD_DIR}/xml2 + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && ${CONFIGURE_COMMAND} + --prefix=${LIBDIR}/xml2 + --disable-shared + --enable-static + --with-pic + --with-python=no + --with-lzma=no + --with-zlib=no + --with-iconv=no + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make install + INSTALL_DIR ${LIBDIR}/xml2 +) diff --git a/build_files/build_environment/cmake/xvidcore.cmake b/build_files/build_environment/cmake/xvidcore.cmake new file mode 100644 index 00000000000..a341275ea47 --- /dev/null +++ b/build_files/build_environment/cmake/xvidcore.cmake @@ -0,0 +1,44 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +if(WIN32) + set(XVIDCORE_EXTRA_ARGS --host=${MINGW_HOST}) +endif() + +ExternalProject_Add(external_xvidcore + URL ${XVIDCORE_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA256=${XVIDCORE_HASH} + PREFIX ${BUILD_DIR}/xvidcore + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xvidcore/src/external_xvidcore/build/generic && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/xvidcore ${XVIDCORE_EXTRA_ARGS} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xvidcore/src/external_xvidcore/build/generic && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && + ${CMAKE_COMMAND} -E remove ${LIBDIR}/xvidcore/lib/* && # clean because re-installing fails otherwise + cd ${BUILD_DIR}/xvidcore/src/external_xvidcore/build/generic && make install + INSTALL_DIR ${LIBDIR}/xvidcore +) + +ExternalProject_Add_Step(external_xvidcore after_install + COMMAND ${CMAKE_COMMAND} -E rename ${LIBDIR}/xvidcore/lib/xvidcore.a ${LIBDIR}/xvidcore/lib/libxvidcore.a || true + COMMAND ${CMAKE_COMMAND} -E remove ${LIBDIR}/xvidcore/lib/xvidcore.dll.a + DEPENDEES install +) + +if(MSVC) + set_target_properties(external_xvidcore PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/zlib.cmake b/build_files/build_environment/cmake/zlib.cmake new file mode 100644 index 00000000000..3307cb1f167 --- /dev/null +++ b/build_files/build_environment/cmake/zlib.cmake @@ -0,0 +1,33 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +ExternalProject_Add(external_zlib + URL ${ZLIB_URI} + URL_HASH MD5=${ZLIB_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/zlib + CMAKE_ARGS -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${LIBDIR}/zlib ${DEFAULT_CMAKE_FLAGS} + INSTALL_DIR ${LIBDIR}/zlib +) + +if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_zlib after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/zlib/lib/zlibstaticd${LIBEXT} ${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + DEPENDEES install + ) +endif() diff --git a/build_files/build_environment/cmake/zlib_mingw.cmake b/build_files/build_environment/cmake/zlib_mingw.cmake new file mode 100644 index 00000000000..13345f29ffa --- /dev/null +++ b/build_files/build_environment/cmake/zlib_mingw.cmake @@ -0,0 +1,40 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +ExternalProject_Add(external_zlib_mingw + URL ${ZLIB_URI} + URL_HASH MD5=${ZLIB_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/zlib_mingw + CONFIGURE_COMMAND echo . + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/zlib_mingw/src/external_zlib_mingw/ && make -f win32/makefile.gcc -j${MAKE_THREADS} + INSTALL_COMMAND echo . + INSTALL_DIR ${LIBDIR}/zlib_mingw +) + +if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_zlib_mingw after_install + COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/zlib_mingw/src/external_zlib_mingw/libz.a ${LIBDIR}/zlib/lib/z.lib + DEPENDEES install + ) +endif() + +if(MSVC) + set_target_properties(external_zlib_mingw PROPERTIES FOLDER Mingw) +endif() + diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 3852b4fe705..6e2910731bb 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -292,13 +292,13 @@ NO_BUILD=false NO_CONFIRM=false USE_CXX11=false -PYTHON_VERSION="3.5.3" -PYTHON_VERSION_MIN="3.5" +PYTHON_VERSION="3.6.2" +PYTHON_VERSION_MIN="3.6" PYTHON_FORCE_BUILD=false PYTHON_FORCE_REBUILD=false PYTHON_SKIP=false -NUMPY_VERSION="1.10.1" +NUMPY_VERSION="1.13.1" NUMPY_VERSION_MIN="1.8" NUMPY_FORCE_BUILD=false NUMPY_FORCE_REBUILD=false @@ -739,7 +739,7 @@ PRINT "" # This has to be done here, because user might force some versions... PYTHON_SOURCE=( "https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz" ) -NUMPY_SOURCE=( "http://sourceforge.net/projects/numpy/files/NumPy/$NUMPY_VERSION/numpy-$NUMPY_VERSION.tar.gz" ) +NUMPY_SOURCE=( "https://github.com/numpy/numpy/releases/download/v$NUMPY_VERSION/numpy-$NUMPY_VERSION.tar.gz" ) _boost_version_nodots=`echo "$BOOST_VERSION" | sed -r 's/\./_/g'` BOOST_SOURCE=( "http://sourceforge.net/projects/boost/files/boost/$BOOST_VERSION/boost_$_boost_version_nodots.tar.bz2/download" ) @@ -1599,7 +1599,7 @@ compile_OIIO() { fi # To be changed each time we make edits that would modify the compiled result! - oiio_magic=16 + oiio_magic=17 _init_oiio # Clean install if needed! @@ -1663,6 +1663,9 @@ compile_OIIO() { INFO "ILMBASE_HOME=$INST/openexr" fi + # ptex is only needed when nicholas bishop is ready + cmake_d="$cmake_d -D USE_PTEX=OFF" + # Optional tests and cmd tools cmake_d="$cmake_d -D USE_QT=OFF" cmake_d="$cmake_d -D USE_PYTHON=OFF" @@ -1774,7 +1777,7 @@ compile_LLVM() { cd $_src # XXX Ugly patching hack! - patch -p1 -i "$SCRIPT_DIR/install_deps_patches/llvm.patch" + patch -p1 -i "$SCRIPT_DIR/patches/install_deps_llvm.diff" cd $CWD @@ -1880,7 +1883,7 @@ compile_OSL() { git reset --hard # XXX Ugly patching hack! - patch -p1 -i "$SCRIPT_DIR/install_deps_patches/osl.patch" + patch -p1 -i "$SCRIPT_DIR/patches/install_deps_osl.diff" fi # Always refresh the whole build! diff --git a/build_files/build_environment/patches/alembic.diff b/build_files/build_environment/patches/alembic.diff new file mode 100644 index 00000000000..f869858efb2 --- /dev/null +++ b/build_files/build_environment/patches/alembic.diff @@ -0,0 +1,35 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 3e09c57..26565ae 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -116,7 +116,7 @@ IF (NOT ${ALEMBIC_LIB_USES_TR1} AND NOT ${ALEMBIC_LIB_USES_BOOST}) + INCLUDE(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) + CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) +- IF (COMPILER_SUPPORTS_CXX1X) ++ IF (COMPILER_SUPPORTS_CXX11) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + ELSEIF (COMPILER_SUPPORTS_CXX0X) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") +--- a/lib/Alembic/AbcCoreOgawa/StreamManager.cpp ++++ b/lib/Alembic/AbcCoreOgawa/StreamManager.cpp +@@ -47,7 +47,18 @@ + #define COMPARE_EXCHANGE( V, COMP, EXCH ) V.compare_exchange_weak( COMP, EXCH, std::memory_order_seq_cst, std::memory_order_seq_cst ) + // Windows + #elif defined( _MSC_VER ) +-#define COMPARE_EXCHANGE( V, COMP, EXCH ) InterlockedCompareExhange64( &V, EXCH, COMP ) == COMP ++#define COMPARE_EXCHANGE( V, COMP, EXCH ) InterlockedCompareExchange64( &V, EXCH, COMP ) == COMP ++int ffsll(long long value) ++{ ++ if (!value) ++ return 0; ++ ++ for (int bit = 0; bit < 63; bit++) ++ { ++ if (value & (1 << bit)) ++ return bit + 1; ++ } ++} + // gcc 4.8 and above not using C++11 + #elif defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 + #define COMPARE_EXCHANGE( V, COMP, EXCH ) __atomic_compare_exchange_n( &V, &COMP, EXCH, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) diff --git a/build_files/build_environment/patches/blosc.diff b/build_files/build_environment/patches/blosc.diff new file mode 100644 index 00000000000..3bd6ef28144 --- /dev/null +++ b/build_files/build_environment/patches/blosc.diff @@ -0,0 +1,33 @@ +diff -Naur src/blosc/CMakeLists.txt external_blosc/blosc/CMakeLists.txt +--- src/blosc/CMakeLists.txt 2016-02-03 10:26:28 -0700 ++++ external_blosc/blosc/CMakeLists.txt 2017-03-03 09:03:31 -0700 +@@ -61,6 +61,8 @@ + set(SOURCES ${SOURCES} win32/pthread.c) + else(NOT Threads_FOUND) + set(LIBS ${LIBS} ${CMAKE_THREAD_LIBS_INIT}) ++ set(LIBS ${LIBS} ${PTHREAD_LIBS}) ++ include_directories( ${PTHREAD_INCLUDE_DIR} ) + endif(NOT Threads_FOUND) + else(WIN32) + find_package(Threads REQUIRED) +diff -Naur src/blosc/blosc.c external_blosc/blosc/blosc.c +--- src/blosc/blosc.c 2016-02-03 10:26:28 -0700 ++++ external_blosc/blosc/blosc.c 2017-03-03 09:01:50 -0700 +@@ -49,12 +49,12 @@ + #include <inttypes.h> + #endif /* _WIN32 */ + +-#if defined(_WIN32) && !defined(__GNUC__) +- #include "win32/pthread.h" +- #include "win32/pthread.c" +-#else ++//#if defined(_WIN32) && !defined(__GNUC__) ++// #include "win32/pthread.h" ++ //#include "win32/pthread.c" ++//#else + #include <pthread.h> +-#endif ++//#endif + + /* If C11 is supported, use it's built-in aligned allocation. */ + #if __STDC_VERSION__ >= 201112L diff --git a/build_files/build_environment/patches/clang.diff b/build_files/build_environment/patches/clang.diff new file mode 100644 index 00000000000..724e92f8163 --- /dev/null +++ b/build_files/build_environment/patches/clang.diff @@ -0,0 +1,127 @@ +--- cfe/trunk/lib/Serialization/ASTWriter.cpp ++++ cfe/trunk/lib/Serialization/ASTWriter.cpp +@@ -56,14 +56,14 @@ + using namespace clang::serialization; + + template <typename T, typename Allocator> +-static StringRef bytes(const std::vector<T, Allocator> &v) { ++static StringRef data(const std::vector<T, Allocator> &v) { + if (v.empty()) return StringRef(); + return StringRef(reinterpret_cast<const char*>(&v[0]), + sizeof(T) * v.size()); + } + + template <typename T> +-static StringRef bytes(const SmallVectorImpl<T> &v) { ++static StringRef data(const SmallVectorImpl<T> &v) { + return StringRef(reinterpret_cast<const char*>(v.data()), + sizeof(T) * v.size()); + } +@@ -1385,7 +1385,7 @@ + Record.push_back(INPUT_FILE_OFFSETS); + Record.push_back(InputFileOffsets.size()); + Record.push_back(UserFilesNum); +- Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, bytes(InputFileOffsets)); ++ Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, data(InputFileOffsets)); + } + + //===----------------------------------------------------------------------===// +@@ -1771,7 +1771,7 @@ + Record.push_back(SOURCE_LOCATION_OFFSETS); + Record.push_back(SLocEntryOffsets.size()); + Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy +- Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, bytes(SLocEntryOffsets)); ++ Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets)); + + // Write the source location entry preloads array, telling the AST + // reader which source locations entries it should load eagerly. +@@ -2087,7 +2087,7 @@ + Record.push_back(MacroOffsets.size()); + Record.push_back(FirstMacroID - NUM_PREDEF_MACRO_IDS); + Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record, +- bytes(MacroOffsets)); ++ data(MacroOffsets)); + } + + void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { +@@ -2185,7 +2185,7 @@ + Record.push_back(PPD_ENTITIES_OFFSETS); + Record.push_back(FirstPreprocessorEntityID - NUM_PREDEF_PP_ENTITY_IDS); + Stream.EmitRecordWithBlob(PPEOffsetAbbrev, Record, +- bytes(PreprocessedEntityOffsets)); ++ data(PreprocessedEntityOffsets)); + } + } + +@@ -2548,7 +2548,7 @@ + Record.push_back(CXX_BASE_SPECIFIER_OFFSETS); + Record.push_back(CXXBaseSpecifiersOffsets.size()); + Stream.EmitRecordWithBlob(BaseSpecifierOffsetAbbrev, Record, +- bytes(CXXBaseSpecifiersOffsets)); ++ data(CXXBaseSpecifiersOffsets)); + } + + //===----------------------------------------------------------------------===// +@@ -2623,7 +2623,7 @@ + Decls.push_back(std::make_pair((*D)->getKind(), GetDeclRef(*D))); + + ++NumLexicalDeclContexts; +- Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, bytes(Decls)); ++ Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, data(Decls)); + return Offset; + } + +@@ -2642,7 +2642,7 @@ + Record.push_back(TYPE_OFFSET); + Record.push_back(TypeOffsets.size()); + Record.push_back(FirstTypeID - NUM_PREDEF_TYPE_IDS); +- Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, bytes(TypeOffsets)); ++ Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, data(TypeOffsets)); + + // Write the declaration offsets array + Abbrev = new BitCodeAbbrev(); +@@ -2655,7 +2655,7 @@ + Record.push_back(DECL_OFFSET); + Record.push_back(DeclOffsets.size()); + Record.push_back(FirstDeclID - NUM_PREDEF_DECL_IDS); +- Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, bytes(DeclOffsets)); ++ Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, data(DeclOffsets)); + } + + void ASTWriter::WriteFileDeclIDsMap() { +@@ -2680,7 +2680,7 @@ + unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); + Record.push_back(FILE_SORTED_DECLS); + Record.push_back(FileSortedIDs.size()); +- Stream.EmitRecordWithBlob(AbbrevCode, Record, bytes(FileSortedIDs)); ++ Stream.EmitRecordWithBlob(AbbrevCode, Record, data(FileSortedIDs)); + } + + void ASTWriter::WriteComments() { +@@ -2893,7 +2893,7 @@ + Record.push_back(SelectorOffsets.size()); + Record.push_back(FirstSelectorID - NUM_PREDEF_SELECTOR_IDS); + Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record, +- bytes(SelectorOffsets)); ++ data(SelectorOffsets)); + } + } + +@@ -3253,7 +3253,7 @@ + Record.push_back(IdentifierOffsets.size()); + Record.push_back(FirstIdentID - NUM_PREDEF_IDENT_IDS); + Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record, +- bytes(IdentifierOffsets)); ++ data(IdentifierOffsets)); + } + + //===----------------------------------------------------------------------===// +@@ -4046,7 +4046,7 @@ + Record.clear(); + Record.push_back(TU_UPDATE_LEXICAL); + Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, +- bytes(NewGlobalDecls)); ++ data(NewGlobalDecls)); + + // And a visible updates block for the translation unit. + Abv = new llvm::BitCodeAbbrev(); diff --git a/build_files/build_environment/patches/cmake/modules/FindBlosc.cmake b/build_files/build_environment/patches/cmake/modules/FindBlosc.cmake new file mode 100644 index 00000000000..d490b7a2ff3 --- /dev/null +++ b/build_files/build_environment/patches/cmake/modules/FindBlosc.cmake @@ -0,0 +1,73 @@ +# - Find BLOSC library +# Find the native BLOSC includes and library +# This module defines +# BLOSC_INCLUDE_DIRS, where to find blosc.h, Set when +# BLOSC is found. +# BLOSC_LIBRARIES, libraries to link against to use BLOSC. +# BLOSC_ROOT_DIR, The base directory to search for BLOSC. +# This can also be an environment variable. +# BLOSC_FOUND, If false, do not try to use BLOSC. +# +# also defined, but not for general use are +# BLOSC_LIBRARY, where to find the BLOSC library. + +#============================================================================= +# Copyright 2016 Blender Foundation. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= + +# If BLOSC_ROOT_DIR was defined in the environment, use it. +IF(NOT BLOSC_ROOT_DIR AND NOT $ENV{BLOSC_ROOT_DIR} STREQUAL "") + SET(BLOSC_ROOT_DIR $ENV{BLOSC_ROOT_DIR}) +ENDIF() + +SET(_blosc_SEARCH_DIRS + ${BLOSC_ROOT_DIR} + /usr/local + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt/lib/blosc +) + +FIND_PATH(BLOSC_INCLUDE_DIR + NAMES + blosc.h + HINTS + ${_blosc_SEARCH_DIRS} + PATH_SUFFIXES + include +) + +FIND_LIBRARY(BLOSC_LIBRARY + NAMES + blosc + HINTS + ${_blosc_SEARCH_DIRS} + PATH_SUFFIXES + lib64 lib +) + +# handle the QUIETLY and REQUIRED arguments and set BLOSC_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(BLOSC DEFAULT_MSG + BLOSC_LIBRARY BLOSC_INCLUDE_DIR) + +IF(BLOSC_FOUND) + SET(BLOSC_LIBRARIES ${BLOSC_LIBRARY}) + SET(BLOSC_INCLUDE_DIRS ${BLOSC_INCLUDE_DIR}) +ELSE() + SET(BLOSC_FOUND FALSE) +ENDIF() + +MARK_AS_ADVANCED( + BLOSC_INCLUDE_DIR + BLOSC_LIBRARY +) diff --git a/build_files/build_environment/patches/cmake/modules/FindCppUnit.cmake b/build_files/build_environment/patches/cmake/modules/FindCppUnit.cmake new file mode 100644 index 00000000000..3dd480356af --- /dev/null +++ b/build_files/build_environment/patches/cmake/modules/FindCppUnit.cmake @@ -0,0 +1,73 @@ +# - Find CPPUNIT library +# Find the native CPPUNIT includes and library +# This module defines +# CPPUNIT_INCLUDE_DIRS, where to find cppunit.h, Set when +# CPPUNIT is found. +# CPPUNIT_LIBRARIES, libraries to link against to use CPPUNIT. +# CPPUNIT_ROOT_DIR, The base directory to search for CPPUNIT. +# This can also be an environment variable. +# CPPUNIT_FOUND, If false, do not try to use CPPUNIT. +# +# also defined, but not for general use are +# CPPUNIT_LIBRARY, where to find the CPPUNIT library. + +#============================================================================= +# Copyright 2016 Blender Foundation. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= + +# If CPPUNIT_ROOT_DIR was defined in the environment, use it. +IF(NOT CPPUNIT_ROOT_DIR AND NOT $ENV{CPPUNIT_ROOT_DIR} STREQUAL "") + SET(CPPUNIT_ROOT_DIR $ENV{CPPUNIT_ROOT_DIR}) +ENDIF() + +SET(_cppunit_SEARCH_DIRS + ${CPPUNIT_ROOT_DIR} + /usr/local + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt/lib/cppunit +) + +FIND_PATH(CPPUNIT_INCLUDE_DIR + NAMES + cppunit/Test.h + HINTS + ${_cppunit_SEARCH_DIRS} + PATH_SUFFIXES + include +) + +FIND_LIBRARY(CPPUNIT_LIBRARY + NAMES + cppunit + HINTS + ${_cppunit_SEARCH_DIRS} + PATH_SUFFIXES + lib64 lib +) + +# handle the QUIETLY and REQUIRED arguments and set CPPUNIT_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(CPPUNIT DEFAULT_MSG + CPPUNIT_LIBRARY CPPUNIT_INCLUDE_DIR) + +IF(CPPUNIT_FOUND) + SET(CPPUNIT_LIBRARIES ${CPPUNIT_LIBRARY}) + SET(CPPUNIT_INCLUDE_DIRS ${CPPUNIT_INCLUDE_DIR}) +ELSE() + SET(CPPUNIT_FOUND FALSE) +ENDIF() + +MARK_AS_ADVANCED( + CPPUNIT_INCLUDE_DIR + CPPUNIT_LIBRARY +) diff --git a/build_files/build_environment/patches/cmake/modules/FindIlmBase.cmake b/build_files/build_environment/patches/cmake/modules/FindIlmBase.cmake new file mode 100644 index 00000000000..f1a45228128 --- /dev/null +++ b/build_files/build_environment/patches/cmake/modules/FindIlmBase.cmake @@ -0,0 +1,260 @@ +# Module to find IlmBase +# +# This module will first look into the directories defined by the variables: +# - ILMBASE_HOME, ILMBASE_VERSION, ILMBASE_LIB_AREA +# +# It also supports non-standard names for the library components. +# +# To use a custom IlmBase: +# - Set the variable ILMBASE_CUSTOM to True +# - Set the variable ILMBASE_CUSTOM_LIBRARIES to a list of the libraries to +# use, e.g. "SpiImath SpiHalf SpiIlmThread SpiIex" +# - Optionally set the variable ILMBASE_CUSTOM_INCLUDE_DIR to any +# particularly weird place that the OpenEXR/*.h files may be found +# - Optionally set the variable ILMBASE_CUSTOM_LIB_DIR to any +# particularly weird place that the libraries files may be found +# +# This module defines the following variables: +# +# ILMBASE_INCLUDE_DIR - where to find half.h, IlmBaseConfig.h, etc. +# ILMBASE_LIBRARIES - list of libraries to link against when using IlmBase. +# ILMBASE_FOUND - True if IlmBase was found. + +# Other standarnd issue macros +include (FindPackageHandleStandardArgs) +include (FindPackageMessage) +include (SelectLibraryConfigurations) + + +if( ILMBASE_USE_STATIC_LIBS ) + set( _ilmbase_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + if(WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES .a ) + endif() +endif() + +# Macro to assemble a helper state variable +macro (SET_STATE_VAR varname) + set (tmp_ilmbaselibs ${ILMBASE_CUSTOM_LIBRARIES}) + separate_arguments (tmp_ilmbaselibs) + set (tmp_lst + ${ILMBASE_CUSTOM} | ${tmp_ilmbaselibs} | + ${ILMBASE_HOME} | ${ILMBASE_VERSION} | ${ILMBASE_LIB_AREA} + ) + set (${varname} "${tmp_lst}") + unset (tmp_ilmbaselibs) + unset (tmp_lst) +endmacro () + +# To enforce that find_* functions do not use inadvertently existing versions +if (ILMBASE_CUSTOM) + set (ILMBASE_FIND_OPTIONS "NO_DEFAULT_PATH") +endif () + +# Macro to search for an include directory +macro (PREFIX_FIND_INCLUDE_DIR prefix includefile libpath_var) + string (TOUPPER ${prefix}_INCLUDE_DIR tmp_varname) + find_path(${tmp_varname} ${includefile} + HINTS ${${libpath_var}} + PATH_SUFFIXES include + ${ILMBASE_FIND_OPTIONS} + ) + if (${tmp_varname}) + mark_as_advanced (${tmp_varname}) + endif () + unset (tmp_varname) +endmacro () + + +# Macro to search for the given library and adds the cached +# variable names to the specified list +macro (PREFIX_FIND_LIB prefix libname libpath_var liblist_var cachelist_var) + string (TOUPPER ${prefix}_${libname} tmp_prefix) + # Handle new library names for OpenEXR 2.1 build via cmake + string(REPLACE "." "_" _ILMBASE_VERSION ${ILMBASE_VERSION}) + string(SUBSTRING ${_ILMBASE_VERSION} 0 3 _ILMBASE_VERSION ) + + find_library(${tmp_prefix}_LIBRARY_RELEASE + NAMES ${libname} ${libname}-${_ILMBASE_VERSION} + HINTS ${${libpath_var}} + PATH_SUFFIXES lib + ${ILMBASE_FIND_OPTIONS} + ) + find_library(${tmp_prefix}_LIBRARY_DEBUG + NAMES ${libname}d ${libname}_d ${libname}debug ${libname}_debug + HINTS ${${libpath_var}} + PATH_SUFFIXES lib + ${ILMBASE_FIND_OPTIONS} + ) + # Properly define ${tmp_prefix}_LIBRARY (cached) and ${tmp_prefix}_LIBRARIES + select_library_configurations (${tmp_prefix}) + list (APPEND ${liblist_var} ${tmp_prefix}_LIBRARIES) + + # Add to the list of variables which should be reset + list (APPEND ${cachelist_var} + ${tmp_prefix}_LIBRARY + ${tmp_prefix}_LIBRARY_RELEASE + ${tmp_prefix}_LIBRARY_DEBUG) + mark_as_advanced ( + ${tmp_prefix}_LIBRARY + ${tmp_prefix}_LIBRARY_RELEASE + ${tmp_prefix}_LIBRARY_DEBUG) + unset (tmp_prefix) +endmacro () + + +# Encode the current state of the external variables into a string +SET_STATE_VAR (ILMBASE_CURRENT_STATE) + +# If the state has changed, clear the cached variables +if (ILMBASE_CACHED_STATE AND + NOT ILMBASE_CACHED_STATE STREQUAL ILMBASE_CURRENT_STATE) + + foreach (libvar ${ILMBASE_CACHED_VARS}) + unset (${libvar} CACHE) + endforeach () +endif () + + +# Generic search paths +set (IlmBase_generic_include_paths + ${ILMBASE_CUSTOM_INCLUDE_DIR} + /usr/include + /usr/include/${CMAKE_LIBRARY_ARCHITECTURE} + /usr/local/include + /sw/include + /opt/local/include) +set (IlmBase_generic_library_paths + ${ILMBASE_CUSTOM_LIB_DIR} + /usr/lib + /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} + /usr/local/lib + /usr/local/lib/${CMAKE_LIBRARY_ARCHITECTURE} + /sw/lib + /opt/local/lib) + +# Search paths for the IlmBase files +if (ILMBASE_HOME) + if (ILMBASE_VERSION) + set (IlmBase_include_paths + ${ILMBASE_HOME}/ilmbase-${ILMBASE_VERSION}/include + ${ILMBASE_HOME}/include/ilmbase-${ILMBASE_VERSION}) + set (IlmBase_library_paths + ${ILMBASE_HOME}/ilmbase-${ILMBASE_VERSION}/lib + ${ILMBASE_HOME}/lib/ilmbase-${ILMBASE_VERSION}) + endif() + list (APPEND IlmBase_include_paths ${ILMBASE_HOME}/include) + set (IlmBase_library_paths + ${ILMBASE_HOME}/lib + ${ILMBASE_HOME}/lib64 + ${ILMBASE_LIB_AREA} + ${IlmBase_library_paths}) +endif () +list (APPEND IlmBase_include_paths ${IlmBase_generic_include_paths}) +list (APPEND IlmBase_library_paths ${IlmBase_generic_library_paths}) + +# Locate the header files +PREFIX_FIND_INCLUDE_DIR (IlmBase + OpenEXR/IlmBaseConfig.h IlmBase_include_paths) + +if (ILMBASE_INCLUDE_DIR) + # Get the version from config file, if not already set. + if (NOT ILMBASE_VERSION) + FILE(STRINGS "${ILMBASE_INCLUDE_DIR}/OpenEXR/IlmBaseConfig.h" ILMBASE_BUILD_SPECIFICATION + REGEX "^[ \t]*#define[ \t]+ILMBASE_VERSION_STRING[ \t]+\"[.0-9]+\".*$") + + if(ILMBASE_BUILD_SPECIFICATION) + if (NOT IlmBase_FIND_QUIETLY) + message(STATUS "${ILMBASE_BUILD_SPECIFICATION}") + endif () + string(REGEX REPLACE ".*#define[ \t]+ILMBASE_VERSION_STRING[ \t]+\"([.0-9]+)\".*" + "\\1" XYZ ${ILMBASE_BUILD_SPECIFICATION}) + set("ILMBASE_VERSION" ${XYZ} CACHE STRING "Version of ILMBase lib") + else() + # Old versions (before 2.0?) do not have any version string, just assuming 2.0 should be fine though. + message(WARNING "Could not determine ILMBase library version, assuming 2.0.") + set("ILMBASE_VERSION" "2.0" CACHE STRING "Version of ILMBase lib") + endif() + endif() +endif () + + +if (ILMBASE_CUSTOM) + if (NOT ILMBASE_CUSTOM_LIBRARIES) + message (FATAL_ERROR "Custom IlmBase libraries requested but ILMBASE_CUSTOM_LIBRARIES is not set.") + endif() + set (IlmBase_Libraries ${ILMBASE_CUSTOM_LIBRARIES}) + separate_arguments(IlmBase_Libraries) +else () +#elseif (${ILMBASE_VERSION} VERSION_LESS "2.1") + set (IlmBase_Libraries Half Iex Imath IlmThread) +#else () +# string(REGEX REPLACE "([0-9]+)[.]([0-9]+).*" "\\1_\\2" _ilmbase_libs_ver ${ILMBASE_VERSION}) +# set (IlmBase_Libraries Half Iex-${_ilmbase_libs_ver} Imath-${_ilmbase_libs_ver} IlmThread-${_ilmbase_libs_ver}) +endif () + + +# Locate the IlmBase libraries +set (IlmBase_libvars "") +set (IlmBase_cachevars "") +foreach (ilmbase_lib ${IlmBase_Libraries}) + PREFIX_FIND_LIB (IlmBase ${ilmbase_lib} + IlmBase_library_paths IlmBase_libvars IlmBase_cachevars) +endforeach () +# Create the list of variables that might need to be cleared +set (ILMBASE_CACHED_VARS + ILMBASE_INCLUDE_DIR ${IlmBase_cachevars} + CACHE INTERNAL "Variables set by FindIlmBase.cmake" FORCE) + +# Store the current state so that variables might be cleared if required +set (ILMBASE_CACHED_STATE ${ILMBASE_CURRENT_STATE} + CACHE INTERNAL "State last seen by FindIlmBase.cmake" FORCE) + +# Link with pthreads if required +if (NOT WIN32 AND EXISTS ${ILMBASE_INCLUDE_DIR}/OpenEXR/IlmBaseConfig.h) + file (STRINGS ${ILMBASE_INCLUDE_DIR}/OpenEXR/IlmBaseConfig.h + ILMBASE_HAVE_PTHREAD + REGEX "^[ \\t]*#define[ \\t]+HAVE_PTHREAD[ \\t]1[ \\t]*\$" + ) + if (ILMBASE_HAVE_PTHREAD) + find_package (Threads) + if (CMAKE_USE_PTHREADS_INIT) + set (ILMBASE_PTHREADS ${CMAKE_THREAD_LIBS_INIT}) + endif () + endif () +endif () + +# Use the standard function to handle ILMBASE_FOUND +FIND_PACKAGE_HANDLE_STANDARD_ARGS (IlmBase DEFAULT_MSG + ILMBASE_INCLUDE_DIR ${IlmBase_libvars}) + +if (ILMBASE_FOUND) + set (ILMBASE_LIBRARIES "") + foreach (tmplib ${IlmBase_libvars}) + list (APPEND ILMBASE_LIBRARIES ${${tmplib}}) + endforeach () + list (APPEND ILMBASE_LIBRARIES ${ILMBASE_PTHREADS}) + if (NOT IlmBase_FIND_QUIETLY) + FIND_PACKAGE_MESSAGE (ILMBASE + "Found IlmBase: ${ILMBASE_LIBRARIES}" + "[${ILMBASE_INCLUDE_DIR}][${ILMBASE_LIBRARIES}][${ILMBASE_CURRENT_STATE}]" + ) + endif () +endif () + +# Restore the original find library ordering +if( ILMBASE_USE_STATIC_LIBS ) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${_ilmbase_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) +endif() + +# Unset the helper variables to avoid pollution +unset (ILMBASE_CURRENT_STATE) +unset (IlmBase_include_paths) +unset (IlmBase_library_paths) +unset (IlmBase_generic_include_paths) +unset (IlmBase_generic_library_paths) +unset (IlmBase_libvars) +unset (IlmBase_cachevars) +unset (ILMBASE_PTHREADS) diff --git a/build_files/build_environment/patches/cmake/modules/FindLogC4Plus.cmake b/build_files/build_environment/patches/cmake/modules/FindLogC4Plus.cmake new file mode 100644 index 00000000000..2002419cc75 --- /dev/null +++ b/build_files/build_environment/patches/cmake/modules/FindLogC4Plus.cmake @@ -0,0 +1,73 @@ +# - Find LOGC4PLUS library +# Find the native LOGC4PLUS includes and library +# This module defines +# LOGC4PLUS_INCLUDE_DIRS, where to find logc4plus.h, Set when +# LOGC4PLUS is found. +# LOGC4PLUS_LIBRARIES, libraries to link against to use LOGC4PLUS. +# LOGC4PLUS_ROOT_DIR, The base directory to search for LOGC4PLUS. +# This can also be an environment variable. +# LOGC4PLUS_FOUND, If false, do not try to use LOGC4PLUS. +# +# also defined, but not for general use are +# LOGC4PLUS_LIBRARY, where to find the LOGC4PLUS library. + +#============================================================================= +# Copyright 2016 Blender Foundation. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= + +# If LOGC4PLUS_ROOT_DIR was defined in the environment, use it. +IF(NOT LOGC4PLUS_ROOT_DIR AND NOT $ENV{LOGC4PLUS_ROOT_DIR} STREQUAL "") + SET(LOGC4PLUS_ROOT_DIR $ENV{LOGC4PLUS_ROOT_DIR}) +ENDIF() + +SET(_logc4plus_SEARCH_DIRS + ${LOGC4PLUS_ROOT_DIR} + /usr/local + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt/lib/logc4plus +) + +FIND_PATH(LOGC4PLUS_INCLUDE_DIR + NAMES + logc4plus.h + HINTS + ${_logc4plus_SEARCH_DIRS} + PATH_SUFFIXES + include +) + +FIND_LIBRARY(LOGC4PLUS_LIBRARY + NAMES + logc4plus + HINTS + ${_logc4plus_SEARCH_DIRS} + PATH_SUFFIXES + lib64 lib + ) + +# handle the QUIETLY and REQUIRED arguments and set LOGC4PLUS_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LOGC4PLUS DEFAULT_MSG + LOGC4PLUS_LIBRARY LOGC4PLUS_INCLUDE_DIR) + +IF(LOGC4PLUS_FOUND) + SET(LOGC4PLUS_LIBRARIES ${LOGC4PLUS_LIBRARY}) + SET(LOGC4PLUS_INCLUDE_DIRS ${LOGC4PLUS_INCLUDE_DIR}) +ELSE() + SET(LOGC4PLUS_LOGC4PLUS_FOUND FALSE) +ENDIF() + +MARK_AS_ADVANCED( + LOGC4PLUS_INCLUDE_DIR + LOGC4PLUS_LIBRARY +) diff --git a/build_files/build_environment/patches/cmake/modules/FindOpenEXR.cmake b/build_files/build_environment/patches/cmake/modules/FindOpenEXR.cmake new file mode 100644 index 00000000000..08d872445d7 --- /dev/null +++ b/build_files/build_environment/patches/cmake/modules/FindOpenEXR.cmake @@ -0,0 +1,244 @@ +# Module to find OpenEXR. +# +# This module will first look into the directories defined by the variables: +# - OPENEXR_HOME, OPENEXR_VERSION, OPENEXR_LIB_AREA +# +# It also supports non-standard names for the library components. +# +# To use a custom OpenEXR +# - Set the variable OPENEXR_CUSTOM to True +# - Set the variable OPENEXR_CUSTOM_LIBRARY to the name of the library to +# use, e.g. "SpiIlmImf" +# - Optionally set the variable OPENEXR_CUSTOM_INCLUDE_DIR to any +# particularly weird place that the OpenEXR/*.h files may be found +# - Optionally set the variable OPENEXR_CUSTOM_LIB_DIR to any +# particularly weird place that the libraries files may be found +# +# This module defines the following variables: +# +# OPENEXR_INCLUDE_DIR - where to find ImfRgbaFile.h, OpenEXRConfig, etc. +# OPENEXR_LIBRARIES - list of libraries to link against when using OpenEXR. +# This list does NOT include the IlmBase libraries. +# These are defined by the FindIlmBase module. +# OPENEXR_FOUND - True if OpenEXR was found. + +# Other standarnd issue macros +include (SelectLibraryConfigurations) +include (FindPackageHandleStandardArgs) +include (FindPackageMessage) + +if( OPENEXR_USE_STATIC_LIBS ) + set( _openexr_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + if(WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES .a ) + endif() +endif() + +# Macro to assemble a helper state variable +macro (SET_STATE_VAR varname) + set (tmp_lst + ${OPENEXR_CUSTOM} | ${OPENEXR_CUSTOM_LIBRARY} | + ${OPENEXR_HOME} | ${OPENEXR_VERSION} | ${OPENEXR_LIB_AREA} + ) + set (${varname} "${tmp_lst}") + unset (tmp_lst) +endmacro () + +# To enforce that find_* functions do not use inadvertently existing versions +if (OPENEXR_CUSTOM) + set (OPENEXR_FIND_OPTIONS "NO_DEFAULT_PATH") +endif () + +# Macro to search for an include directory +macro (PREFIX_FIND_INCLUDE_DIR prefix includefile libpath_var) + string (TOUPPER ${prefix}_INCLUDE_DIR tmp_varname) + find_path(${tmp_varname} ${includefile} + HINTS ${${libpath_var}} + PATH_SUFFIXES include + ${OPENEXR_FIND_OPTIONS} + ) + if (${tmp_varname}) + mark_as_advanced (${tmp_varname}) + endif () + unset (tmp_varname) +endmacro () + + +# Macro to search for the given library and adds the cached +# variable names to the specified list +macro (PREFIX_FIND_LIB prefix libname libpath_var liblist_var cachelist_var) + string (TOUPPER ${prefix}_${libname} tmp_prefix) + # Handle new library names for OpenEXR 2.1 build via cmake + string(REPLACE "." "_" _ILMBASE_VERSION ${ILMBASE_VERSION}) + string(SUBSTRING ${_ILMBASE_VERSION} 0 3 _ILMBASE_VERSION ) + find_library(${tmp_prefix}_LIBRARY_RELEASE + NAMES ${libname} ${libname}-${_ILMBASE_VERSION} + HINTS ${${libpath_var}} + PATH_SUFFIXES lib + ${OPENEXR_FIND_OPTIONS} + ) + find_library(${tmp_prefix}_LIBRARY_DEBUG + NAMES ${libname}d ${libname}_d ${libname}debug ${libname}_debug + HINTS ${${libpath_var}} + PATH_SUFFIXES lib + ${OPENEXR_FIND_OPTIONS} + ) + # Properly define ${tmp_prefix}_LIBRARY (cached) and ${tmp_prefix}_LIBRARIES + select_library_configurations (${tmp_prefix}) + list (APPEND ${liblist_var} ${tmp_prefix}_LIBRARIES) + + # Add to the list of variables which should be reset + list (APPEND ${cachelist_var} + ${tmp_prefix}_LIBRARY + ${tmp_prefix}_LIBRARY_RELEASE + ${tmp_prefix}_LIBRARY_DEBUG) + mark_as_advanced ( + ${tmp_prefix}_LIBRARY + ${tmp_prefix}_LIBRARY_RELEASE + ${tmp_prefix}_LIBRARY_DEBUG) + unset (tmp_prefix) +endmacro () + + +# Encode the current state of the external variables into a string +SET_STATE_VAR (OPENEXR_CURRENT_STATE) + +# If the state has changed, clear the cached variables +if (OPENEXR_CACHED_STATE AND + NOT OPENEXR_CACHED_STATE STREQUAL OPENEXR_CURRENT_STATE) + foreach (libvar ${OPENEXR_CACHED_VARS}) + unset (${libvar} CACHE) + endforeach () +endif () + +# Generic search paths +set (OpenEXR_generic_include_paths + ${OPENEXR_CUSTOM_INCLUDE_DIR} + /usr/include + /usr/include/${CMAKE_LIBRARY_ARCHITECTURE} + /usr/local/include + /sw/include + /opt/local/include) +set (OpenEXR_generic_library_paths + ${OPENEXR_CUSTOM_LIB_DIR} + /usr/lib + /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} + /usr/local/lib + /usr/local/lib/${CMAKE_LIBRARY_ARCHITECTURE} + /sw/lib + /opt/local/lib) + +# Search paths for the OpenEXR files +if (OPENEXR_HOME) + set (OpenEXR_library_paths + ${OPENEXR_HOME}/lib + ${OPENEXR_HOME}/lib64) + if (OPENEXR_VERSION) + set (OpenEXR_include_paths + ${OPENEXR_HOME}/openexr-${OPENEXR_VERSION}/include + ${OPENEXR_HOME}/include/openexr-${OPENEXR_VERSION}) + list (APPEND OpenEXR_library_paths + ${OPENEXR_HOME}/openexr-${OPENEXR_VERSION}/lib + ${OPENEXR_HOME}/lib/openexr-${OPENEXR_VERSION}) + endif() + list (APPEND OpenEXR_include_paths ${OPENEXR_HOME}/include) + if (OPENEXR_LIB_AREA) + list (INSERT OpenEXR_library_paths 2 ${OPENEXR_LIB_AREA}) + endif () +endif () +if (ILMBASE_HOME AND OPENEXR_VERSION) + list (APPEND OpenEXR_include_paths + ${ILMBASE_HOME}/include/openexr-${OPENEXR_VERSION}) +endif() +list (APPEND OpenEXR_include_paths ${OpenEXR_generic_include_paths}) +list (APPEND OpenEXR_library_paths ${OpenEXR_generic_library_paths}) + +# Locate the header files +PREFIX_FIND_INCLUDE_DIR (OpenEXR + OpenEXR/ImfArray.h OpenEXR_include_paths) + +if (OPENEXR_INCLUDE_DIR) + # Get the version from config file, if not already set. + if (NOT OPENEXR_VERSION) + FILE(STRINGS "${OPENEXR_INCLUDE_DIR}/OpenEXR/OpenEXRConfig.h" OPENEXR_BUILD_SPECIFICATION + REGEX "^[ \t]*#define[ \t]+OPENEXR_VERSION_STRING[ \t]+\"[.0-9]+\".*$") + + if(OPENEXR_BUILD_SPECIFICATION) + if (NOT OpenEXR_FIND_QUIETLY) + message(STATUS "${OPENEXR_BUILD_SPECIFICATION}") + endif () + string(REGEX REPLACE ".*#define[ \t]+OPENEXR_VERSION_STRING[ \t]+\"([.0-9]+)\".*" + "\\1" XYZ ${OPENEXR_BUILD_SPECIFICATION}) + set("OPENEXR_VERSION" ${XYZ} CACHE STRING "Version of OpenEXR lib") + else() + # Old versions (before 2.0?) do not have any version string, just assuming 2.0 should be fine though. + message(WARNING "Could not determine ILMBase library version, assuming 2.0.") + set("OPENEXR_VERSION" "2.0" CACHE STRING "Version of OpenEXR lib") + endif() + endif() +endif () + +if (OPENEXR_CUSTOM) + if (NOT OPENEXR_CUSTOM_LIBRARY) + message (FATAL_ERROR "Custom OpenEXR library requested but OPENEXR_CUSTOM_LIBRARY is not set.") + endif() + set (OpenEXR_Library ${OPENEXR_CUSTOM_LIBRARY}) +else () +#elseif (${OPENEXR_VERSION} VERSION_LESS "2.1") + set (OpenEXR_Library IlmImf) +#else () +# string(REGEX REPLACE "([0-9]+)[.]([0-9]+).*" "\\1_\\2" _openexr_libs_ver ${OPENEXR_VERSION}) +# set (OpenEXR_Library IlmImf-${_openexr_libs_ver}) +endif () + +# Locate the OpenEXR library +set (OpenEXR_libvars "") +set (OpenEXR_cachevars "") +PREFIX_FIND_LIB (OpenEXR ${OpenEXR_Library} + OpenEXR_library_paths OpenEXR_libvars OpenEXR_cachevars) + +# Create the list of variables that might need to be cleared +set (OPENEXR_CACHED_VARS + OPENEXR_INCLUDE_DIR ${OpenEXR_cachevars} + CACHE INTERNAL "Variables set by FindOpenEXR.cmake" FORCE) + +# Store the current state so that variables might be cleared if required +set (OPENEXR_CACHED_STATE ${OPENEXR_CURRENT_STATE} + CACHE INTERNAL "State last seen by FindOpenEXR.cmake" FORCE) + +# Always link explicitly with zlib +set (OPENEXR_ZLIB ${ZLIB_LIBRARIES}) + +# Use the standard function to handle OPENEXR_FOUND +FIND_PACKAGE_HANDLE_STANDARD_ARGS (OpenEXR DEFAULT_MSG + OPENEXR_INCLUDE_DIR ${OpenEXR_libvars}) + +if (OPENEXR_FOUND) + set (OPENEXR_LIBRARIES "") + foreach (tmplib ${OpenEXR_libvars}) + list (APPEND OPENEXR_LIBRARIES ${${tmplib}}) + endforeach () + list (APPEND OPENEXR_LIBRARIES ${ZLIB_LIBRARIES}) + if (NOT OpenEXR_FIND_QUIETLY) + FIND_PACKAGE_MESSAGE (OPENEXR + "Found OpenEXR: ${OPENEXR_LIBRARIES}" + "[${OPENEXR_INCLUDE_DIR}][${OPENEXR_LIBRARIES}][${OPENEXR_CURRENT_STATE}]" + ) + endif () +endif () + +# Restore the original find library ordering +if( OPENEXR_USE_STATIC_LIBS ) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${_openexr_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) +endif() + +# Unset the helper variables to avoid pollution +unset (OPENEXR_CURRENT_STATE) +unset (OpenEXR_include_paths) +unset (OpenEXR_library_paths) +unset (OpenEXR_generic_include_paths) +unset (OpenEXR_generic_library_paths) +unset (OpenEXR_libvars) +unset (OpenEXR_cachevars) diff --git a/build_files/build_environment/patches/cmake/modules/FindTBB.cmake b/build_files/build_environment/patches/cmake/modules/FindTBB.cmake new file mode 100644 index 00000000000..8a821f8092e --- /dev/null +++ b/build_files/build_environment/patches/cmake/modules/FindTBB.cmake @@ -0,0 +1,73 @@ +# - Find TBB library +# Find the native TBB includes and library +# This module defines +# TBB_INCLUDE_DIRS, where to find tbb.h, Set when +# TBB is found. +# TBB_LIBRARIES, libraries to link against to use TBB. +# TBB_ROOT_DIR, The base directory to search for TBB. +# This can also be an environment variable. +# TBB_FOUND, If false, do not try to use TBB. +# +# also defined, but not for general use are +# TBB_LIBRARY, where to find the TBB library. + +#============================================================================= +# Copyright 2016 Blender Foundation. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= + +# If TBB_ROOT_DIR was defined in the environment, use it. +IF(NOT TBB_ROOT_DIR AND NOT $ENV{TBB_ROOT_DIR} STREQUAL "") + SET(TBB_ROOT_DIR $ENV{TBB_ROOT_DIR}) +ENDIF() + +SET(_tbb_SEARCH_DIRS + ${TBB_ROOT_DIR} + /usr/local + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt/lib/tbb +) + +FIND_PATH(TBB_INCLUDE_DIR + NAMES + tbb/tbb.h + HINTS + ${_tbb_SEARCH_DIRS} + PATH_SUFFIXES + include +) + +FIND_LIBRARY(TBB_LIBRARY + NAMES + tbb + HINTS + ${_tbb_SEARCH_DIRS} + PATH_SUFFIXES + lib64 lib + ) + +# handle the QUIETLY and REQUIRED arguments and set TBB_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(TBB DEFAULT_MSG + TBB_LIBRARY TBB_INCLUDE_DIR) + +IF(TBB_FOUND) + SET(TBB_LIBRARIES ${TBB_LIBRARY}) + SET(TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR}) +ELSE() + SET(TBB_TBB_FOUND FALSE) +ENDIF() + +MARK_AS_ADVANCED( + TBB_INCLUDE_DIR + TBB_LIBRARY +) diff --git a/build_files/build_environment/patches/cmake/modules/SelectLibraryConfigurations.cmake b/build_files/build_environment/patches/cmake/modules/SelectLibraryConfigurations.cmake new file mode 100644 index 00000000000..51b4dda0653 --- /dev/null +++ b/build_files/build_environment/patches/cmake/modules/SelectLibraryConfigurations.cmake @@ -0,0 +1,82 @@ +# select_library_configurations( basename ) +# +# This macro takes a library base name as an argument, and will choose good +# values for basename_LIBRARY, basename_LIBRARIES, basename_LIBRARY_DEBUG, and +# basename_LIBRARY_RELEASE depending on what has been found and set. If only +# basename_LIBRARY_RELEASE is defined, basename_LIBRARY, basename_LIBRARY_DEBUG, +# and basename_LIBRARY_RELEASE will be set to the release value. If only +# basename_LIBRARY_DEBUG is defined, then basename_LIBRARY, +# basename_LIBRARY_DEBUG and basename_LIBRARY_RELEASE will take the debug value. +# +# If the generator supports configuration types, then basename_LIBRARY and +# basename_LIBRARIES will be set with debug and optimized flags specifying the +# library to be used for the given configuration. If no build type has been set +# or the generator in use does not support configuration types, then +# basename_LIBRARY and basename_LIBRARIES will take only the release values. + +#============================================================================= +# Copyright 2009 Kitware, Inc. +# Copyright 2009 Will Dicharry <wdicharry@stellarscience.com> +# Copyright 2005-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# This macro was adapted from the FindQt4 CMake module and is maintained by Will +# Dicharry <wdicharry@stellarscience.com>. + +# Utility macro to check if one variable exists while another doesn't, and set +# one that doesn't exist to the one that exists. +macro( _set_library_name basename GOOD BAD ) + if( ${basename}_LIBRARY_${GOOD} AND NOT ${basename}_LIBRARY_${BAD} ) + set( ${basename}_LIBRARY_${BAD} ${${basename}_LIBRARY_${GOOD}} ) + set( ${basename}_LIBRARY ${${basename}_LIBRARY_${GOOD}} ) + set( ${basename}_LIBRARIES ${${basename}_LIBRARY_${GOOD}} ) + endif( ${basename}_LIBRARY_${GOOD} AND NOT ${basename}_LIBRARY_${BAD} ) +endmacro( _set_library_name ) + +macro( select_library_configurations basename ) + # if only the release version was found, set the debug to be the release + # version. + _set_library_name( ${basename} RELEASE DEBUG ) + # if only the debug version was found, set the release value to be the + # debug value. + _set_library_name( ${basename} DEBUG RELEASE ) + if (${basename}_LIBRARY_DEBUG AND ${basename}_LIBRARY_RELEASE ) + # if the generator supports configuration types or CMAKE_BUILD_TYPE + # is set, then set optimized and debug options. + if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE ) + set( ${basename}_LIBRARY + optimized ${${basename}_LIBRARY_RELEASE} + debug ${${basename}_LIBRARY_DEBUG} ) + set( ${basename}_LIBRARIES + optimized ${${basename}_LIBRARY_RELEASE} + debug ${${basename}_LIBRARY_DEBUG} ) + else( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE ) + # If there are no configuration types or build type, just use + # the release version + set( ${basename}_LIBRARY ${${basename}_LIBRARY_RELEASE} ) + set( ${basename}_LIBRARIES ${${basename}_LIBRARY_RELEASE} ) + endif( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE ) + endif( ${basename}_LIBRARY_DEBUG AND ${basename}_LIBRARY_RELEASE ) + + set( ${basename}_LIBRARY ${${basename}_LIBRARY} CACHE FILEPATH + "The ${basename} library" ) + + if( ${basename}_LIBRARY ) + set( ${basename}_FOUND TRUE ) + endif( ${basename}_LIBRARY ) + + mark_as_advanced( ${basename}_LIBRARY + ${basename}_LIBRARY_RELEASE + ${basename}_LIBRARY_DEBUG + ) +endmacro( select_library_configurations ) + diff --git a/build_files/build_environment/patches/cmakelists_glew.txt b/build_files/build_environment/patches/cmakelists_glew.txt new file mode 100644 index 00000000000..ec36d4bde63 --- /dev/null +++ b/build_files/build_environment/patches/cmakelists_glew.txt @@ -0,0 +1,2 @@ +cmake_minimum_required (VERSION 2.4) +add_subdirectory(build/cmake)
\ No newline at end of file diff --git a/build_files/build_environment/patches/cmakelists_hidapi.txt b/build_files/build_environment/patches/cmakelists_hidapi.txt new file mode 100644 index 00000000000..239b9d88b16 --- /dev/null +++ b/build_files/build_environment/patches/cmakelists_hidapi.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 2.8) +project(hidapi) + +set(SRC_FILES + windows/hid.c +) + +set(HEADER_FILES + hidapi/hidapi.h +) +include_directories(hidapi) +add_definitions(-DHID_API_STATIC) +add_library(hidapi STATIC ${SRC_FILES} ${HEADER_FILES}) + +install(TARGETS hidapi DESTINATION lib) + +INSTALL(FILES hidapi/hidapi.h + DESTINATION "include" + ) + diff --git a/build_files/build_environment/patches/cmakelists_openvdb.txt b/build_files/build_environment/patches/cmakelists_openvdb.txt new file mode 100644 index 00000000000..dd3e9c1a887 --- /dev/null +++ b/build_files/build_environment/patches/cmakelists_openvdb.txt @@ -0,0 +1,398 @@ +# -------------------------------------------------------------------------------- + +cmake_minimum_required(VERSION 2.8) + +# -------------------------------------------------------------------------------- + +project(OpenVDB) + +# -------------------------------------------------------------------------------- + +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules") + +# -------------------------------------------------------------------------------- + +set(CMAKE_BUILD_TYPE_INIT "Release") + +# -------------------------------------------------------------------------------- +# Options + +option(WITH_BLOSC "Enable Blosc support for compression" OFF) +option(WITH_LOGC4PLUS "Enable logging" OFF) +option(WITH_OPENVDB_2_ABI "Enable building the library to be compability with the OpenVDB 2 ABI" OFF) +option(WITH_PRINTER "Enable building the OpenVDB print executable" OFF) +option(WITH_PYTHON "Enable building the OpenVDB python API" OFF) +option(WITH_RENDERER "Enable building the OpenVDB render executable" OFF) +option(WITH_UNITTEST "Enable building the unit tests" OFF) +option(WITH_VIEWER "Enable building the OpenVDB viewer executable" OFF) + +# -------------------------------------------------------------------------------- +# Find packages +#set(BOOST_LIBRARIES boost_iostreams boost_system boost_thread) + +find_package(IlmBase) +find_package(OpenEXR) +find_package(TBB) +find_package(Boost) + +if(WITH_BLOSC) + find_package(Blosc) + + if(NOT BLOSC_FOUND) + set(WITH_BLOSC OFF) + endif() +endif() + +# todo +if(WITH_VIEWER) + set(GLFW_INCLUDE_DIRS ${GLFW_INCLUDE_PATH}) + set(GLFW_LIBRARY_DIRS ${GLFW_LIBRARY_PATH}) +endif() + +if(WITH_LOGC4PLUS) + find_package(LogC4Plus) + + if(NOT LOGC4PLUS_FOUND) + set(WITH_LOGC4PLUS OFF) + endif() +endif() + +# todo +if(WITH_PYTHON) + set(PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_PATH}) + set(PYTHON_LIBRARY_DIRS ${PYTHON_LIBRARY_PATH}) +endif() + +if(WITH_UNITTEST) + find_package(CppUnit) + + if(NOT CPPUNIT_FOUND) + set(WITH_UNITTEST OFF) + endif() +endif() + +# -------------------------------------------------------------------------------- + +message (STATUS "BOOST_ROOT ${BOOST_ROOT}") +message (STATUS "Boost found ${Boost_FOUND} ") +message (STATUS "Boost version ${Boost_VERSION}") +message (STATUS "Boost include dirs ${Boost_INCLUDE_DIRS}") +message (STATUS "Boost library dirs ${Boost_LIBRARY_DIRS}") +message (STATUS "Boost libraries ${Boost_LIBRARIES}") + +message (STATUS "ILMBase found ${ILMBASE_FOUND} ") +message (STATUS "ILMBase include dir ${ILMBASE_INCLUDE_DIR}") +message (STATUS "ILMBase libraries ${ILMBASE_LIBRARIES}") + +message (STATUS "TBB found ${TBB_FOUND} ") +message (STATUS "TBB include dir ${TBB_INCLUDE_DIR}") +message (STATUS "TBB libraries ${TBB_LIBRARIES}") + +if(MSVC) + set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj" ) + set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /bigobj" ) +endif() + +set(OPENVDB_LIBRARIES ${BLOSC_LIBRARIES} ${BOOST_LIBRARIES} ${OPENEXR_LIBRARIES} ${ILMBASE_LIBRARIES} ${TBB_LIBRARIES} ${ZLIB_LIBRARY} ) + +include_directories(. ${CMAKE_CURRENT_SOURCE_DIR}/../ ${Boost_INCLUDE_DIRS} ${ILMBASE_INCLUDE_DIR} ${OPENEXR_INCLUDE_DIR} ${TBB_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR}) +link_directories(${Boost_LIBRARY_DIRS} ${OPENEXR_LIBRARY_DIRS} ${TBB_INCLUDE_DIRS}) +add_definitions(-DNOMINMAX -D__TBB_NO_IMPLICIT_LINKAGE -DOPENVDB_STATICLIB -DOPENVDB_OPENEXR_STATICLIB) + +if(WITH_BLOSC) + add_definitions(-DOPENVDB_USE_BLOSC) + include_directories(${BLOSC_INCLUDE_DIRS}) + link_directories(${BLOSC_LIBRARY_DIRS}) +endif() + +if(WITH_LOGC4PLUS) + add_definitions(-DOPENVDB_USE_LOG4CPLUS) + include_directories(${LOG4CPLUS_INCLUDE_DIRS}) + link_directories(${LOG4CPLUS_LIBRARY_DIRS}) +endif() + +if(WITH_OPENVDB_2_ABI) + add_definitions(-DOPENVDB_2_ABI_COMPATIBLE) +endif() + +# todo +if(WITH_OPENVDB_USE_GLFW_3) + add_definitions(-DOPENVDB_USE_GLFW_3) +endif() + +if(WITH_UNITTEST) + include_directories(${CPPUNIT_INCLUDE_DIRS}) + link_directories(${CPPUNIT_LIBRARY_DIRS}) +endif() + +# -------------------------------------------------------------------------------- + +set(SRC_FILES + openvdb/openvdb.cc + openvdb/io/Compression.cc + openvdb/io/File.cc + openvdb/io/Queue.cc + openvdb/io/Stream.cc + openvdb/io/TempFile.cc + openvdb/io/GridDescriptor.cc + openvdb/io/Archive.cc + openvdb/metadata/MetaMap.cc + openvdb/metadata/Metadata.cc + openvdb/math/Maps.cc + openvdb/math/Transform.cc + openvdb/math/QuantizedUnitVec.cc + openvdb/math/Proximity.cc + openvdb/Grid.cc + openvdb/util/Formats.cc + openvdb/util/Util.cc +) + +set(HEADER_FILES + openvdb/openvdb.h + openvdb/version.h + openvdb/PlatformConfig.h + openvdb/Metadata.h + openvdb/Exceptions.h + openvdb/Grid.h + openvdb/Types.h + openvdb/Platform.h + openvdb/tree/ValueAccessor.h + openvdb/tree/NodeUnion.h + openvdb/tree/Tree.h + openvdb/tree/Iterator.h + openvdb/tree/LeafNodeBool.h + openvdb/tree/TreeIterator.h + openvdb/tree/LeafNode.h + openvdb/tree/NodeManager.h + openvdb/tree/LeafManager.h + openvdb/tree/InternalNode.h + openvdb/tree/RootNode.h + openvdb/tools/PointScatter.h + openvdb/tools/VolumeAdvect.h + openvdb/tools/LevelSetTracker.h + openvdb/tools/Composite.h + openvdb/tools/Morphology.h + openvdb/tools/ValueTransformer.h + openvdb/tools/ChangeBackground.h + openvdb/tools/GridTransformer.h + openvdb/tools/Prune.h + openvdb/tools/LevelSetUtil.h + openvdb/tools/VolumeToSpheres.h + openvdb/tools/LevelSetAdvect.h + openvdb/tools/Statistics.h + openvdb/tools/LevelSetMeasure.h + openvdb/tools/VectorTransformer.h + openvdb/tools/RayIntersector.h + openvdb/tools/PointPartitioner.h + openvdb/tools/Interpolation.h + openvdb/tools/VelocityFields.h + openvdb/tools/PointIndexGrid.h + openvdb/tools/LevelSetRebuild.h + openvdb/tools/Clip.h + openvdb/tools/SignedFloodFill.h + openvdb/tools/MeshToVolume.h + openvdb/tools/Dense.h + openvdb/tools/Filter.h + openvdb/tools/RayTracer.h + openvdb/tools/Diagnostics.h + openvdb/tools/VolumeToMesh.h + openvdb/tools/PoissonSolver.h + openvdb/tools/LevelSetFracture.h + openvdb/tools/GridOperators.h + openvdb/tools/DenseSparseTools.h + openvdb/tools/ParticlesToLevelSet.h + openvdb/tools/LevelSetSphere.h + openvdb/tools/LevelSetMorph.h + openvdb/tools/LevelSetFilter.h + openvdb/tools/PointAdvect.h + openvdb/io/Queue.h + openvdb/io/TempFile.h + openvdb/io/Stream.h + openvdb/io/GridDescriptor.h + openvdb/io/Archive.h + openvdb/io/io.h + openvdb/io/Compression.h + openvdb/io/File.h + openvdb/metadata/StringMetadata.h + openvdb/metadata/MetaMap.h + openvdb/metadata/Metadata.h + openvdb/math/DDA.h + openvdb/math/Vec2.h + openvdb/math/FiniteDifference.h + openvdb/math/Stencils.h + openvdb/math/BBox.h + openvdb/math/Mat3.h + openvdb/math/Mat.h + openvdb/math/Proximity.h + openvdb/math/Ray.h + openvdb/math/ConjGradient.h + openvdb/math/Quat.h + openvdb/math/Vec3.h + openvdb/math/Vec4.h + openvdb/math/QuantizedUnitVec.h + openvdb/math/Coord.h + openvdb/math/Operators.h + openvdb/math/Stats.h + openvdb/math/Math.h + openvdb/math/Tuple.h + openvdb/math/LegacyFrustum.h + openvdb/math/Mat4.h + openvdb/math/Maps.h + openvdb/math/Transform.h + openvdb/util/PagedArray.h + openvdb/util/CpuTimer.h + openvdb/util/Formats.h + openvdb/util/NullInterrupter.h + openvdb/util/Util.h + openvdb/util/Name.h + openvdb/util/MapsUtil.h + openvdb/util/NodeMasks.h + openvdb/util/logging.h +) + +add_library(openvdb STATIC ${SRC_FILES} ${HEADER_FILES}) + +# -------------------------------------------------------------------------------- + +target_link_libraries(openvdb ${OPENVDB_LIBRARIES}) + +set(OPENVDB_VERSION_MAJOR 3) +set(OPENVDB_VERSION_MINOR 1) +set(OPENVDB_VERSION_PATCH 0) +set(OPENVDB_VERSION_STRING ${OPENVDB_VERSION_MAJOR}.${OPENVDB_VERSION_MINOR}.${OPENVDB_VERSION_PATCH}) + +set_target_properties(openvdb PROPERTIES VERSION ${OPENVDB_VERSION_STRING} SOVERSION ${OPENVDB_VERSION_MAJOR}) + +install(TARGETS openvdb DESTINATION lib) + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DESTINATION include COMPONENT Development FILES_MATCHING PATTERN "*.h" + PATTERN ".git" EXCLUDE PATTERN "build" EXCLUDE PATTERN "cmake" EXCLUDE) + +# -------------------------------------------------------------------------------- + +if(WITH_PRINTER) + set(PRINT_SRC + openvdb/cmd/openvdb_print/main.cc + ) + + add_executable(vdb_print ${PRINT_SRC}) + target_link_libraries(vdb_print openvdb) + install(TARGETS vdb_print RUNTIME DESTINATION bin) +endif() + +if(WITH_RENDER) + set(RENDER_SRC + openvdb/cmd/openvdb_render/main.cc + ) + + add_executable(vdb_render ${RENDER_SRC}) + target_link_libraries(vdb_render openvdb) + install(TARGETS vdb_render RUNTIME DESTINATION bin) +endif() + +# todo +if(WITH_VIEWER) + set(VIEWER_SRC + openvdb/viewer/Camera.cc + openvdb/viewer/ClipBox.cc + openvdb/viewer/Font.cc + openvdb/viewer/RenderModules.cc + openvdb/viewer/Viewer.cc + + openvdb/viewer/Camera.h + openvdb/viewer/ClipBox.h + openvdb/viewer/Font.h + openvdb/viewer/RenderModules.h + openvdb/viewer/Viewer.h + openvdb/cmd/openvdb_viewer/main.cc + ) + + include_directories(${GLFW_INCLUDE_DIRS}) + link_directories(${GLFW_LIBRARY_DIRS}) + + add_executable(vdb_viewer ${VIEWER_SRC}) + target_link_libraries(vdb_viewer openvdb) + install(TARGETS vdb_viewer RUNTIME DESTINATION bin) +endif() + +# todo +if(WITH_PYTHON) +# add_library(pyopenvdb SHARED ) +endif() + +set(UNITTEST_SRC + openvdb/unittest/main.cc + openvdb/unittest/TestBBox.cc + openvdb/unittest/TestConjGradient.cc + openvdb/unittest/TestCoord.cc + openvdb/unittest/TestCpt.cc + openvdb/unittest/TestCurl.cc + openvdb/unittest/TestDense.cc + openvdb/unittest/TestDenseSparseTools.cc + openvdb/unittest/TestDiagnostics.cc + openvdb/unittest/TestDivergence.cc + openvdb/unittest/TestDoubleMetadata.cc + openvdb/unittest/TestExceptions.cc + openvdb/unittest/TestFile.cc + openvdb/unittest/TestFloatMetadata.cc + openvdb/unittest/TestGradient.cc + openvdb/unittest/TestGrid.cc + openvdb/unittest/TestGridBbox.cc + openvdb/unittest/TestGridDescriptor.cc + openvdb/unittest/TestGridIO.cc + openvdb/unittest/TestGridTransformer.cc + openvdb/unittest/TestInit.cc + openvdb/unittest/TestInt32Metadata.cc + openvdb/unittest/TestInt64Metadata.cc + openvdb/unittest/TestInternalOrigin.cc + openvdb/unittest/TestLaplacian.cc + openvdb/unittest/TestLeaf.cc + openvdb/unittest/TestLeafBool.cc + openvdb/unittest/TestLeafIO.cc + openvdb/unittest/TestLeafOrigin.cc + openvdb/unittest/TestLevelSetRayIntersector.cc + openvdb/unittest/TestLevelSetUtil.cc + openvdb/unittest/TestLinearInterp.cc + openvdb/unittest/TestMaps.cc + openvdb/unittest/TestMat4Metadata.cc + openvdb/unittest/TestMath.cc + openvdb/unittest/TestMeanCurvature.cc + openvdb/unittest/TestMeshToVolume.cc + openvdb/unittest/TestMetadata.cc + openvdb/unittest/TestMetadataIO.cc + openvdb/unittest/TestMetaMap.cc + openvdb/unittest/TestName.cc + openvdb/unittest/TestNodeIterator.cc + openvdb/unittest/TestNodeMask.cc + openvdb/unittest/TestParticlesToLevelSet.cc + openvdb/unittest/TestPointIndexGrid.cc + openvdb/unittest/TestPointPartitioner.cc + openvdb/unittest/TestPoissonSolver.cc + openvdb/unittest/TestPrePostAPI.cc + openvdb/unittest/TestQuadraticInterp.cc + openvdb/unittest/TestQuantizedUnitVec.cc + openvdb/unittest/TestQuat.cc + openvdb/unittest/TestRay.cc + openvdb/unittest/TestStats.cc + openvdb/unittest/TestStream.cc + openvdb/unittest/TestStringMetadata.cc + openvdb/unittest/TestTools.cc + openvdb/unittest/TestTransform.cc + openvdb/unittest/TestTree.cc + openvdb/unittest/TestTreeCombine.cc + openvdb/unittest/TestTreeGetSetValues.cc + openvdb/unittest/TestTreeIterators.cc + openvdb/unittest/TestTreeVisitor.cc + openvdb/unittest/TestUtil.cc + openvdb/unittest/TestValueAccessor.cc + openvdb/unittest/TestVec2Metadata.cc + openvdb/unittest/TestVec3Metadata.cc + openvdb/unittest/TestVolumeRayIntersector.cc + openvdb/unittest/TestVolumeToMesh.cc +) + +# todo +if(WITH_UNITTEST) + add_executable(test ${UNITTEST_SRC} ${HEADER_FILES}) + target_link_libraries(test openvdb ${CPPUNIT_LIBRARIES}) +endif() diff --git a/build_files/build_environment/patches/cmakelists_tbb.txt b/build_files/build_environment/patches/cmakelists_tbb.txt new file mode 100644 index 00000000000..1be9ca25f6a --- /dev/null +++ b/build_files/build_environment/patches/cmakelists_tbb.txt @@ -0,0 +1,196 @@ +cmake_minimum_required (VERSION 2.8) +project(tbb CXX) + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to 'Release' as none was specified.") + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" + "MinSizeRel" "RelWithDebInfo") +endif() + +include_directories(include src src/rml/include ) + +option(TBB_BUILD_SHARED "Build TBB shared library" ON) +option(TBB_BUILD_STATIC "Build TBB static library" ON) +option(TBB_BUILD_TBBMALLOC "Build TBB malloc library" ON) +option(TBB_BUILD_TBBMALLOC_PROXY "Build TBB malloc proxy library" ON) + +if(APPLE) + set(CMAKE_MACOSX_RPATH ON) +endif() + +file(GLOB tbb_src "${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/old/*.cpp") +list(APPEND tbb_src ${CMAKE_CURRENT_SOURCE_DIR}/src/rml/client/rml_tbb.cpp) +file(GLOB to_remove "${CMAKE_CURRENT_SOURCE_DIR}/src/old/test*.cpp") +list(REMOVE_ITEM tbb_src ${to_remove}) + +set(tbbmalloc_static_src + src/tbbmalloc/backend.cpp + src/tbbmalloc/large_objects.cpp + src/tbbmalloc/backref.cpp + src/tbbmalloc/tbbmalloc.cpp + src/tbbmalloc/frontend.cpp + src/tbb/itt_notify.cpp) + +set(tbbmalloc_src ${tbbmalloc_static_src}) + +set(tbbmalloc_proxy_src + src/tbbmalloc/proxy.cpp + src/tbbmalloc/tbb_function_replacement.cpp) + +if (NOT APPLE) + add_definitions(-DDO_ITT_NOTIFY) +else() + # Disable annoying "has no symbols" warnings + set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>") + set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>") + set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>") + set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>") +endif() + +if (UNIX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -DUSE_PTHREAD") + if(NOT CMAKE_CXX_FLAGS MATCHES "-mno-rtm") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mrtm") + endif() + if (APPLE) + set(ARCH_PREFIX "mac") + else() + set(ARCH_PREFIX "lin") + endif() + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + set(ARCH_PREFIX "${ARCH_PREFIX}64") + else() + set(ARCH_PREFIX "${ARCH_PREFIX}32") + endif() + set(ENABLE_RTTI "-frtti -fexceptions ") + set(DISABLE_RTTI "-fno-rtti -fno-exceptions ") +elseif(WIN32) + cmake_minimum_required (VERSION 3.1) + enable_language(ASM_MASM) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GS- /Zc:wchar_t /Zc:forScope /DUSE_WINTHREAD") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D_CRT_SECURE_NO_DEPRECATE /D_WIN32_WINNT=0x0600 /volatile:iso") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267 /wd4800 /wd4146 /wd4244 /wd4018") + + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + list(APPEND tbb_src src/tbb/intel64-masm/atomic_support.asm + src/tbb/intel64-masm/itsx.asm src/tbb/intel64-masm/intel64_misc.asm) + list(APPEND tbbmalloc_src src/tbb/intel64-masm/atomic_support.asm) + set(CMAKE_ASM_MASM_FLAGS "/DEM64T=1") + set(ARCH_PREFIX "win64") + else() + list(APPEND tbb_src src/tbb/ia32-masm/atomic_support.asm + src/tbb/ia32-masm/itsx.asm src/tbb/ia32-masm/lock_byte.asm) + list(APPEND tbbmalloc_src src/tbb/ia32-masm/atomic_support.asm) + set(ARCH_PREFIX "win32") + endif() + set(ENABLE_RTTI "/EHsc /GR ") + set(DISABLE_RTTI "/EHs- /GR- ") +endif() + +# Linker export definitions +if (WIN32) + add_custom_command(OUTPUT tbb.def + COMMAND ${CMAKE_CXX_COMPILER} /TC /EP ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include > tbb.def + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def + COMMENT "Preprocessing tbb.def" + ) + + add_custom_command(OUTPUT tbbmalloc.def + COMMAND ${CMAKE_CXX_COMPILER} /TC /EP ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include > tbbmalloc.def + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def + COMMENT "Preprocessing tbbmalloc.def" + ) +else() + add_custom_command(OUTPUT tbb.def + COMMAND ${CMAKE_CXX_COMPILER} -xc++ -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbb.def + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def + COMMENT "Preprocessing tbb.def" + ) + + add_custom_command(OUTPUT tbbmalloc.def + COMMAND ${CMAKE_CXX_COMPILER} -xc++ -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbbmalloc.def + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def + COMMENT "Preprocessing tbbmalloc.def" + ) +endif() + +add_custom_target(tbb_def_files DEPENDS tbb.def tbbmalloc.def) + +# TBB library +if (TBB_BUILD_STATIC) + add_library(tbb_static STATIC ${tbb_src}) + set_property(TARGET tbb_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_BUILD=1") + set_property(TARGET tbb_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_SOURCE_DIRECTLY_INCLUDED=1") + set_property(TARGET tbb_static APPEND_STRING PROPERTY COMPILE_FLAGS ${ENABLE_RTTI}) + install(TARGETS tbb_static ARCHIVE DESTINATION lib) +endif() + +if (TBB_BUILD_SHARED) + add_library(tbb SHARED ${tbb_src}) + set_property(TARGET tbb APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_BUILD=1") + set_property(TARGET tbb APPEND_STRING PROPERTY COMPILE_FLAGS ${ENABLE_RTTI}) + add_dependencies(tbb tbb_def_files) + if (APPLE) + set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/tbb.def") + elseif(UNIX) + set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,${CMAKE_CURRENT_BINARY_DIR}/tbb.def") + elseif(WIN32) + set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "/DEF:${CMAKE_CURRENT_BINARY_DIR}/tbb.def") + endif() + install(TARGETS tbb DESTINATION lib) +endif() + +if(CMAKE_COMPILER_IS_GNUCC) + # Quench a warning on GCC + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/governor.cpp COMPILE_FLAGS "-Wno-missing-field-initializers ") +elseif(MSVC) + # Quench a warning on MSVC + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/scheduler.cpp COMPILE_FLAGS "/wd4458 ") +endif() + +if(TBB_BUILD_TBBMALLOC) + # TBB malloc library + if (TBB_BUILD_STATIC) + add_library(tbbmalloc_static STATIC ${tbbmalloc_static_src}) + set_property(TARGET tbbmalloc_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1") + set_property(TARGET tbbmalloc_static APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI}) + install(TARGETS tbbmalloc_static ARCHIVE DESTINATION lib) + endif() + + if (TBB_BUILD_SHARED) + add_library(tbbmalloc SHARED ${tbbmalloc_src}) + set_property(TARGET tbbmalloc APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1") + set_property(TARGET tbbmalloc APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI}) + add_dependencies(tbbmalloc tbb_def_files) + if (APPLE) + set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def") + elseif(UNIX) + set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def") + elseif(WIN32) + set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "/DEF:${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def") + endif() + install(TARGETS tbbmalloc DESTINATION lib) + endif() +endif() + +if(TBB_BUILD_TBBMALLOC_PROXY) + # TBB malloc proxy library + if (TBB_BUILD_STATIC) + add_library(tbbmalloc_proxy_static STATIC ${tbbmalloc_proxy_src}) + set_property(TARGET tbbmalloc_proxy_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1") + set_property(TARGET tbbmalloc_proxy_static APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI}) + link_libraries(tbbmalloc_proxy_static tbbmalloc) + install(TARGETS tbbmalloc_proxy_static ARCHIVE DESTINATION lib) + endif() + + if (TBB_BUILD_SHARED) + add_library(tbbmalloc_proxy SHARED ${tbbmalloc_proxy_src}) + set_property(TARGET tbbmalloc_proxy APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1") + set_property(TARGET tbbmalloc_proxy APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI}) + link_libraries(tbbmalloc_proxy tbbmalloc) + install(TARGETS tbbmalloc_proxy DESTINATION lib) + endif() +endif() + +install(DIRECTORY include/tbb DESTINATION include) diff --git a/build_files/build_environment/patches/cuew.diff b/build_files/build_environment/patches/cuew.diff new file mode 100644 index 00000000000..0363034cd93 --- /dev/null +++ b/build_files/build_environment/patches/cuew.diff @@ -0,0 +1,26 @@ +--- CmakeLists.txt.orig 2015-12-31 03:46:41 -0700 ++++ CMakeLists.txt 2016-04-01 13:28:33 -0600 +@@ -22,3 +22,10 @@ + + add_executable(testcuew cuewTest/cuewTest.c include/cuew.h) + target_link_libraries(testcuew cuew ${CMAKE_DL_LIBS}) ++ ++install(TARGETS cuew ++ LIBRARY DESTINATION lib COMPONENT libraries ++ ARCHIVE DESTINATION lib/static COMPONENT libraries) ++ ++INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/cuew.h ++ DESTINATION include/) +\ No newline at end of file +--- src/cuew.c 2016-04-01 13:41:43 -0600 ++++ src/cuew.c 2016-04-01 13:41:11 -0600 +@@ -15,7 +15,9 @@ + */ + + #ifdef _MSC_VER ++#if _MSC_VER < 1900 + # define snprintf _snprintf ++#endif + # define popen _popen + # define pclose _pclose + # define _CRT_SECURE_NO_WARNINGS diff --git a/build_files/build_environment/patches/distutildebugflags.diff b/build_files/build_environment/patches/distutildebugflags.diff new file mode 100644 index 00000000000..3d6b688bc53 --- /dev/null +++ b/build_files/build_environment/patches/distutildebugflags.diff @@ -0,0 +1,11 @@ +--- _msvccompiler.py.orig 2017-01-17 00:57:48 -0700 ++++ _msvccompiler.py 2017-05-20 09:47:26 -0600 +@@ -237,7 +237,7 @@ + ldflags.extend(('/nodefaultlib:libucrt.lib', 'ucrt.lib')) + + ldflags_debug = [ +- '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL' ++ '/nologo', '/INCREMENTAL:NO', '/LTCG' + ] + + self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1'] diff --git a/build_files/build_environment/patches/ffmpeg.diff b/build_files/build_environment/patches/ffmpeg.diff new file mode 100644 index 00000000000..75fc6490031 --- /dev/null +++ b/build_files/build_environment/patches/ffmpeg.diff @@ -0,0 +1,32 @@ +--- libavutil/common.h 2016-02-14 19:29:42 -0700 ++++ libavutil/common.h 2016-03-30 09:50:29 -0600 +@@ -99,6 +99,11 @@ + #define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) + #define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) + ++//msvc helper ++#ifdef _MSC_VER ++#define inline __inline ++#endif ++ + /* misc math functions */ + + #ifdef HAVE_AV_CONFIG_H +--- configure 2016-11-26 03:12:05.000000000 +0100 ++++ configure 2017-04-05 03:24:35.000000000 +0200 +@@ -1899,7 +1899,6 @@ + access + aligned_malloc + arc4random +- clock_gettime + closesocket + CommandLineToArgvW + CoTaskMemFree +@@ -5494,7 +5493,6 @@ + + check_func access + check_func_headers stdlib.h arc4random +-check_func_headers time.h clock_gettime || { check_func_headers time.h clock_gettime -lrt && add_extralibs -lrt && LIBRT="-lrt"; } + check_func fcntl + check_func fork + check_func gethrtime diff --git a/build_files/build_environment/patches/fftw3.diff b/build_files/build_environment/patches/fftw3.diff new file mode 100644 index 00000000000..48d88414045 --- /dev/null +++ b/build_files/build_environment/patches/fftw3.diff @@ -0,0 +1,25 @@ +--- config.h.in 2014-03-04 11:44:58 -0700 ++++ config.h.in 2016-03-30 11:42:49 -0600 +@@ -142,9 +142,6 @@ + /* Define to 1 if you have the `gethrtime' function. */ + #undef HAVE_GETHRTIME + +-/* Define to 1 if you have the `gettimeofday' function. */ +-#undef HAVE_GETTIMEOFDAY +- + /* Define to 1 if hrtime_t is defined in <sys/time.h> */ + #undef HAVE_HRTIME_T + +--- kernel/assert.c 2014-03-04 11:41:03 -0700 ++++ kernel/assert.c 2016-04-01 09:41:05 -0600 +@@ -24,8 +24,10 @@ + + void X(assertion_failed)(const char *s, int line, const char *file) + { ++#if 0 + fflush(stdout); + fprintf(stderr, "fftw: %s:%d: assertion failed: %s\n", file, line, s); ++#endif + #ifdef HAVE_ABORT + abort(); + #else diff --git a/build_files/build_environment/patches/hdf5.diff b/build_files/build_environment/patches/hdf5.diff new file mode 100644 index 00000000000..cb84625810d --- /dev/null +++ b/build_files/build_environment/patches/hdf5.diff @@ -0,0 +1,11 @@ +--- UserMacros.cmake ++++ UserMacros.cmake +@@ -16,6 +16,8 @@ + if (BUILD_USER_DEFINED_LIBS) + MACRO_USER_DEFINED_LIBS () + endif (BUILD_USER_DEFINED_LIBS) ++ ++include(Config/cmake/usermacros/windows_mt.cmake) + #----------------------------------------------------------------------------- + #------------------- E X A M P L E E N D ----------------------------------- + #----------------------------------------------------------------------------- diff --git a/build_files/build_environment/patches/hidapi.diff b/build_files/build_environment/patches/hidapi.diff new file mode 100644 index 00000000000..720a8ae5ae9 --- /dev/null +++ b/build_files/build_environment/patches/hidapi.diff @@ -0,0 +1,15 @@ +--- hidapi/hidapi.h 2011-10-25 20:58:16 -0600 ++++ hidapi/hidapi.h 2016-11-01 12:05:58 -0600 +@@ -30,7 +30,11 @@ + #include <wchar.h> + + #ifdef _WIN32 +- #define HID_API_EXPORT __declspec(dllexport) ++ #ifdef HID_API_STATIC ++ #define HID_API_EXPORT ++ #else ++ #define HID_API_EXPORT __declspec(dllexport) ++ #endif + #define HID_API_CALL + #else + #define HID_API_EXPORT /**< API export macro */ diff --git a/build_files/build_environment/install_deps_patches/llvm.patch b/build_files/build_environment/patches/install_deps_llvm.diff index 968f011e57c..968f011e57c 100644 --- a/build_files/build_environment/install_deps_patches/llvm.patch +++ b/build_files/build_environment/patches/install_deps_llvm.diff diff --git a/build_files/build_environment/install_deps_patches/osl.patch b/build_files/build_environment/patches/install_deps_osl.diff index 3b52403f740..3b52403f740 100644 --- a/build_files/build_environment/install_deps_patches/osl.patch +++ b/build_files/build_environment/patches/install_deps_osl.diff diff --git a/build_files/build_environment/patches/libfaad.diff b/build_files/build_environment/patches/libfaad.diff new file mode 100644 index 00000000000..37605b29cd9 --- /dev/null +++ b/build_files/build_environment/patches/libfaad.diff @@ -0,0 +1,10 @@ +--- frontend/main.c 2008-09-22 11:55:09 -0600 ++++ frontend/main.c 2016-04-06 15:20:36 -0600 +@@ -31,7 +31,6 @@ + #ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include <windows.h> +-#define off_t __int64 + #else + #include <time.h> + #endif diff --git a/build_files/build_environment/patches/llvm-alloca-fix.diff b/build_files/build_environment/patches/llvm-alloca-fix.diff new file mode 100644 index 00000000000..5394a472167 --- /dev/null +++ b/build_files/build_environment/patches/llvm-alloca-fix.diff @@ -0,0 +1,111 @@ +Index: lib/Target/X86/X86ISelLowering.cpp +=================================================================== +--- lib/Target/X86/X86ISelLowering.cpp 2014-04-11 23:04:44.000000000 +0200 ++++ lib/Target/X86/X86ISelLowering.cpp (working copy) +@@ -15493,12 +15493,36 @@ + // non-trivial part is impdef of ESP. + + if (Subtarget->isTargetWin64()) { ++ const char *StackProbeSymbol = ++ Subtarget->isTargetCygMing() ? "___chkstk" : "__chkstk"; ++ ++ MachineInstrBuilder MIB; ++ ++ if (getTargetMachine().getCodeModel() == CodeModel::Large) { ++ // For large code model we need to do indirect call to __chkstk. ++ ++ // R11 will be used to contain the address of __chkstk. ++ // R11 is a volotiale register and assumed to be destoyed by the callee, ++ // so there is no need to save and restore it. ++ BuildMI(*BB, MI, DL, TII->get(X86::MOV64ri), X86::R11) ++ .addExternalSymbol(StackProbeSymbol); ++ // Create a call to __chkstk function which address contained in R11. ++ MIB = BuildMI(*BB, MI, DL, TII->get(X86::CALL64r)) ++ .addReg(X86::R11, RegState::Kill); ++ ++ } else { ++ ++ // For non-large code model we can do direct call to __chkstk. ++ ++ MIB = BuildMI(*BB, MI, DL, TII->get(X86::W64ALLOCA)) ++ .addExternalSymbol(StackProbeSymbol); ++ } ++ + if (Subtarget->isTargetCygMing()) { + // ___chkstk(Mingw64): + // Clobbers R10, R11, RAX and EFLAGS. + // Updates RSP. +- BuildMI(*BB, MI, DL, TII->get(X86::W64ALLOCA)) +- .addExternalSymbol("___chkstk") ++ MIB + .addReg(X86::RAX, RegState::Implicit) + .addReg(X86::RSP, RegState::Implicit) + .addReg(X86::RAX, RegState::Define | RegState::Implicit) +@@ -15507,8 +15531,7 @@ + } else { + // __chkstk(MSVCRT): does not update stack pointer. + // Clobbers R10, R11 and EFLAGS. +- BuildMI(*BB, MI, DL, TII->get(X86::W64ALLOCA)) +- .addExternalSymbol("__chkstk") ++ MIB + .addReg(X86::RAX, RegState::Implicit) + .addReg(X86::EFLAGS, RegState::Define | RegState::Implicit); + // RAX has the offset to be subtracted from RSP. +Index: lib/Target/X86/X86FrameLowering.cpp +=================================================================== +--- lib/Target/X86/X86FrameLowering.cpp 2013-10-24 01:37:01.000000000 +0200 ++++ lib/Target/X86/X86FrameLowering.cpp (working copy) +@@ -635,25 +635,49 @@ + .addReg(X86::EAX, RegState::Kill) + .setMIFlag(MachineInstr::FrameSetup); + } ++ ++ MachineInstrBuilder MIB; + + if (Is64Bit) { ++ + // Handle the 64-bit Windows ABI case where we need to call __chkstk. + // Function prologue is responsible for adjusting the stack pointer. + BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64ri), X86::RAX) + .addImm(NumBytes) + .setMIFlag(MachineInstr::FrameSetup); ++ ++ if (TM.getCodeModel() == CodeModel::Large) { ++ // For large code model we need to do indirect call to __chkstk. ++ ++ ++ // R11 will be used to contain the address of __chkstk. ++ // R11 is a volotiale register and assumed to be destoyed by the callee, ++ // so there is no need to save and restore it. ++ BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64ri), X86::R11) ++ .addExternalSymbol(StackProbeSymbol); ++ // Create a call to __chkstk function which address contained in R11. ++ MIB = BuildMI(MBB, MBBI, DL, TII.get(X86::CALL64r)) ++ .addReg(X86::R11, RegState::Kill); ++ } else { ++ ++ // For non-large code model we can do direct call to __chkstk. ++ ++ MIB = BuildMI(MBB, MBBI, DL, TII.get(X86::W64ALLOCA)) ++ .addExternalSymbol(StackProbeSymbol); ++ } + } else { + // Allocate NumBytes-4 bytes on stack in case of isEAXAlive. + // We'll also use 4 already allocated bytes for EAX. + BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32ri), X86::EAX) + .addImm(isEAXAlive ? NumBytes - 4 : NumBytes) + .setMIFlag(MachineInstr::FrameSetup); ++ ++ MIB = BuildMI(MBB, MBBI, DL, TII.get(X86::CALLpcrel32)) ++ .addExternalSymbol(StackProbeSymbol); + } + +- BuildMI(MBB, MBBI, DL, +- TII.get(Is64Bit ? X86::W64ALLOCA : X86::CALLpcrel32)) +- .addExternalSymbol(StackProbeSymbol) +- .addReg(StackPtr, RegState::Define | RegState::Implicit) ++ ++ MIB.addReg(StackPtr, RegState::Define | RegState::Implicit) + .addReg(X86::EFLAGS, RegState::Define | RegState::Implicit) + .setMIFlag(MachineInstr::FrameSetup); + diff --git a/build_files/build_environment/patches/ming32sh.cmd b/build_files/build_environment/patches/ming32sh.cmd new file mode 100644 index 00000000000..3259d9d3714 --- /dev/null +++ b/build_files/build_environment/patches/ming32sh.cmd @@ -0,0 +1,7 @@ +@title MinGW-w64 32-bit GCC build environment + +@echo Setting up environment for MinGW-w64 GCC 32-bit... + +@set PATH=%CD%\bin;%CD%\msys\1.0\bin;%cd%\..\..\perl32\site\bin;%cd%\..\..\perl32\bin;%cd%\..\..\c\bin;%PATH% + + diff --git a/build_files/build_environment/patches/ming64sh.cmd b/build_files/build_environment/patches/ming64sh.cmd new file mode 100644 index 00000000000..18fea3829f3 --- /dev/null +++ b/build_files/build_environment/patches/ming64sh.cmd @@ -0,0 +1,7 @@ +@title MinGW-w64 64-bit GCC build environment + +@echo Setting up environment for MinGW-w64 GCC 64-bit... + +@set PATH=%CD%\bin;%CD%\msys\1.0\bin;%cd%\..\..\perl\site\bin;%cd%\..\..\perl\bin;%cd%\..\..\c\bin;%PATH% + + diff --git a/build_files/build_environment/patches/numpy.diff b/build_files/build_environment/patches/numpy.diff new file mode 100644 index 00000000000..c4c57222838 --- /dev/null +++ b/build_files/build_environment/patches/numpy.diff @@ -0,0 +1,23 @@ +diff -Naur numpy-1.11.1/numpy/distutils/ccompiler.py numpy-1.11.1/numpy/distutils/ccompiler.py +--- numpy-1.11.1/numpy/distutils/ccompiler.py 2016-06-25 08:38:34 -0600 ++++ numpy-1.11.1/numpy/distutils/ccompiler.py 2016-08-04 12:33:43 -0600 +@@ -29,6 +29,7 @@ + + # Using customized CCompiler.spawn. + def CCompiler_spawn(self, cmd, display=None): ++ cmd = quote_args(cmd) + """ + Execute a command in a sub-process. + +diff -Naur numpy-1.11.1/numpy/distutils/misc_util.py numpy-1.11.1/numpy/distutils/misc_util.py +--- numpy-1.11.1/numpy/distutils/misc_util.py 2016-06-25 08:38:34 -0600 ++++ numpy-1.11.1/numpy/distutils/misc_util.py 2016-08-04 12:34:56 -0600 +@@ -116,7 +116,7 @@ + args = list(args) + for i in range(len(args)): + a = args[i] +- if ' ' in a and a[0] not in '"\'': ++ if ' ' in a and a[0] not in '"\'' and a[len(a)-1] not in '"\'': + args[i] = '"%s"' % (a) + return args + diff --git a/build_files/build_environment/patches/opencollada.diff b/build_files/build_environment/patches/opencollada.diff new file mode 100644 index 00000000000..0c91b4151fe --- /dev/null +++ b/build_files/build_environment/patches/opencollada.diff @@ -0,0 +1,32 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 3fc9be5..5112ce6 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -254,11 +254,11 @@ + endif()
+
+ #adding PCRE
+-find_package(PCRE)
++#find_package(PCRE)
+ if (PCRE_FOUND)
+ message(STATUS "SUCCESSFUL: PCRE found")
+ else () # if pcre not found building its local copy from ./Externals
+- if (WIN32 OR APPLE)
++ if (1)
+ message("WARNING: Native PCRE not found, taking PCRE from ./Externals")
+ add_definitions(-DPCRE_STATIC)
+ add_subdirectory(${EXTERNAL_LIBRARIES}/pcre)
+diff --git a/DAEValidator/library/include/no_warning_begin.orig b/DAEValidator/library/include/no_warning_begin +index 3fc9be5..5112ce6 100644 +--- a/DAEValidator/library/include/no_warning_begin.orig 2017-05-31 16:56:39 -0600 ++++ b/DAEValidator/library/include/no_warning_begin 2017-06-07 10:18:45 -0600 +@@ -2,6 +2,9 @@ + #if defined(_WIN32) + # pragma warning(push) + # pragma warning(disable:4668) ++# if _MSC_VER >=1900 ++# pragma warning(disable:5031) ++# endif + # if defined(_MSC_VER) && defined(_DEBUG) + # pragma warning(disable:4548) + # endif diff --git a/build_files/build_environment/patches/opencolorio.diff b/build_files/build_environment/patches/opencolorio.diff new file mode 100644 index 00000000000..4e947d89097 --- /dev/null +++ b/build_files/build_environment/patches/opencolorio.diff @@ -0,0 +1,21 @@ +diff -ru ./CMakeLists.txt ./CMakeLists.txt +--- ./CMakeLists.txt 2014-09-11 21:08:18.000000000 +0200 ++++ ./CMakeLists.txt 2016-05-15 17:17:01.000000000 +0200 +@@ -186,7 +186,7 @@ + PATCH_COMMAND patch -f -p1 < ${CMAKE_SOURCE_DIR}/ext/tinyxml_${TINYXML_VERSION}.patch + BINARY_DIR ext/build/tinyxml + INSTALL_DIR ext/dist +- CMAKE_ARGS ${TINYXML_CMAKE_ARGS} ++ CMAKE_ARGS ${TINYXML_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} -DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} -DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT} -DCMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG} -DCMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE} -DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG} -DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE} -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} + ) + if(WIN32) + set(TINYXML_STATIC_LIBRARIES ${PROJECT_BINARY_DIR}/ext/dist/lib/tinyxml.lib) +@@ -254,7 +254,7 @@ + BINARY_DIR ext/build/yaml-cpp + PATCH_COMMAND patch -p1 < ${CMAKE_SOURCE_DIR}/ext/yaml-cpp-${YAML_CPP_VERSION}.patch + INSTALL_DIR ext/dist +- CMAKE_ARGS ${YAML_CPP_CMAKE_ARGS} ++ CMAKE_ARGS ${YAML_CPP_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} -DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} -DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT} -DCMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG} -DCMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE} -DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG} -DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE} -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} + ) + set(YAML_CPP_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/ext/dist/include) + set(YAML_CPP_LIBRARY_DIRS ${PROJECT_BINARY_DIR}/ext/dist/lib) diff --git a/build_files/build_environment/patches/openexr.diff b/build_files/build_environment/patches/openexr.diff new file mode 100644 index 00000000000..ec18751fe74 --- /dev/null +++ b/build_files/build_environment/patches/openexr.diff @@ -0,0 +1,33 @@ +--- IlmImf/CMakeLists.txt 2014-08-10 06:23:56.000000000 +0200 ++++ IlmImf/CMakeLists.txt 2017-01-08 04:06:04.931723800 +0100 +@@ -8,8 +8,8 @@ + + TARGET_LINK_LIBRARIES ( b44ExpLogTable + Half +- Iex${ILMBASE_LIBSUFFIX} + IlmThread${ILMBASE_LIBSUFFIX} ++ Iex${ILMBASE_LIBSUFFIX} + ${PTHREAD_LIB} + ) + +@@ -25,8 +25,8 @@ + + TARGET_LINK_LIBRARIES ( dwaLookups + Half +- Iex${ILMBASE_LIBSUFFIX} + IlmThread${ILMBASE_LIBSUFFIX} ++ Iex${ILMBASE_LIBSUFFIX} + ${PTHREAD_LIB} + ) + +@@ -138,9 +138,9 @@ + + TARGET_LINK_LIBRARIES ( IlmImf + Half +- Iex${ILMBASE_LIBSUFFIX} + Imath${ILMBASE_LIBSUFFIX} + IlmThread${ILMBASE_LIBSUFFIX} ++ Iex${ILMBASE_LIBSUFFIX} + ${PTHREAD_LIB} ${ZLIB_LIBRARIES} + ) + diff --git a/build_files/build_environment/patches/openimageio_gdi.diff b/build_files/build_environment/patches/openimageio_gdi.diff new file mode 100644 index 00000000000..af0c90638de --- /dev/null +++ b/build_files/build_environment/patches/openimageio_gdi.diff @@ -0,0 +1,26 @@ +Index: OpenImageIO/osdep.h +=================================================================== +--- OpenImageIO/osdep.h (revision 61595) ++++ OpenImageIO/osdep.h (working copy) +@@ -34,6 +34,7 @@ + # define WIN32_LEAN_AND_MEAN + # define VC_EXTRALEAN + # define NOMINMAX ++# define NOGDI + # include <windows.h> + #endif + +Index: OpenImageIO/platform.h +=================================================================== +--- OpenImageIO/platform.h (revision 61595) ++++ OpenImageIO/platform.h (working copy) +@@ -77,6 +77,9 @@ + # ifndef NOMINMAX + # define NOMINMAX + # endif ++# ifndef NOGDI ++# define NOGDI ++# endif + # include <windows.h> + #endif + diff --git a/build_files/build_environment/patches/openimageio_idiff.diff b/build_files/build_environment/patches/openimageio_idiff.diff new file mode 100644 index 00000000000..ae1884f76b5 --- /dev/null +++ b/build_files/build_environment/patches/openimageio_idiff.diff @@ -0,0 +1,13 @@ +--- idiff.cpp 2016-11-18 11:42:01 -0700 ++++ idiff.cpp 2016-11-18 11:41:25 -0700 +@@ -308,8 +308,10 @@ + // printed with three digit exponent. We change this behaviour to fit + // Linux way + #ifdef _MSC_VER ++#if _MSC_VER < 1900 + _set_output_format(_TWO_DIGIT_EXPONENT); + #endif ++#endif + std::streamsize precis = std::cout.precision(); + std::cout << " " << cr.nwarn << " pixels (" + << std::setprecision(3) << (100.0*cr.nwarn / npels) diff --git a/build_files/build_environment/patches/openimageio_staticexr.diff b/build_files/build_environment/patches/openimageio_staticexr.diff new file mode 100644 index 00000000000..e1f0f473057 --- /dev/null +++ b/build_files/build_environment/patches/openimageio_staticexr.diff @@ -0,0 +1,11 @@ +--- CMakeLists.txt 2016-11-01 01:03:44 -0600 ++++ CMakeLists.txt 2016-12-01 09:20:12 -0700 +@@ -454,7 +454,7 @@ + add_definitions (-D_CRT_NONSTDC_NO_WARNINGS) + add_definitions (-D_SCL_SECURE_NO_WARNINGS) + add_definitions (-DJAS_WIN_MSVC_BUILD) +- add_definitions (-DOPENEXR_DLL) ++ add_definitions (-DOPJ_STATIC) + if (LINKSTATIC) + add_definitions (-DBoost_USE_STATIC_LIBS=1) + else () diff --git a/build_files/build_environment/patches/opensubdiv.diff b/build_files/build_environment/patches/opensubdiv.diff new file mode 100644 index 00000000000..9e9cf7ad554 --- /dev/null +++ b/build_files/build_environment/patches/opensubdiv.diff @@ -0,0 +1,16 @@ + opensubdiv/osd/d3d11VertexBuffer.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/opensubdiv/osd/d3d11VertexBuffer.cpp b/opensubdiv/osd/d3d11VertexBuffer.cpp +index 603cbf4..07e7e0a 100644 +--- a/opensubdiv/osd/d3d11VertexBuffer.cpp ++++ b/opensubdiv/osd/d3d11VertexBuffer.cpp +@@ -81,7 +81,7 @@ D3D11VertexBuffer::UpdateData(const float *src, int startVertex, int numVertices + + deviceContext->Unmap(_uploadBuffer, 0); + +- D3D11_BOX srcBox = { 0, 0, 0, size, 1, 1 }; ++ D3D11_BOX srcBox = { 0, 0, 0, (UINT) size, 1, 1 }; + deviceContext->CopySubresourceRegion(_buffer, 0, 0, 0, 0, + _uploadBuffer, 0, &srcBox); + } diff --git a/build_files/build_environment/patches/openvdb.diff b/build_files/build_environment/patches/openvdb.diff new file mode 100644 index 00000000000..f3afa13ea17 --- /dev/null +++ b/build_files/build_environment/patches/openvdb.diff @@ -0,0 +1,11 @@ +diff -Naur k:\BlenderDev\lib\win64_vc12_Harvest\openVDB\/include/openvdb/math/Coord.h .\openVDB/include/openvdb/math/Coord.h +--- k:\BlenderDev\lib\win64_vc12_Harvest\openVDB\/include/openvdb/math/Coord.h 2016-03-30 15:09:49 -0600 ++++ .\openVDB/include/openvdb/math/Coord.h 2016-04-01 06:53:47 -0600 +@@ -34,6 +34,7 @@ + #include <openvdb/Platform.h> + #include "Math.h" + #include "Vec3.h" ++#define NOMINMAX + + namespace tbb { class split; } // forward declaration + diff --git a/build_files/build_environment/patches/openvdb_vc2013.diff b/build_files/build_environment/patches/openvdb_vc2013.diff new file mode 100644 index 00000000000..7dc3e476297 --- /dev/null +++ b/build_files/build_environment/patches/openvdb_vc2013.diff @@ -0,0 +1,35 @@ +--- openvdb/tree/LeafNode.h 2015-10-01 15:55:33 -0600 ++++ openvdb/tree/LeafNode.h 2016-03-26 13:12:22 -0600 +@@ -70,13 +70,14 @@ + typedef boost::shared_ptr<LeafNode> Ptr; + typedef util::NodeMask<Log2Dim> NodeMaskType; + +- static const Index +- LOG2DIM = Log2Dim, // needed by parent nodes +- TOTAL = Log2Dim, // needed by parent nodes +- DIM = 1 << TOTAL, // dimension along one coordinate direction +- NUM_VALUES = 1 << 3 * Log2Dim, +- NUM_VOXELS = NUM_VALUES, // total number of voxels represented by this node +- SIZE = NUM_VALUES, ++ static const Index ++ LOG2DIM = Log2Dim, // needed by parent nodes ++ TOTAL = Log2Dim, // needed by parent nodes ++ DIM = 1 << TOTAL, // dimension along one coordinate direction ++ NUM_VALUES = 1 << 3 * Log2Dim, ++ NUM_VOXELS = NUM_VALUES; // total number of voxels represented by this node ++ static const Index ++ SIZE = NUM_VALUES, + LEVEL = 0; // level 0 = leaf + + /// @brief ValueConverter<T>::Type is the type of a LeafNode having the same +--- openvdb/PlatformConfig.h 2016-03-30 15:09:49 -0600 ++++ openvdb/PlatformConfig.h 2016-04-01 07:00:38 -0600 +@@ -47,7 +47,7 @@ + #if !defined(OPENVDB_OPENEXR_STATICLIB) && !defined(OPENEXR_DLL) + #define OPENEXR_DLL + #endif +- ++ #define NOMINMAX + #endif // _WIN32 + + #endif // OPENVDB_PLATFORMCONFIG_HAS_BEEN_INCLUDED diff --git a/build_files/build_environment/patches/osl.diff b/build_files/build_environment/patches/osl.diff new file mode 100644 index 00000000000..fcb5ec4165f --- /dev/null +++ b/build_files/build_environment/patches/osl.diff @@ -0,0 +1,12 @@ +diff -Naur osl/src/external_osl/src/cmake/flexbison.cmake osl_bak/src/external_osl/src/cmake/flexbison.cmake +--- osl/src/external_osl//src/cmake/flexbison.cmake 2016-01-29 11:15:22 -0700 ++++ osl_bak/src/external_osl/src/cmake/flexbison.cmake 2016-02-29 21:26:26 -0700 +@@ -77,7 +77,7 @@ + DEPENDS ${${compiler_headers}} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) + ADD_CUSTOM_COMMAND ( OUTPUT ${flexoutputcxx} +- COMMAND ${FLEX_EXECUTABLE} -o ${flexoutputcxx} "${CMAKE_CURRENT_SOURCE_DIR}/${flexsrc}" ++ COMMAND ${FLEX_EXECUTABLE} ${FLEX_EXTRA_OPTIONS} -o ${flexoutputcxx} "${CMAKE_CURRENT_SOURCE_DIR}/${flexsrc}" + MAIN_DEPENDENCY ${flexsrc} + DEPENDS ${${compiler_headers}} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/build_files/build_environment/patches/osl_simd_oiio.diff b/build_files/build_environment/patches/osl_simd_oiio.diff new file mode 100644 index 00000000000..5062a597167 --- /dev/null +++ b/build_files/build_environment/patches/osl_simd_oiio.diff @@ -0,0 +1,14 @@ +--- CMakeLists.txt 2016-10-31 16:48:19 -0600 ++++ CMakeLists.txt 2017-04-10 10:38:48 -0600 +@@ -269,6 +269,11 @@ + add_definitions ("-DOIIO_STATIC_BUILD=1") + endif () + ++set (OIIO_NOSIMD OFF CACHE BOOL "Disable simd support in oiio") ++if (OIIO_NOSIMD) ++ add_definitions ("-DOIIO_NO_SSE=1") ++endif () ++ + if (OSL_NO_DEFAULT_TEXTURESYSTEM) + add_definitions ("-DOSL_NO_DEFAULT_TEXTURESYSTEM=1") + endif () diff --git a/build_files/build_environment/patches/pthreads.diff b/build_files/build_environment/patches/pthreads.diff new file mode 100644 index 00000000000..bbabfdc8925 --- /dev/null +++ b/build_files/build_environment/patches/pthreads.diff @@ -0,0 +1,13 @@ +--- pthread.h.orig 2012-05-26 22:16:45 -0600 ++++ pthread.h 2016-04-01 09:20:36 -0600 +@@ -109,6 +109,10 @@ + /* Include everything */ + #endif + ++#if _MSC_VER >= 1900 ++# define HAVE_STRUCT_TIMESPEC 1 ++#endif ++ + #if defined(_UWIN) + # define HAVE_STRUCT_TIMESPEC 1 + # define HAVE_SIGNAL_H 1 diff --git a/build_files/build_environment/patches/pyshell.diff b/build_files/build_environment/patches/pyshell.diff new file mode 100644 index 00000000000..7ccffe4c040 --- /dev/null +++ b/build_files/build_environment/patches/pyshell.diff @@ -0,0 +1,12 @@ +--- pyshellext.cpp.orig 2017-01-17 00:57:53 -0700 ++++ pyshellext.cpp 2017-05-20 15:21:51 -0600 +@@ -13,6 +13,9 @@ + #include <strsafe.h> + + #include "pyshellext_h.h" ++#if _MSC_VER < 1900 ++#include "pyshellext_i.c" ++#endif + + #define DDWM_UPDATEWINDOW (WM_USER+3) + diff --git a/build_files/build_environment/patches/python.diff b/build_files/build_environment/patches/python.diff new file mode 100644 index 00000000000..9e7eccfafff --- /dev/null +++ b/build_files/build_environment/patches/python.diff @@ -0,0 +1,82 @@ +--- Include/Python.h 2017-07-07 21:33:27 -0600 ++++ Include/Python.h 2017-09-19 10:36:10 -0600 +@@ -2,6 +2,10 @@ + #define Py_PYTHON_H + /* Since this is a "meta-include" file, no #ifdef __cplusplus / extern "C" { */ + ++#if _MSC_VER < 1900 ++#define inline __inline ++#endif ++ + /* Include nearly all Python header files */ + + #include "patchlevel.h" +--- Include/pydtrace.h 2017-07-07 21:33:27 -0600 ++++ Include/pydtrace.h 2017-09-19 10:32:31 -0600 +@@ -2,6 +2,11 @@ + + #ifndef Py_DTRACE_H + #define Py_DTRACE_H ++ ++#if _MSC_VER < 1900 ++#define inline __inline ++#endif ++ + #ifdef __cplusplus + extern "C" { + #endif + +--- Modules/_blake2/impl/blake2.h 2017-07-07 21:33:27 -0600 ++++ Modules/_blake2/impl/blake2.h 2017-09-19 10:22:41 -0600 +@@ -19,6 +19,10 @@ + #include <stddef.h> + #include <stdint.h> + ++#if _MSC_VER < 1900 ++#define inline __inline ++#endif ++ + #ifdef BLAKE2_NO_INLINE + #define BLAKE2_LOCAL_INLINE(type) static type + #endif + +--- pcbuild/build.bat 2016-05-21 09:53:55 -0600 ++++ pcbuild/build.bat 2016-05-21 09:56:16 -0600 +@@ -59,6 +59,7 @@ + if "%~1"=="-h" goto Usage + if "%~1"=="-c" (set conf=%2) & shift & shift & goto CheckOpts + if "%~1"=="-p" (set platf=%2) & shift & shift & goto CheckOpts ++if "%~1"=="-k" (set vs_toolset=%2) & shift & shift & goto CheckOpts + if "%~1"=="-r" (set target=Rebuild) & shift & goto CheckOpts + if "%~1"=="-t" (set target=%2) & shift & shift & goto CheckOpts + if "%~1"=="-d" (set conf=Debug) & shift & goto CheckOpts +@@ -120,7 +120,7 @@ + + :Kill + echo on +-%MSBUILD% "%dir%\pythoncore.vcxproj" /t:KillPython %verbose%^ ++%MSBUILD% "%dir%\pythoncore.vcxproj" /t:KillPython %verbose% /p:PlatformToolset=%vs_toolset%^ + /p:Configuration=%conf% /p:Platform=%platf%^ + /p:KillPython=true + +@@ -130,7 +130,7 @@ + rem batch is, shall we say, "lackluster" + echo on + %MSBUILD% "%dir%pcbuild.proj" /t:%target% %parallel% %verbose%^ +- /p:Configuration=%conf% /p:Platform=%platf%^ ++ /p:Configuration=%conf% /p:Platform=%platf% /p:PlatformToolset=%vs_toolset%^ + /p:IncludeExternals=%IncludeExternals%^ + /p:IncludeSSL=%IncludeSSL% /p:IncludeTkinter=%IncludeTkinter%^ + /p:UseTestMarker=%UseTestMarker%^ + +--- pcbuild/sqlite3.vcxproj 2015-12-06 18:39:10 -0700 ++++ pcbuild/sqlite3.vcxproj 2016-11-02 09:25:56 -0600 +@@ -43,7 +43,7 @@ + <Import Project="python.props" /> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> +- <ConfigurationType>DynamicLibrary</ConfigurationType> ++ <ConfigurationType>StaticLibrary</ConfigurationType> + <CharacterSet>NotSet</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> diff --git a/build_files/build_environment/patches/python_apple.diff b/build_files/build_environment/patches/python_apple.diff new file mode 100644 index 00000000000..34a7906ed6c --- /dev/null +++ b/build_files/build_environment/patches/python_apple.diff @@ -0,0 +1,25 @@ +--- pyconfig.h.in 2017-09-19 14:41:01.000000000 +0300 ++++ pyconfig.h.in 2017-09-19 14:43:18.000000000 +0300 +@@ -119,12 +119,6 @@ + /* Define to 1 if you have the `clock' function. */ + #undef HAVE_CLOCK + +-/* Define to 1 if you have the `clock_getres' function. */ +-#undef HAVE_CLOCK_GETRES +- +-/* Define to 1 if you have the `clock_gettime' function. */ +-#undef HAVE_CLOCK_GETTIME +- + /* Define to 1 if you have the `clock_settime' function. */ + #undef HAVE_CLOCK_SETTIME + +@@ -369,9 +363,6 @@ + /* Define this if you have flockfile(), getc_unlocked(), and funlockfile() */ + #undef HAVE_GETC_UNLOCKED + +-/* Define to 1 if you have the `getentropy' function. */ +-#undef HAVE_GETENTROPY +- + /* Define to 1 if you have the `getgrouplist' function. */ + #undef HAVE_GETGROUPLIST + diff --git a/build_files/build_environment/patches/python_runtime_vc2013.diff b/build_files/build_environment/patches/python_runtime_vc2013.diff new file mode 100644 index 00000000000..186d2b36c07 --- /dev/null +++ b/build_files/build_environment/patches/python_runtime_vc2013.diff @@ -0,0 +1,29 @@ +--- _msvccompiler.py.orig 2017-05-20 19:31:45 -0600 ++++ _msvccompiler.py 2017-06-10 10:05:38 -0600 +@@ -222,9 +222,9 @@ + # use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib + # later to dynamically link to ucrtbase but not vcruntime. + self.compile_options = [ +- '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG' ++ '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG' , '/MD' + ] +- self.compile_options.append('/MD' if self._vcruntime_redist else '/MT') ++ #self.compile_options.append('/MD' if self._vcruntime_redist else '/MT') + + self.compile_options_debug = [ + '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG' +@@ -233,11 +233,11 @@ + ldflags = [ + '/nologo', '/INCREMENTAL:NO', '/LTCG' + ] +- if not self._vcruntime_redist: +- ldflags.extend(('/nodefaultlib:libucrt.lib', 'ucrt.lib')) ++ #if not self._vcruntime_redist: ++ # ldflags.extend(('/nodefaultlib:libucrt.lib', 'ucrt.lib')) + + ldflags_debug = [ +- '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL' ++ '/nologo', '/INCREMENTAL:NO', '/LTCG' + ] + + self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1'] diff --git a/build_files/build_environment/patches/schroedinger.diff b/build_files/build_environment/patches/schroedinger.diff new file mode 100644 index 00000000000..6acb35f2a7b --- /dev/null +++ b/build_files/build_environment/patches/schroedinger.diff @@ -0,0 +1,54 @@ +--- configure.orig 2012-01-22 19:06:43 -0700 ++++ configure 2016-04-06 20:00:50 -0600 +@@ -16492,10 +16492,10 @@ + HAVE_ORC=yes + fi + if test "x${HAVE_ORC}" != xyes ; then +- as_fn_error $? "orc-0.4 >= $ORC_VER is required" "$LINENO" 5 ++ $as_echo "orc-0.4 >= $ORC_VER is required" + fi + SCHRO_PKG_DEPS="$SCHRO_PKG_DEPS orc-0.4 >= $ORC_VER" +-ORCC=`$PKG_CONFIG --variable=orcc orc-0.4` ++#ORCC=`$PKG_CONFIG --variable=orcc orc-0.4` + + if test "x$cross_compiling" != xyes; then + HAVE_ORCC_TRUE= +--- Makefile.in 2012-01-22 18:06:42 -0700 ++++ Makefile.in 2016-04-06 20:30:09 -0600 +@@ -291,7 +291,7 @@ + top_builddir = @top_builddir@ + top_srcdir = @top_srcdir@ + AUTOMAKE_OPTIONS = foreign +-SUBDIRS = schroedinger doc tools testsuite ++SUBDIRS = schroedinger doc tools + DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc + DIST_SUBDIRS = schroedinger doc tools testsuite + EXTRA_DIST = COPYING COPYING.GPL COPYING.LGPL COPYING.MIT COPYING.MPL \ + +--- schroedinger.pc.in 2011-03-21 17:08:39 -0600 ++++ schroedinger.pc.in 2016-04-08 13:30:42 -0600 +@@ -7,9 +7,9 @@ + + Name: schroedinger-@SCHRO_MAJORMINOR@ + Description: Dirac codec library +-Requires.private: @SCHRO_PKG_DEPS@ ++Requires: @SCHRO_PKG_DEPS@ + Version: @VERSION@ +-Libs: -L${libdir} -lschroedinger-@SCHRO_MAJORMINOR@ ++Libs: -L${libdir} -lschroedinger-@SCHRO_MAJORMINOR@ -lorc-0.4 + Libs.private: @PTHREAD_LIBS@ @LIBM@ + Cflags: -I${includedir} + +--- ./schroedinger/schrodecoder.c 2012-01-23 00:38:57.000000000 +0100 ++++ ./schroedinger/schrodecoder.c 2016-05-15 06:07:24.000000000 +0200 +@@ -70,8 +70,8 @@ + }; + + +-int _schro_decode_prediction_only; +-int _schro_telemetry; ++int _schro_decode_prediction_only = 0; ++int _schro_telemetry = 0; + + static void schro_decoder_x_decode_motion (SchroAsyncStage * stage); + static void schro_decoder_x_render_motion (SchroAsyncStage * stage); diff --git a/build_files/build_environment/patches/sdl.diff b/build_files/build_environment/patches/sdl.diff new file mode 100644 index 00000000000..b309d0230f3 --- /dev/null +++ b/build_files/build_environment/patches/sdl.diff @@ -0,0 +1,50 @@ +diff -ru /Users/brecht/dev/lib/deps/Downloads/SDL2-2.0.4/src/video/SDL_video.c ./src/video/SDL_video.c +--- /Users/brecht/dev/lib/deps/Downloads/SDL2-2.0.4/src/video/SDL_video.c 2016-01-02 20:56:31.000000000 +0100 ++++ ./src/video/SDL_video.c 2016-05-15 02:58:27.000000000 +0200 +@@ -137,7 +137,7 @@ + + #define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN) + +-#ifdef __MACOSX__ ++#if SDL_VIDEO_DRIVER_COCOA + /* Support for Mac OS X fullscreen spaces */ + extern SDL_bool Cocoa_IsWindowInFullscreenSpace(SDL_Window * window); + extern SDL_bool Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state); +@@ -1141,7 +1141,7 @@ + if ( window->is_hiding && fullscreen ) + return 0; + +-#ifdef __MACOSX__ ++#if SDL_VIDEO_DRIVER_COCOA + /* if the window is going away and no resolution change is necessary, + do nothing, or else we may trigger an ugly double-transition + */ +@@ -2365,7 +2365,7 @@ + return SDL_FALSE; + } + +-#ifdef __MACOSX__ ++#if SDL_VIDEO_DRIVER_COCOA + if (Cocoa_IsWindowInFullscreenSpace(window)) { + return SDL_FALSE; + } +--- CMakeLists.txt.old 2016-01-02 12:56:31 -0700 ++++ CMakeLists.txt 2016-10-03 11:24:24 -0600 +@@ -609,7 +609,7 @@ + list(APPEND EXTRA_LIBS m) + endif() + +- check_library_exists(iconv iconv_open "" HAVE_LIBICONV) ++ #check_library_exists(iconv iconv_open "" HAVE_LIBICONV) + if(HAVE_LIBICONV) + list(APPEND EXTRA_LIBS iconv) + set(HAVE_ICONV 1) +@@ -1455,7 +1455,7 @@ + set(_INSTALL_LIBS "SDL2main") + + if(SDL_SHARED) +- add_library(SDL2 SHARED ${SOURCE_FILES}) ++ add_library(SDL2 SHARED ${SOURCE_FILES} ${VERSION_SOURCES}) + if(UNIX) + set_target_properties(SDL2 PROPERTIES + VERSION ${LT_VERSION} diff --git a/build_files/build_environment/patches/semi.txt b/build_files/build_environment/patches/semi.txt new file mode 100644 index 00000000000..092bc2b0412 --- /dev/null +++ b/build_files/build_environment/patches/semi.txt @@ -0,0 +1 @@ +; diff --git a/build_files/build_environment/patches/sndfile.diff b/build_files/build_environment/patches/sndfile.diff new file mode 100644 index 00000000000..ab43baa78df --- /dev/null +++ b/build_files/build_environment/patches/sndfile.diff @@ -0,0 +1,42 @@ +--- src/Makefile.in 2017-09-26 01:28:47.000000000 +0300 ++++ src/Makefile.in 2017-09-26 01:19:06.000000000 +0300 +@@ -513,7 +513,7 @@ + libcommon_la_SOURCES = common.c file_io.c command.c pcm.c ulaw.c alaw.c \ + float32.c double64.c ima_adpcm.c ms_adpcm.c gsm610.c dwvw.c vox_adpcm.c \ + interleave.c strings.c dither.c cart.c broadcast.c audio_detect.c \ +- ima_oki_adpcm.c ima_oki_adpcm.h alac.c chunk.c ogg.c chanmap.c \ ++ ima_oki_adpcm.c ima_oki_adpcm.h alac.c chunk.c ogg.c chanmap.c \ + windows.c id3.c $(WIN_VERSION_FILE) + + +@@ -719,10 +719,10 @@ + $(AM_V_CCLD)$(LINK) $(GSM610_libgsm_la_OBJECTS) $(GSM610_libgsm_la_LIBADD) $(LIBS) + + libcommon.la: $(libcommon_la_OBJECTS) $(libcommon_la_DEPENDENCIES) $(EXTRA_libcommon_la_DEPENDENCIES) +- $(AM_V_CCLD)$(LINK) $(libcommon_la_OBJECTS) $(libcommon_la_LIBADD) $(LIBS) ++ $(AM_V_CCLD)$(LINK) $(libcommon_la_OBJECTS) $(libcommon_la_LIBADD) $(LIBS) $(EXTERNAL_XIPH_LIBS) + + libsndfile.la: $(libsndfile_la_OBJECTS) $(libsndfile_la_DEPENDENCIES) $(EXTRA_libsndfile_la_DEPENDENCIES) +- $(AM_V_CCLD)$(libsndfile_la_LINK) -rpath $(libdir) $(libsndfile_la_OBJECTS) $(libsndfile_la_LIBADD) $(LIBS) ++ $(AM_V_CCLD)$(libsndfile_la_LINK) -rpath $(libdir) $(libsndfile_la_OBJECTS) $(libsndfile_la_LIBADD) $(LIBS) $(EXTERNAL_XIPH_LIBS) + + clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ +@@ -924,7 +924,7 @@ + @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -c -o libsndfile_la-dwd.lo `test -f 'dwd.c' || echo '$(srcdir)/'`dwd.c + + libsndfile_la-flac.lo: flac.c +-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -MT libsndfile_la-flac.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-flac.Tpo -c -o libsndfile_la-flac.lo `test -f 'flac.c' || echo '$(srcdir)/'`flac.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) $(EXTERNAL_XIPH_CFLAGS) -MT libsndfile_la-flac.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-flac.Tpo -c -o libsndfile_la-flac.lo `test -f 'flac.c' || echo '$(srcdir)/'`flac.c + @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsndfile_la-flac.Tpo $(DEPDIR)/libsndfile_la-flac.Plo + @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='flac.c' object='libsndfile_la-flac.lo' libtool=yes @AMDEPBACKSLASH@ + @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@@ -1092,7 +1092,7 @@ + @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -c -o libsndfile_la-rf64.lo `test -f 'rf64.c' || echo '$(srcdir)/'`rf64.c + + libsndfile_la-ogg_vorbis.lo: ogg_vorbis.c +-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -MT libsndfile_la-ogg_vorbis.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-ogg_vorbis.Tpo -c -o libsndfile_la-ogg_vorbis.lo `test -f 'ogg_vorbis.c' || echo '$(srcdir)/'`ogg_vorbis.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) $(EXTERNAL_XIPH_CFLAGS) -MT libsndfile_la-ogg_vorbis.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-ogg_vorbis.Tpo -c -o libsndfile_la-ogg_vorbis.lo `test -f 'ogg_vorbis.c' || echo '$(srcdir)/'`ogg_vorbis.c + @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsndfile_la-ogg_vorbis.Tpo $(DEPDIR)/libsndfile_la-ogg_vorbis.Plo + @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ogg_vorbis.c' object='libsndfile_la-ogg_vorbis.lo' libtool=yes @AMDEPBACKSLASH@ + @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ diff --git a/build_files/build_environment/windows/build_deps.cmd b/build_files/build_environment/windows/build_deps.cmd new file mode 100644 index 00000000000..96280014df2 --- /dev/null +++ b/build_files/build_environment/windows/build_deps.cmd @@ -0,0 +1,122 @@ +@echo off +if NOT "%1" == "" ( + if "%1" == "2013" ( + echo "Building for VS2013" + set VSVER=12.0 + set VSVER_SHORT=12 + set BuildDir=VS12 + goto par2 + ) + if "%1" == "2015" ( + echo "Building for VS2015" + set VSVER=14.0 + set VSVER_SHORT=14 + set BuildDir=VS14 + goto par2 + ) +) +:usage + +Echo Usage build_deps 2013/2015 x64/x86 +goto exit +:par2 +if NOT "%2" == "" ( + if "%2" == "x86" ( + echo "Building for x86" + set HARVESTROOT=Windows_vc + set ARCH=86 + if "%1" == "2013" ( + set CMAKE_BUILDER=Visual Studio 12 2013 + ) + if "%1" == "2015" ( + set CMAKE_BUILDER=Visual Studio 14 2015 + ) + goto start + ) + if "%2" == "x64" ( + echo "Building for x64" + set HARVESTROOT=Win64_vc + set ARCH=64 + if "%1" == "2013" ( + set CMAKE_BUILDER=Visual Studio 12 2013 Win64 + ) + if "%1" == "2015" ( + set CMAKE_BUILDER=Visual Studio 14 2015 Win64 + ) + goto start + ) +) +goto usage + +:start +setlocal ENABLEEXTENSIONS +set CMAKE_DEBUG_OPTIONS=-DWITH_OPTIMIZED_DEBUG=On +if "%3" == "debug" set CMAKE_DEBUG_OPTIONS=-DWITH_OPTIMIZED_DEBUG=Off + +set SOURCE_DIR=%~dp0\.. +set BUILD_DIR=%cd%\build +set HARVEST_DIR=%BUILD_DIR%\output +set STAGING=%BUILD_DIR%\S + +rem for python module build +set MSSdk=1 +set DISTUTILS_USE_SDK=1 +rem for python externals source to be shared between the various archs and compilers +mkdir %BUILD_DIR%\downloads\externals + +REM Detect MSVC Installation +if DEFINED VisualStudioVersion goto msvc_detect_finally +set VALUE_NAME=ProductDir +REM Check 64 bits +set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%VSVER%\Setup\VC" +for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO set MSVC_VC_DIR=%%C +if DEFINED MSVC_VC_DIR goto msvc_detect_finally +REM Check 32 bits +set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\%VSVER%\Setup\VC" +for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO set MSVC_VC_DIR=%%C +if DEFINED MSVC_VC_DIR goto msvc_detect_finally +:msvc_detect_finally +if DEFINED MSVC_VC_DIR call "%MSVC_VC_DIR%\vcvarsall.bat" +echo on + +REM Sanity Checks +where /Q msbuild +if %ERRORLEVEL% NEQ 0 ( + echo Error: "MSBuild" command not in the PATH. + echo You must have MSVC installed and run this from the "Developer Command Prompt" + echo ^(available from Visual Studio's Start menu entry^), aborting! + goto EOF +) +where /Q cmake +if %ERRORLEVEL% NEQ 0 ( + echo Error: "CMake" command not in the PATH. + echo You must have CMake installed and added to your PATH, aborting! + goto EOF +) + +set StatusFile=%BUILD_DIR%\%1_%2.log +set path=%BUILD_DIR%\downloads\mingw\mingw64\msys\1.0\bin\;%BUILD_DIR%\downloads\nasm-2.12.01\;%path% +mkdir %STAGING%\%BuildDir%%ARCH%R +cd %Staging%\%BuildDir%%ARCH%R +echo %DATE% %TIME% : Start > %StatusFile% +cmake -G "%CMAKE_BUILDER%" %SOURCE_DIR% -DDOWNLOAD_DIR=%BUILD_DIR%/downloads -DBUILD_MODE=Release -DHARVEST_TARGET=%HARVEST_DIR%/%HARVESTROOT%%VSVER_SHORT%/ +echo %DATE% %TIME% : Release Configuration done >> %StatusFile% +msbuild /m "ll.vcxproj" /p:Configuration=Release /fl /flp:logfile=BlenderDeps_llvm.log;Verbosity=normal +msbuild /m "BlenderDependencies.sln" /p:Configuration=Release /fl /flp:logfile=BlenderDeps.log;Verbosity=minimal /verbosity:minimal +echo %DATE% %TIME% : Release Build done >> %StatusFile% +cmake --build . --target Harvest_Release_Results > Harvest_Release.txt +echo %DATE% %TIME% : Release Harvest done >> %StatusFile% +cd %BUILD_DIR% +mkdir %STAGING%\%BuildDir%%ARCH%D +cd %Staging%\%BuildDir%%ARCH%D +cmake -G "%CMAKE_BUILDER%" %SOURCE_DIR% -DDOWNLOAD_DIR=%BUILD_DIR%/downloads -DCMAKE_BUILD_TYPE=Debug -DBUILD_MODE=Debug -DHARVEST_TARGET=%HARVEST_DIR%/%HARVESTROOT%%VSVER_SHORT%/ %CMAKE_DEBUG_OPTIONS% +echo %DATE% %TIME% : Debug Configuration done >> %StatusFile% +msbuild /m "ll.vcxproj" /p:Configuration=Debug /fl /flp:logfile=BlenderDeps_llvm.log;;Verbosity=normal +msbuild /m "BlenderDependencies.sln" /p:Configuration=Debug /verbosity:n /fl /flp:logfile=BlenderDeps.log;;Verbosity=normal +echo %DATE% %TIME% : Debug Build done >> %StatusFile% +cmake --build . --target Harvest_Debug_Results> Harvest_Debug.txt +echo %DATE% %TIME% : Debug Harvest done >> %StatusFile% +cd %BUILD_DIR% + +:exit +Echo . diff --git a/build_files/build_environment/windows/buildall.cmd b/build_files/build_environment/windows/buildall.cmd new file mode 100644 index 00000000000..480be8cde44 --- /dev/null +++ b/build_files/build_environment/windows/buildall.cmd @@ -0,0 +1,10 @@ +title building 1_4 - x86_2013 +call build_deps 2013 x86 +title building 2_4 - x86_2015 +call build_deps 2015 x86 +title building 3_4 - x64_2013 +call build_deps 2013 x64 +title building 4_4 - x64_2015 +call build_deps 2015 x64 +title done! +echo done!
\ No newline at end of file diff --git a/build_files/build_environment/windows/nuke.cmd b/build_files/build_environment/windows/nuke.cmd new file mode 100644 index 00000000000..68dbc8d1487 --- /dev/null +++ b/build_files/build_environment/windows/nuke.cmd @@ -0,0 +1,52 @@ +@echo off +if "%1"=="" goto EOF: +set ROOT=%~dp0\..\..\..\..\build_windows\deps + +set CurPath=%ROOT%\s\vs1264D\debug\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1264D\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1264R\release\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1264R\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\output\win64_vc12\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) + +set CurPath=%ROOT%\s\vs1464D\debug\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1464D\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1464R\release\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1464R\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\output\win64_vc14\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) + +set CurPath=%ROOT%\s\vs1286D\debug\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1286D\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1286R\release\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1286R\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\output\windows_vc12\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) + +set CurPath=%ROOT%\s\vs1486D\debug\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1486D\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1486R\release\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1486R\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\output\windows_vc14\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) + + +:EOF + + diff --git a/build_files/buildbot/config/blender_linux.cmake b/build_files/buildbot/config/blender_linux.cmake index 56f18967300..95265754d74 100644 --- a/build_files/buildbot/config/blender_linux.cmake +++ b/build_files/buildbot/config/blender_linux.cmake @@ -70,7 +70,7 @@ set(FFMPEG_LIBRARIES ) # SndFile libraries -set(SNDFILE_LIBRARY "/usr/lib/libsndfile.a;/usr/lib/libFLAC.a" CACHE STRING "" FORCE) +set(SNDFILE_LIBRARY "/usr/lib${MULTILIB}/libsndfile.a;/usr/lib${MULTILIB}/libFLAC.a" CACHE STRING "" FORCE) # OpenAL libraries set(OPENAL_ROOT_DIR "/opt/lib/openal" CACHE STRING "" FORCE) diff --git a/build_files/buildbot/master.cfg b/build_files/buildbot/master.cfg index c650cb8c302..c721d5a4ba9 100644 --- a/build_files/buildbot/master.cfg +++ b/build_files/buildbot/master.cfg @@ -246,8 +246,6 @@ def git_submodules_update(): def lib_svn_step(dir): name = "lib svn" - if dir == "darwin": - name = "C++11 lib svn" return SVN(name=name, baseURL='https://svn.blender.org/svnroot/bf-blender/%%BRANCH%%/lib/' + dir, codebase='lib svn', @@ -277,9 +275,6 @@ def generic_builder(id, libdir='', branch='', rsync=False): f = BuildFactory() if libdir != '': f.addStep(lib_svn_step(libdir)) - # Special trick to make sure we always have all the libs. - if libdir.startswith("darwin"): - f.addStep(lib_svn_step("darwin")) for submodule in ('blender-translations', 'blender-addons', @@ -312,15 +307,13 @@ def generic_builder(id, libdir='', branch='', rsync=False): # Builders -add_builder(c, 'mac_x86_64_10_6_cmake', 'darwin-9.x.universal', generic_builder, hour=5) -# add_builder(c, 'linux_glibc211_i686_cmake', '', generic_builder, hour=1) -# add_builder(c, 'linux_glibc211_x86_64_cmake', '', generic_builder, hour=2) -add_builder(c, 'linux_glibc219_i686_cmake', '', generic_builder, hour=3) -add_builder(c, 'linux_glibc219_x86_64_cmake', '', generic_builder, hour=4) -add_builder(c, 'win32_cmake_vc2013', 'windows_vc12', generic_builder, hour=3) -add_builder(c, 'win64_cmake_vc2013', 'win64_vc12', generic_builder, hour=4) -add_builder(c, 'win32_cmake_vc2015', 'windows_vc14', generic_builder, hour=5) -add_builder(c, 'win64_cmake_vc2015', 'win64_vc14', generic_builder, hour=6) +add_builder(c, 'mac_x86_64_10_6_cmake', 'darwin', generic_builder, hour=1) +add_builder(c, 'linux_glibc219_i686_cmake', '', generic_builder, hour=2) +add_builder(c, 'linux_glibc219_x86_64_cmake', '', generic_builder, hour=1) +add_builder(c, 'win32_cmake_vc2013', 'windows_vc12', generic_builder, hour=1) +add_builder(c, 'win64_cmake_vc2013', 'win64_vc12', generic_builder, hour=2) +add_builder(c, 'win32_cmake_vc2015', 'windows_vc14', generic_builder, hour=3) +add_builder(c, 'win64_cmake_vc2015', 'win64_vc14', generic_builder, hour=4) # STATUS TARGETS # diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py index 0e264a752d5..84f924b2dd9 100644 --- a/build_files/buildbot/slave_compile.py +++ b/build_files/buildbot/slave_compile.py @@ -72,7 +72,6 @@ if 'cmake' in builder: # Set up OSX architecture if builder.endswith('x86_64_10_6_cmake'): cmake_extra_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64') - cmake_extra_options.append('-DWITH_CODEC_QUICKTIME=OFF') cmake_extra_options.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=10.6') cmake_extra_options.append('-DCUDA_HOST_COMPILER=/usr/local/cuda-hack/clang') cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE=/usr/local/cuda-hack/nvcc') @@ -112,8 +111,8 @@ if 'cmake' in builder: chroot_name = 'buildbot_' + deb_name + '_i686' cuda_chroot_name = 'buildbot_' + deb_name + '_x86_64' targets = ['player', 'blender', 'cuda'] - cmake_extra_options.extend(["-DCMAKE_C_COMPILER=/usr/bin/gcc-6", - "-DCMAKE_CXX_COMPILER=/usr/bin/g++-6"]) + cmake_extra_options.extend(["-DCMAKE_C_COMPILER=/usr/bin/gcc-7", + "-DCMAKE_CXX_COMPILER=/usr/bin/g++-7"]) cmake_options.append("-C" + os.path.join(blender_dir, cmake_config_file)) diff --git a/build_files/cmake/cmake_consistency_check.py b/build_files/cmake/cmake_consistency_check.py index 3d06790758a..443657532de 100755 --- a/build_files/cmake/cmake_consistency_check.py +++ b/build_files/cmake/cmake_consistency_check.py @@ -61,10 +61,8 @@ def replace_line(f, i, text, keep_indent=True): def source_list(path, filename_check=None): for dirpath, dirnames, filenames in os.walk(path): - # skip '.git' - if dirpath.startswith("."): - continue + dirnames[:] = [d for d in dirnames if not d.startswith(".")] for filename in filenames: if filename_check is None or filename_check(filename): diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake index 62e2ce1636d..35eba1e6a41 100644 --- a/build_files/cmake/config/blender_full.cmake +++ b/build_files/cmake/config/blender_full.cmake @@ -66,9 +66,7 @@ elseif(WIN32) set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE) elseif(APPLE) set(WITH_JACK ON CACHE BOOL "" FORCE) - set(WITH_CODEC_QUICKTIME OFF CACHE BOOL "" FORCE) set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE) # include("${CMAKE_CURRENT_SOURCE_DIR}/../platform/platform_apple_xcode.cmake") -# apple_check_quicktime() endif() diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake index 537134eb357..98818d4ab50 100644 --- a/build_files/cmake/config/blender_lite.cmake +++ b/build_files/cmake/config/blender_lite.cmake @@ -56,7 +56,3 @@ set(WITH_SDL OFF CACHE BOOL "" FORCE) set(WITH_X11_XINPUT OFF CACHE BOOL "" FORCE) set(WITH_X11_XF86VMODE OFF CACHE BOOL "" FORCE) -if(APPLE) - set(WITH_CODEC_QUICKTIME OFF CACHE BOOL "" FORCE) -endif() - diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake index 3e2e26e6a44..3cdbfdfcf3b 100644 --- a/build_files/cmake/config/blender_release.cmake +++ b/build_files/cmake/config/blender_release.cmake @@ -67,9 +67,7 @@ elseif(WIN32) set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE) elseif(APPLE) set(WITH_JACK ON CACHE BOOL "" FORCE) - set(WITH_CODEC_QUICKTIME OFF CACHE BOOL "" FORCE) set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE) # include("${CMAKE_CURRENT_SOURCE_DIR}/../platform/platform_apple_xcode.cmake") -# apple_check_quicktime() endif() diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 6303119773d..06f47b9402b 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -403,9 +403,6 @@ function(setup_liblinks if(WITH_SDL AND NOT WITH_SDL_DYNLOAD) target_link_libraries(${target} ${SDL_LIBRARY}) endif() - if(WITH_CODEC_QUICKTIME) - target_link_libraries(${target} ${QUICKTIME_LIBRARIES}) - endif() if(WITH_IMAGE_TIFF) target_link_libraries(${target} ${TIFF_LIBRARY}) endif() @@ -715,10 +712,6 @@ function(SETUP_BLENDER_SORTED_LIBS) list(APPEND BLENDER_SORTED_LIBS bf_intern_itasc) endif() - if(WITH_CODEC_QUICKTIME) - list(APPEND BLENDER_SORTED_LIBS bf_quicktime) - endif() - if(WITH_MOD_BOOLEAN) list(APPEND BLENDER_SORTED_LIBS extern_carve) endif() diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 6105f2e04de..a08f94e5ec0 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -28,11 +28,7 @@ macro(find_package_wrapper) endmacro() if(NOT DEFINED LIBDIR) - if(WITH_CXX11) - set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin) - else() - set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-9.x.universal) - endif() + set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin) else() message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}") endif() @@ -88,12 +84,12 @@ endif() if(WITH_PYTHON) # we use precompiled libraries for py 3.5 and up by default - set(PYTHON_VERSION 3.5) + set(PYTHON_VERSION 3.6) if(NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK) # normally cached but not since we include them with blender set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}m") set(PYTHON_EXECUTABLE "${LIBDIR}/python/bin/python${PYTHON_VERSION}m") - set(PYTHON_LIBRARY python${PYTHON_VERSION}m) + set(PYTHON_LIBRARY ${LIBDIR}/python/lib/libpython${PYTHON_VERSION}m.a) set(PYTHON_LIBPATH "${LIBDIR}/python/lib/python${PYTHON_VERSION}") # set(PYTHON_LINKFLAGS "-u _PyMac_Error") # won't build with this enabled else() @@ -113,6 +109,9 @@ if(WITH_PYTHON) set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}") + # needed for Audaspace, numpy is installed into python site-packages + set(NUMPY_INCLUDE_DIRS "${PYTHON_LIBPATH}/site-packages/numpy/core/include") + if(NOT EXISTS "${PYTHON_EXECUTABLE}") message(FATAL_ERROR "Python executable missing: ${PYTHON_EXECUTABLE}") endif() @@ -141,11 +140,7 @@ if(WITH_IMAGE_OPENEXR) set(OPENEXR ${LIBDIR}/openexr) set(OPENEXR_INCLUDE_DIR ${OPENEXR}/include) set(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR}/include/OpenEXR) - if(WITH_CXX11) - set(OPENEXR_POSTFIX -2_2) - else() - set(OPENEXR_POSTFIX) - endif() + set(OPENEXR_POSTFIX -2_2) set(OPENEXR_LIBRARIES Iex${OPENEXR_POSTFIX} Half @@ -162,20 +157,16 @@ if(WITH_CODEC_FFMPEG) avcodec avdevice avformat avutil mp3lame swscale x264 xvidcore theora theoradec theoraenc vorbis vorbisenc vorbisfile ogg ) - if(WITH_CXX11) - set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} schroedinger orc vpx webp swresample) - endif() + set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} schroedinger orc vpx webp swresample) set(FFMPEG_LIBPATH ${FFMPEG}/lib) endif() if(WITH_OPENJPEG OR WITH_CODEC_FFMPEG) # use openjpeg from libdir that is linked into ffmpeg - if(WITH_CXX11) - set(OPENJPEG ${LIBDIR}/openjpeg) - set(WITH_SYSTEM_OPENJPEG ON) - set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include) - set(OPENJPEG_LIBRARIES ${OPENJPEG}/lib/libopenjpeg.a) - endif() + set(OPENJPEG ${LIBDIR}/openjpeg) + set(WITH_SYSTEM_OPENJPEG ON) + set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include) + set(OPENJPEG_LIBRARIES ${OPENJPEG}/lib/libopenjpeg.a) endif() find_library(SYSTEMSTUBS_LIBRARY @@ -192,19 +183,8 @@ set(PLATFORM_CFLAGS "-pipe -funsigned-char") set(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox -framework CoreAudio" ) -if(WITH_CODEC_QUICKTIME) - set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QTKit") - if(CMAKE_OSX_ARCHITECTURES MATCHES i386) - set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QuickTime") - # libSDL still needs 32bit carbon quicktime - endif() -endif() -if(WITH_CXX11) - list(APPEND PLATFORM_LINKLIBS c++) -else() - list(APPEND PLATFORM_LINKLIBS stdc++) -endif() +list(APPEND PLATFORM_LINKLIBS c++) if(WITH_JACK) set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -F/Library/Frameworks -weak_framework jackmp") @@ -255,11 +235,7 @@ if(WITH_SDL) set(SDL_INCLUDE_DIR ${SDL}/include) set(SDL_LIBRARY SDL2) set(SDL_LIBPATH ${SDL}/lib) - if(WITH_CXX11) - set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework ForceFeedback") - else() - set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -lazy_framework ForceFeedback") - endif() + set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework ForceFeedback") endif() set(PNG "${LIBDIR}/png") @@ -280,11 +256,7 @@ endif() if(WITH_BOOST) set(BOOST ${LIBDIR}/boost) set(BOOST_INCLUDE_DIR ${BOOST}/include) - if(WITH_CXX11) - set(BOOST_POSTFIX) - else() - set(BOOST_POSTFIX -mt) - endif() + set(BOOST_POSTFIX) set(BOOST_LIBRARIES boost_date_time${BOOST_POSTFIX} boost_filesystem${BOOST_POSTFIX} @@ -321,9 +293,7 @@ if(WITH_OPENIMAGEIO) ${OPENEXR_LIBRARIES} ${ZLIB_LIBRARIES} ) - if(WITH_CXX11) - set(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARIES} ${LIBDIR}/ffmpeg/lib/libwebp.a) - endif() + set(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARIES} ${LIBDIR}/ffmpeg/lib/libwebp.a) set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib ${JPEG_LIBPATH} @@ -461,10 +431,8 @@ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -Xlinker -unexported_symbols_list -Xlinker ${CMAKE_SOURCE_DIR}/source/creator/osx_locals.map" ) -if(WITH_CXX11) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") - set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -stdlib=libc++") -endif() +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") +set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -stdlib=libc++") # Suppress ranlib "has no symbols" warnings (workaround for T48250) set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>") diff --git a/build_files/cmake/platform/platform_apple_xcode.cmake b/build_files/cmake/platform/platform_apple_xcode.cmake index e76a7783939..8bb08b5a29f 100644 --- a/build_files/cmake/platform/platform_apple_xcode.cmake +++ b/build_files/cmake/platform/platform_apple_xcode.cmake @@ -101,21 +101,14 @@ if(OSX_SYSTEM MATCHES 10.9) set(CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT}) endif() -if(WITH_CXX11) - # 10.9 is our min. target, if you use higher sdk, weak linking happens - if(CMAKE_OSX_DEPLOYMENT_TARGET) - if(${CMAKE_OSX_DEPLOYMENT_TARGET} VERSION_LESS 10.9) - message(STATUS "Setting deployment target to 10.9, lower versions are incompatible with WITH_CXX11") - set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "" FORCE) - endif() - else() +# 10.9 is our min. target, if you use higher sdk, weak linking happens +if(CMAKE_OSX_DEPLOYMENT_TARGET) + if(${CMAKE_OSX_DEPLOYMENT_TARGET} VERSION_LESS 10.9) + message(STATUS "Setting deployment target to 10.9, lower versions are incompatible with WITH_CXX11") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "" FORCE) endif() else() - if(NOT CMAKE_OSX_DEPLOYMENT_TARGET) - # 10.6 is our min. target, if you use higher sdk, weak linking happens - set(CMAKE_OSX_DEPLOYMENT_TARGET "10.6" CACHE STRING "" FORCE) - endif() + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "" FORCE) endif() if(NOT ${CMAKE_GENERATOR} MATCHES "Xcode") @@ -124,12 +117,3 @@ if(NOT ${CMAKE_GENERATOR} MATCHES "Xcode") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") add_definitions("-DMACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}") endif() - -macro(apple_check_quicktime) - # QuickTime framework is no longer available in SDK 10.12+ - if(WITH_CODEC_QUICKTIME AND ${OSX_SYSTEM} VERSION_GREATER 10.11) - set(WITH_CODEC_QUICKTIME OFF CACHE BOOL "" FORCE) - message(STATUS "QuickTime not supported by SDK ${OSX_SYSTEM}, disabling WITH_CODEC_QUICKTIME") - endif() -endmacro() - diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 62e0caa7c43..5eefc40e8f4 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -400,10 +400,6 @@ if(CMAKE_COMPILER_IS_GNUCC) # CLang is the same as GCC for now. elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing") -# Solaris CC -elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro") - set(PLATFORM_CFLAGS "-pipe -features=extensions -fPIC -D__FUNCTION__=__func__") - # Intel C++ Compiler elseif(CMAKE_C_COMPILER_ID MATCHES "Intel") # think these next two are broken diff --git a/build_files/cmake/platform/platform_win32_msvc.cmake b/build_files/cmake/platform/platform_win32_msvc.cmake index 3b417f79cbe..47dd0edc8ba 100644 --- a/build_files/cmake/platform/platform_win32_msvc.cmake +++ b/build_files/cmake/platform/platform_win32_msvc.cmake @@ -134,7 +134,10 @@ if(NOT DEFINED LIBDIR) message(STATUS "32 bit compiler detected.") set(LIBDIR_BASE "windows") endif() - if(MSVC_VERSION EQUAL 1910) + if(MSVC_VERSION EQUAL 1911) + message(STATUS "Visual Studio 2017 detected.") + set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14) + elseif(MSVC_VERSION EQUAL 1910) message(STATUS "Visual Studio 2017 detected.") set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14) elseif(MSVC_VERSION EQUAL 1900) @@ -299,7 +302,7 @@ if(WITH_JACK) endif() if(WITH_PYTHON) - set(PYTHON_VERSION 3.5) # CACHE STRING) + set(PYTHON_VERSION 3.6) # CACHE STRING) string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION}) # Use shared libs for vc2008 and vc2010 until we actually have vc2010 libs diff --git a/build_files/cmake/project_info.py b/build_files/cmake/project_info.py index 3ac4c4c9480..9b0905da030 100755 --- a/build_files/cmake/project_info.py +++ b/build_files/cmake/project_info.py @@ -84,10 +84,8 @@ def init(cmake_path): def source_list(path, filename_check=None): for dirpath, dirnames, filenames in os.walk(path): - - # skip '.svn' - if dirpath.startswith("."): - continue + # skip '.git' + dirnames[:] = [d for d in dirnames if not d.startswith(".")] for filename in filenames: filepath = join(dirpath, filename) diff --git a/build_files/utils/build_tgz.sh b/build_files/utils/build_tgz.sh index 865df277605..c568d17db1c 100755 --- a/build_files/utils/build_tgz.sh +++ b/build_files/utils/build_tgz.sh @@ -53,7 +53,11 @@ echo "OK" # Create the tarball cd "$blender_srcdir" echo -n "Creating archive: \"$BASE_DIR/$TARBALL\" ..." -GZIP=-9 tar --transform "s,^,blender-$VERSION/,g" -zcf "$BASE_DIR/$TARBALL" -T "$BASE_DIR/$MANIFEST" +tar --transform "s,^,blender-$VERSION/,g" \ + --use-compress-program="gzip --best" \ + --create \ + --file="$BASE_DIR/$TARBALL" \ + --files-from="$BASE_DIR/$MANIFEST" echo "OK" diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index 8b3a97816ba..a3ccf9227d3 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = Blender # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "V2.8x" +PROJECT_NUMBER = "V2.79" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/doc/doxygen/doxygen.source.h b/doc/doxygen/doxygen.source.h index 3ef20466664..67e231212c7 100644 --- a/doc/doxygen/doxygen.source.h +++ b/doc/doxygen/doxygen.source.h @@ -160,9 +160,6 @@ * merged in docs. */ -/** \defgroup quicktime QuickTime - * \ingroup blender - /** \defgroup gui GUI */ /** \defgroup wm Window Manager diff --git a/doc/python_api/rst/bge_types/bge.types.BL_ShapeActionActuator.rst b/doc/python_api/rst/bge_types/bge.types.BL_ShapeActionActuator.rst index d08a761ed95..4bb3d273cb9 100644 --- a/doc/python_api/rst/bge_types/bge.types.BL_ShapeActionActuator.rst +++ b/doc/python_api/rst/bge_types/bge.types.BL_ShapeActionActuator.rst @@ -59,7 +59,7 @@ base class --- :class:`SCA_IActuator` .. attribute:: mode - The operation mode of the actuator. Can be one of :ref:`these constants<shape-action-actuator>`. + The operation mode of the actuator. Can be one of :ref:`these constants<action-actuator>`. :type: integer @@ -68,5 +68,3 @@ base class --- :class:`SCA_IActuator` The name of the property that is set to the current frame number. :type: string - - diff --git a/doc/python_api/rst/change_log.rst b/doc/python_api/rst/change_log.rst index 5a3bf2a6d8d..21c7cf96135 100644 --- a/doc/python_api/rst/change_log.rst +++ b/doc/python_api/rst/change_log.rst @@ -1,3 +1,5 @@ +:tocdepth: 2 + Blender API Change Log ********************** @@ -5648,3 +5650,5652 @@ Added * :class:`bpy.types.SceneRenderLayer.freestyle_settings` * :class:`bpy.types.SceneRenderLayer.use_freestyle` + +2.67 to 2.68 +============ + +bpy.types.BlendDataTexts +------------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataTexts.load` (filepath, internal), *was (filepath)* + +bpy.types.DopeSheet +------------------- + +Added +^^^^^ + +* :class:`bpy.types.DopeSheet.show_modifiers` + +bpy.types.Armature +------------------ + +Added +^^^^^ + +* :class:`bpy.types.Armature.is_editmode` + +bpy.types.Curve +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Curve.is_editmode` + +bpy.types.Lattice +----------------- + +Added +^^^^^ + +* :class:`bpy.types.Lattice.is_editmode` + +bpy.types.Mesh +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Mesh.calc_smooth_groups` +* :class:`bpy.types.Mesh.is_editmode` + +bpy.types.MetaBall +------------------ + +Added +^^^^^ + +* :class:`bpy.types.MetaBall.is_editmode` + +bpy.types.ParticleSettings +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ParticleSettings.use_modifier_stack` + +bpy.types.WindowManager +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.WindowManager.popup_menu` +* :class:`bpy.types.WindowManager.pupmenu_begin__internal` +* :class:`bpy.types.WindowManager.pupmenu_end__internal` + +bpy.types.World +--------------- + +Added +^^^^^ + +* :class:`bpy.types.World.cycles_visibility` + +bpy.types.MaskSpline +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.MaskSpline.points` + +bpy.types.MaskSplines +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.MaskSplines.new` +* :class:`bpy.types.MaskSplines.remove` + +Removed +^^^^^^^ + +* **add** + +bpy.types.MeshPolygon +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.MeshPolygon.center` + +bpy.types.DecimateModifier +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.DecimateModifier.delimit` + +bpy.types.MovieTrackingSettings +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.MovieTrackingSettings.use_keyframe_selection` + +bpy.types.Node +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Node.dimensions` + +bpy.types.NodeSocket +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.NodeSocket.hide_value` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.NodeSocket.draw` (context, layout, node, text), *was (context, layout, node)* + +bpy.types.NodeSocketStandard +---------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.NodeSocketStandard.draw` (context, layout, node, text), *was (context, layout, node)* + +bpy.types.NodeSocketInterfaceStandard +------------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.NodeSocketInterfaceStandard.type` + +bpy.types.NodeTreeInputs +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.NodeTreeInputs.move` + +bpy.types.NodeTreeOutputs +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.NodeTreeOutputs.move` + +bpy.types.CyclesMaterialSettings +-------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesMaterialSettings.use_transparent_shadow` + +bpy.types.CyclesRenderSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesRenderSettings.sampling_pattern` + +bpy.types.RenderEngine +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderEngine.bl_use_exclude_layers` +* :class:`bpy.types.RenderEngine.bl_use_save_buffers` + +bpy.types.SmokeDomainSettings +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SmokeDomainSettings.highres_sampling` + +Removed +^^^^^^^ + +* **use_smooth_emitter** + +bpy.types.SmokeFlowSettings +--------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SmokeFlowSettings.particle_size` +* :class:`bpy.types.SmokeFlowSettings.subframes` +* :class:`bpy.types.SmokeFlowSettings.use_particle_size` + +bpy.types.SpaceProperties +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceProperties.use_limited_texture_context` + +bpy.types.SpaceView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceView3D.transform_manipulators` + +Removed +^^^^^^^ + +* **use_manipulator_rotate** +* **use_manipulator_scale** +* **use_manipulator_translate** + +bpy.types.ThemeFontStyle +------------------------ + +Renamed +^^^^^^^ + +* **shadowalpha** -> :class:`bpy.types.ThemeFontStyle.shadow_alpha` +* **shadowcolor** -> :class:`bpy.types.ThemeFontStyle.shadow_value` + +bpy.types.ThemeView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeView3D.wire_edit` + +bpy.types.ToolSettings +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.ToolSettings.vertex_group_subset` + +bpy.types.UserPreferences +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferences.autoexec_paths` + +2.68 to 2.69 +============ + +bpy.types.ActionActuator +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.ActionActuator.blend_mode` + +bpy.types.ColorManagedViewSettings +---------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ColorManagedViewSettings.look` + +bpy.types.ShrinkwrapConstraint +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.ShrinkwrapConstraint.project_axis` +* :class:`bpy.types.ShrinkwrapConstraint.project_axis_space` +* :class:`bpy.types.ShrinkwrapConstraint.project_limit` + +Removed +^^^^^^^ + +* **use_x** +* **use_y** +* **use_z** + +bpy.types.CurveMapping +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.CurveMapping.initialize` + +bpy.types.DynamicPaintSurface +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.DynamicPaintSurface.wave_smoothness` + +bpy.types.Mesh +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Mesh.calc_normals_split` +* :class:`bpy.types.Mesh.free_normals_split` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Mesh.calc_smooth_groups` (use_bitflags), *was ()* + +bpy.types.Scene +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Scene.frame_current_final` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Scene.collada_export` (filepath, apply_modifiers, export_mesh_type, selected, include_children, include_armatures, include_shapekeys, deform_bones_only, active_uv_only, include_uv_textures, include_material_textures, use_texture_copies, use_ngons, use_object_instantiation, sort_by_name, open_sim, export_transformation_type), *was (filepath, apply_modifiers, export_mesh_type, selected, include_children, include_armatures, include_shapekeys, deform_bones_only, active_uv_only, include_uv_textures, include_material_textures, use_texture_copies, use_ngons, use_object_instantiation, sort_by_name, second_life, export_transformation_type)* + +bpy.types.Text +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Text.current_line_index` + +bpy.types.IDMaterials +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.IDMaterials.clear` + +bpy.types.KeyMaps +----------------- + +Added +^^^^^ + +* :class:`bpy.types.KeyMaps.remove` + +bpy.types.MaskParent +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.MaskParent.type` + +bpy.types.MeshLoop +------------------ + +Added +^^^^^ + +* :class:`bpy.types.MeshLoop.normal` + +bpy.types.SimpleDeformModifier +------------------------------ + +Removed +^^^^^^^ + +* **use_relative** + +bpy.types.MovieTracking +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.MovieTracking.plane_tracks` + +bpy.types.MovieTrackingObject +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.MovieTrackingObject.plane_tracks` + +bpy.types.ShaderNodeMapping +--------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeMapping.vector_type` + +bpy.types.ShaderNodeSubsurfaceScattering +---------------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeSubsurfaceScattering.falloff` + +bpy.types.ShaderNodeTexSky +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeTexSky.ground_albedo` +* :class:`bpy.types.ShaderNodeTexSky.sky_type` + +bpy.types.ParticleSystem +------------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.ParticleSystem.co_hair` (object, particle_no, step), *was (object, modifier, particle_no, step)* + +bpy.types.Property +------------------ + +Added +^^^^^ + +* :class:`bpy.types.Property.is_argument_optional` + +bpy.types.CyclesCurveRenderSettings +----------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesCurveRenderSettings.cull_backfacing` +* :class:`bpy.types.CyclesCurveRenderSettings.shape` + +Removed +^^^^^^^ + +* **encasing_ratio** +* **interpolation** +* **line_method** +* **normalmix** +* **preset** +* **segments** +* **triangle_method** +* **use_backfacing** +* **use_encasing** +* **use_joined** +* **use_parents** +* **use_smooth** +* **use_tangent_normal** +* **use_tangent_normal_correction** +* **use_tangent_normal_geometry** + +bpy.types.CyclesRenderSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesRenderSettings.use_square_samples` + +bpy.types.RenderEngine +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderEngine.bind_display_space_shader` +* :class:`bpy.types.RenderEngine.support_display_space_shader` +* :class:`bpy.types.RenderEngine.unbind_display_space_shader` + +bpy.types.RenderLayer +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderLayer.use_pass_subsurface_color` +* :class:`bpy.types.RenderLayer.use_pass_subsurface_direct` +* :class:`bpy.types.RenderLayer.use_pass_subsurface_indirect` + +bpy.types.SceneGameData +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.SceneGameData.vsync` + +bpy.types.SceneRenderLayer +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SceneRenderLayer.use_pass_subsurface_color` +* :class:`bpy.types.SceneRenderLayer.use_pass_subsurface_direct` +* :class:`bpy.types.SceneRenderLayer.use_pass_subsurface_indirect` + +bpy.types.SpaceNodeEditor +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceNodeEditor.cursor_location_from_region` + +bpy.types.SpaceTextEditor +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceTextEditor.top` +* :class:`bpy.types.SpaceTextEditor.visible_lines` + +bpy.types.SpaceView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceView3D.show_occlude_wire` + +bpy.types.TexMapping +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.TexMapping.vector_type` + +bpy.types.ThemeImageEditor +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeImageEditor.uv_others` +* :class:`bpy.types.ThemeImageEditor.uv_shadow` + +bpy.types.UILayout +------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.UILayout.template_list` (listtype_name, list_id, dataptr, propname, active_dataptr, active_propname, rows, maxrows, type, columns), *was (listtype_name, list_id, dataptr, propname, active_dataptr, active_propname, rows, maxrows, type)* + +bpy.types.UIList +---------------- + +Added +^^^^^ + +* :class:`bpy.types.UIList.bitflag_filter_item` +* :class:`bpy.types.UIList.draw_filter` +* :class:`bpy.types.UIList.filter_items` +* :class:`bpy.types.UIList.filter_name` +* :class:`bpy.types.UIList.use_filter_invert` +* :class:`bpy.types.UIList.use_filter_show` +* :class:`bpy.types.UIList.use_filter_sort_alpha` +* :class:`bpy.types.UIList.use_filter_sort_reverse` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.UIList.draw_item` (context, layout, data, item, icon, active_data, active_property, index, flt_flag), *was (context, layout, data, item, icon, active_data, active_property, index)* + +bpy.types.UI_UL_list +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.UI_UL_list.filter_items_by_name` +* :class:`bpy.types.UI_UL_list.sort_items_by_name` +* :class:`bpy.types.UI_UL_list.sort_items_helper` + +bpy.types.Window +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Window.cursor_modal_restore` +* :class:`bpy.types.Window.cursor_modal_set` +* :class:`bpy.types.Window.cursor_set` +* :class:`bpy.types.Window.cursor_warp` + +2.69 to 2.70 +============ + +bpy.types.BlendData +------------------- + +Added +^^^^^ + +* :class:`bpy.types.BlendData.use_autopack` + +bpy.types.ClothSettings +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.ClothSettings.sewing_force_max` +* :class:`bpy.types.ClothSettings.shrink_max` +* :class:`bpy.types.ClothSettings.shrink_min` +* :class:`bpy.types.ClothSettings.use_sewing_springs` +* :class:`bpy.types.ClothSettings.vertex_group_shrink` + +bpy.types.DupliObject +--------------------- + +Removed +^^^^^^^ + +* **matrix_original** + +bpy.types.FCurve +---------------- + +Added +^^^^^ + +* :class:`bpy.types.FCurve.update_autoflags` + +bpy.types.FModifierNoise +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.FModifierNoise.offset` + +bpy.types.FreestyleSettings +--------------------------- + +Removed +^^^^^^^ + +* **raycasting_algorithm** + +bpy.types.GameObjectSettings +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GameObjectSettings.use_record_animation` + +bpy.types.Armature +------------------ + +Added +^^^^^ + +* :class:`bpy.types.Armature.transform` + +bpy.types.Brush +--------------- + +Renamed +^^^^^^^ + +* **use_restore_mesh** -> :class:`bpy.types.Brush.use_drag_dot` + +bpy.types.Curve +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Curve.transform` + +Removed +^^^^^^^ + +* **use_time_offset** + +bpy.types.Image +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Image.filepath_from_user` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Image.gl_load` (frame, filter, mag), *was (filter, mag)* +* :class:`bpy.types.Image.gl_touch` (frame, filter, mag), *was (filter, mag)* + +bpy.types.Lattice +----------------- + +Added +^^^^^ + +* :class:`bpy.types.Lattice.transform` + +bpy.types.Mesh +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Mesh.calc_tangents` +* :class:`bpy.types.Mesh.free_tangents` + +bpy.types.Object +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Object.image_user` +* :class:`bpy.types.Object.lod_levels` + +bpy.types.ParticleSettings +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ParticleSettings.material_slot` + +bpy.types.Scene +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Scene.lock_frame_selection_to_range` + +bpy.types.Texture +----------------- + +Added +^^^^^ + +* :class:`bpy.types.Texture.use_clamp` + +bpy.types.World +--------------- + +Removed +^^^^^^^ + +* **star_settings** + +bpy.types.MaskLayer +------------------- + +Added +^^^^^ + +* :class:`bpy.types.MaskLayer.use_fill_holes` +* :class:`bpy.types.MaskLayer.use_fill_overlap` + +bpy.types.Menu +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Menu.draw_collapsible` + +bpy.types.MeshLoop +------------------ + +Added +^^^^^ + +* :class:`bpy.types.MeshLoop.bitangent` +* :class:`bpy.types.MeshLoop.bitangent_sign` +* :class:`bpy.types.MeshLoop.tangent` + +bpy.types.BevelModifier +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.BevelModifier.offset_type` +* :class:`bpy.types.BevelModifier.profile` + +bpy.types.BuildModifier +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.BuildModifier.use_reverse` + +bpy.types.ScrewModifier +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.ScrewModifier.use_stretch_u` +* :class:`bpy.types.ScrewModifier.use_stretch_v` + +bpy.types.TriangulateModifier +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.TriangulateModifier.ngon_method` +* :class:`bpy.types.TriangulateModifier.quad_method` + +Removed +^^^^^^^ + +* **use_beauty** + +bpy.types.MovieTrackingMarker +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.MovieTrackingMarker.is_keyed` + +bpy.types.MovieTrackingPlaneTrack +--------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.MovieTrackingPlaneTrack.image` +* :class:`bpy.types.MovieTrackingPlaneTrack.image_opacity` + +bpy.types.MovieTrackingSettings +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.MovieTrackingSettings.default_weight` +* :class:`bpy.types.MovieTrackingSettings.show_extra_expanded` + +Removed +^^^^^^^ + +* **reconstruction_success_threshold** +* **use_fallback_reconstruction** + +bpy.types.MovieTrackingTrack +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.MovieTrackingTrack.offset` +* :class:`bpy.types.MovieTrackingTrack.weight` + +bpy.types.Node +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Node.draw_label` + +bpy.types.CompositorNodeDefocus +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CompositorNodeDefocus.scene` + +bpy.types.CompositorNodeDespeckle +--------------------------------- + +Renamed +^^^^^^^ + +* **threshold_neighbour** -> :class:`bpy.types.CompositorNodeDespeckle.threshold_neighbor` + +bpy.types.ShaderNodeOutput +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeOutput.is_active_output` + +bpy.types.ShaderNodeOutputLamp +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeOutputLamp.is_active_output` + +bpy.types.ShaderNodeOutputMaterial +---------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeOutputMaterial.is_active_output` + +bpy.types.ShaderNodeOutputWorld +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeOutputWorld.is_active_output` + +bpy.types.NodeSocket +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.NodeSocket.is_output` + +Removed +^^^^^^^ + +* **in_out** + +bpy.types.NodeSocketInterface +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.NodeSocketInterface.is_output` + +Removed +^^^^^^^ + +* **in_out** + +bpy.types.Paint +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Paint.use_symmetry_feather` +* :class:`bpy.types.Paint.use_symmetry_x` +* :class:`bpy.types.Paint.use_symmetry_y` +* :class:`bpy.types.Paint.use_symmetry_z` + +bpy.types.Sculpt +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Sculpt.detail_refine_method` +* :class:`bpy.types.Sculpt.gravity` +* :class:`bpy.types.Sculpt.gravity_object` + +Removed +^^^^^^^ + +* **use_edge_collapse** +* **use_symmetry_feather** +* **use_symmetry_x** +* **use_symmetry_y** +* **use_symmetry_z** + +bpy.types.VertexPaint +--------------------- + +Removed +^^^^^^^ + +* **use_all_faces** + +bpy.types.Panel +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Panel.bl_category` +* :class:`bpy.types.Panel.use_pin` + +bpy.types.CyclesRenderSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesRenderSettings.sample_clamp_direct` +* :class:`bpy.types.CyclesRenderSettings.sample_clamp_indirect` +* :class:`bpy.types.CyclesRenderSettings.volume_bounces` +* :class:`bpy.types.CyclesRenderSettings.volume_homogeneous_sampling` +* :class:`bpy.types.CyclesRenderSettings.volume_max_steps` +* :class:`bpy.types.CyclesRenderSettings.volume_samples` +* :class:`bpy.types.CyclesRenderSettings.volume_step_size` + +Removed +^^^^^^^ + +* **sample_clamp** + +bpy.types.CyclesWorldSettings +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesWorldSettings.homogeneous_volume` + +bpy.types.RenderEngine +---------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.RenderEngine.end_result` (result, cancel, do_merge_results), *was (result, cancel)* + +bpy.types.RenderSettings +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.RenderSettings.bake_user_scale` +* :class:`bpy.types.RenderSettings.use_bake_user_scale` +* :class:`bpy.types.RenderSettings.use_lock_interface` + +bpy.types.RigidBodyObject +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.RigidBodyObject.mesh_source` +* :class:`bpy.types.RigidBodyObject.use_deform` + +bpy.types.SceneRenderLayer +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SceneRenderLayer.pass_alpha_threshold` + +bpy.types.SculptToolCapabilities +-------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SculptToolCapabilities.has_gravity` + +bpy.types.SpaceClipEditor +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceClipEditor.mask_overlay_mode` +* :class:`bpy.types.SpaceClipEditor.show_graph_tracks_error` +* :class:`bpy.types.SpaceClipEditor.show_mask_overlay` + +Renamed +^^^^^^^ + +* **show_graph_tracks** -> :class:`bpy.types.SpaceClipEditor.show_graph_tracks_motion` + +bpy.types.SpaceGraphEditor +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceGraphEditor.use_auto_normalization` +* :class:`bpy.types.SpaceGraphEditor.use_normalization` + +bpy.types.SpaceImageEditor +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceImageEditor.mask_overlay_mode` +* :class:`bpy.types.SpaceImageEditor.show_mask_overlay` + +bpy.types.SpaceNodeEditor +------------------------- + +Removed +^^^^^^^ + +* **use_hidden_preview** + +bpy.types.SpaceView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceView3D.show_textured_shadeless` + +bpy.types.TextCharacterFormat +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.TextCharacterFormat.material_index` + +bpy.types.ThemeDopeSheet +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.ThemeDopeSheet.keyframe` +* :class:`bpy.types.ThemeDopeSheet.keyframe_border` +* :class:`bpy.types.ThemeDopeSheet.keyframe_border_selected` +* :class:`bpy.types.ThemeDopeSheet.keyframe_breakdown` +* :class:`bpy.types.ThemeDopeSheet.keyframe_breakdown_selected` +* :class:`bpy.types.ThemeDopeSheet.keyframe_extreme` +* :class:`bpy.types.ThemeDopeSheet.keyframe_extreme_selected` +* :class:`bpy.types.ThemeDopeSheet.keyframe_jitter` +* :class:`bpy.types.ThemeDopeSheet.keyframe_jitter_selected` +* :class:`bpy.types.ThemeDopeSheet.keyframe_selected` + +bpy.types.ThemeImageEditor +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeImageEditor.edge_select` +* :class:`bpy.types.ThemeImageEditor.wire_edit` + +bpy.types.ThemeInfo +------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeInfo.info_debug` +* :class:`bpy.types.ThemeInfo.info_debug_text` +* :class:`bpy.types.ThemeInfo.info_error` +* :class:`bpy.types.ThemeInfo.info_error_text` +* :class:`bpy.types.ThemeInfo.info_info` +* :class:`bpy.types.ThemeInfo.info_info_text` +* :class:`bpy.types.ThemeInfo.info_selected` +* :class:`bpy.types.ThemeInfo.info_selected_text` +* :class:`bpy.types.ThemeInfo.info_warning` +* :class:`bpy.types.ThemeInfo.info_warning_text` + +bpy.types.ThemeNLAEditor +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.ThemeNLAEditor.keyframe_border` +* :class:`bpy.types.ThemeNLAEditor.keyframe_border_selected` + +bpy.types.ThemeNodeEditor +------------------------- + +Removed +^^^^^^^ + +* **in_out_node** + +Renamed +^^^^^^^ + +* **operator_node** -> :class:`bpy.types.ThemeNodeEditor.color_node` +* **operator_node** -> :class:`bpy.types.ThemeNodeEditor.filter_node` +* **operator_node** -> :class:`bpy.types.ThemeNodeEditor.input_node` +* **operator_node** -> :class:`bpy.types.ThemeNodeEditor.layout_node` +* **operator_node** -> :class:`bpy.types.ThemeNodeEditor.output_node` +* **operator_node** -> :class:`bpy.types.ThemeNodeEditor.pattern_node` +* **operator_node** -> :class:`bpy.types.ThemeNodeEditor.script_node` +* **operator_node** -> :class:`bpy.types.ThemeNodeEditor.shader_node` +* **operator_node** -> :class:`bpy.types.ThemeNodeEditor.texture_node` +* **operator_node** -> :class:`bpy.types.ThemeNodeEditor.vector_node` + +bpy.types.ThemeSpaceGeneric +--------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeSpaceGeneric.tab_active` +* :class:`bpy.types.ThemeSpaceGeneric.tab_back` +* :class:`bpy.types.ThemeSpaceGeneric.tab_inactive` +* :class:`bpy.types.ThemeSpaceGeneric.tab_outline` + +bpy.types.ThemeSpaceGradient +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeSpaceGradient.tab_active` +* :class:`bpy.types.ThemeSpaceGradient.tab_back` +* :class:`bpy.types.ThemeSpaceGradient.tab_inactive` +* :class:`bpy.types.ThemeSpaceGradient.tab_outline` + +bpy.types.TimelineMarkers +------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.TimelineMarkers.new` (name, frame), *was (name)* + +bpy.types.UILayout +------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.UILayout.prop` (data, property, text, text_ctxt, translate, icon, expand, slider, toggle, icon_only, event, full_event, emboss, index, icon_value), *was (data, property, text, text_ctxt, translate, icon, expand, slider, toggle, icon_only, event, full_event, emboss, index)* +* :class:`bpy.types.UILayout.template_header` (), *was (menus)* + +bpy.types.UserPreferencesEdit +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesEdit.grease_pencil_default_color` + +bpy.types.UserPreferencesInput +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesInput.navigation_mode` +* :class:`bpy.types.UserPreferencesInput.ndof_pan_yz_swap_axis` +* :class:`bpy.types.UserPreferencesInput.ndof_rotx_invert_axis` +* :class:`bpy.types.UserPreferencesInput.ndof_roty_invert_axis` +* :class:`bpy.types.UserPreferencesInput.ndof_rotz_invert_axis` +* :class:`bpy.types.UserPreferencesInput.ndof_view_navigate_method` +* :class:`bpy.types.UserPreferencesInput.walk_navigation` + +Removed +^^^^^^^ + +* **ndof_roll_invert_axis** +* **ndof_rotate_invert_axis** +* **ndof_tilt_invert_axis** +* **ndof_zoom_updown** + +2.70 to 2.71 +============ + +bpy.types.Actuator +------------------ + +Added +^^^^^ + +* :class:`bpy.types.Actuator.active` + +bpy.types.BlendDataLineStyles +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.BlendDataLineStyles.is_updated` + +bpy.types.TransformConstraint +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.TransformConstraint.from_max_x_rot` +* :class:`bpy.types.TransformConstraint.from_max_x_scale` +* :class:`bpy.types.TransformConstraint.from_max_y_rot` +* :class:`bpy.types.TransformConstraint.from_max_y_scale` +* :class:`bpy.types.TransformConstraint.from_max_z_rot` +* :class:`bpy.types.TransformConstraint.from_max_z_scale` +* :class:`bpy.types.TransformConstraint.from_min_x_rot` +* :class:`bpy.types.TransformConstraint.from_min_x_scale` +* :class:`bpy.types.TransformConstraint.from_min_y_rot` +* :class:`bpy.types.TransformConstraint.from_min_y_scale` +* :class:`bpy.types.TransformConstraint.from_min_z_rot` +* :class:`bpy.types.TransformConstraint.from_min_z_scale` +* :class:`bpy.types.TransformConstraint.to_max_x_rot` +* :class:`bpy.types.TransformConstraint.to_max_x_scale` +* :class:`bpy.types.TransformConstraint.to_max_y_rot` +* :class:`bpy.types.TransformConstraint.to_max_y_scale` +* :class:`bpy.types.TransformConstraint.to_max_z_rot` +* :class:`bpy.types.TransformConstraint.to_max_z_scale` +* :class:`bpy.types.TransformConstraint.to_min_x_rot` +* :class:`bpy.types.TransformConstraint.to_min_x_scale` +* :class:`bpy.types.TransformConstraint.to_min_y_rot` +* :class:`bpy.types.TransformConstraint.to_min_y_scale` +* :class:`bpy.types.TransformConstraint.to_min_z_rot` +* :class:`bpy.types.TransformConstraint.to_min_z_scale` + +bpy.types.Controller +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.Controller.active` + +bpy.types.FCurve +---------------- + +Added +^^^^^ + +* :class:`bpy.types.FCurve.update` + +bpy.types.Brush +--------------- + +Removed +^^^^^^^ + +* **sculpt_stroke_method** + +bpy.types.Curve +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Curve.bevel_factor_mapping_end` +* :class:`bpy.types.Curve.bevel_factor_mapping_start` + +bpy.types.FreestyleLineStyle +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.FreestyleLineStyle.active_texture` +* :class:`bpy.types.FreestyleLineStyle.active_texture_index` +* :class:`bpy.types.FreestyleLineStyle.integration_type` +* :class:`bpy.types.FreestyleLineStyle.node_tree` +* :class:`bpy.types.FreestyleLineStyle.sort_key` +* :class:`bpy.types.FreestyleLineStyle.sort_order` +* :class:`bpy.types.FreestyleLineStyle.texture_slots` +* :class:`bpy.types.FreestyleLineStyle.texture_spacing` +* :class:`bpy.types.FreestyleLineStyle.use_nodes` +* :class:`bpy.types.FreestyleLineStyle.use_sorting` +* :class:`bpy.types.FreestyleLineStyle.use_texture` + +bpy.types.Material +------------------ + +Added +^^^^^ + +* :class:`bpy.types.Material.use_cast_shadows` + +bpy.types.Mesh +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Mesh.show_normal_loop` + +bpy.types.Object +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Object.cycles` + +bpy.types.Scene +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Scene.show_keys_from_selected_only` + +bpy.types.Speaker +----------------- + +Added +^^^^^ + +* :class:`bpy.types.Speaker.relative` + +bpy.types.Keyframe +------------------ + +Added +^^^^^ + +* :class:`bpy.types.Keyframe.amplitude` +* :class:`bpy.types.Keyframe.back` +* :class:`bpy.types.Keyframe.easing` +* :class:`bpy.types.Keyframe.period` + +bpy.types.Linesets +------------------ + +Added +^^^^^ + +* :class:`bpy.types.Linesets.new` +* :class:`bpy.types.Linesets.remove` + +bpy.types.MaskSplinePoint +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.MaskSplinePoint.handle_left_type` +* :class:`bpy.types.MaskSplinePoint.handle_right_type` +* :class:`bpy.types.MaskSplinePoint.weight` + +bpy.types.MeshEdge +------------------ + +Added +^^^^^ + +* :class:`bpy.types.MeshEdge.use_freestyle_mark` + +bpy.types.MeshPolygon +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.MeshPolygon.use_freestyle_mark` + +bpy.types.MeshTessFace +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.MeshTessFace.split_normals` + +bpy.types.MovieTrackingCamera +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.MovieTrackingCamera.distortion_model` +* :class:`bpy.types.MovieTrackingCamera.division_k1` +* :class:`bpy.types.MovieTrackingCamera.division_k2` + +bpy.types.ShaderNodeTexImage +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeTexImage.interpolation` + +bpy.types.PackedFile +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.PackedFile.data` + +bpy.types.Sculpt +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Sculpt.constant_detail` +* :class:`bpy.types.Sculpt.detail_type_method` + +bpy.types.CyclesRenderSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesRenderSettings.bake_type` +* :class:`bpy.types.CyclesRenderSettings.sample_all_lights_direct` +* :class:`bpy.types.CyclesRenderSettings.sample_all_lights_indirect` + +bpy.types.RenderEngine +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderEngine.bake` +* :class:`bpy.types.RenderEngine.frame_set` + +bpy.types.CYCLES +---------------- + +Added +^^^^^ + +* :class:`bpy.types.CYCLES.bake` + +bpy.types.RenderSettings +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.RenderSettings.bake` + +bpy.types.Sensor +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Sensor.active` + +bpy.types.SequenceElements +-------------------------- + +Renamed +^^^^^^^ + +* **push** -> :class:`bpy.types.SequenceElements.append` + +bpy.types.SmokeDomainSettings +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SmokeDomainSettings.color_grid` +* :class:`bpy.types.SmokeDomainSettings.density_grid` +* :class:`bpy.types.SmokeDomainSettings.flame_grid` + +Removed +^^^^^^^ + +* **density** + +bpy.types.Space +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Space.show_locked_time` + +bpy.types.SpaceTimeline +----------------------- + +Removed +^^^^^^^ + +* **show_only_selected** + +bpy.types.SpaceView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceView3D.region_quadviews` + +Removed +^^^^^^^ + +* **region_quadview** + +bpy.types.SpaceNodeEditorPath +----------------------------- + +Renamed +^^^^^^^ + +* **push** -> :class:`bpy.types.SpaceNodeEditorPath.append` + +bpy.types.ThemeClipEditor +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeClipEditor.handle_align` +* :class:`bpy.types.ThemeClipEditor.handle_auto` +* :class:`bpy.types.ThemeClipEditor.handle_auto_clamped` +* :class:`bpy.types.ThemeClipEditor.handle_free` +* :class:`bpy.types.ThemeClipEditor.handle_sel_align` +* :class:`bpy.types.ThemeClipEditor.handle_sel_auto` +* :class:`bpy.types.ThemeClipEditor.handle_sel_auto_clamped` +* :class:`bpy.types.ThemeClipEditor.handle_sel_free` + +bpy.types.ThemeImageEditor +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeImageEditor.frame_current` +* :class:`bpy.types.ThemeImageEditor.handle_align` +* :class:`bpy.types.ThemeImageEditor.handle_auto` +* :class:`bpy.types.ThemeImageEditor.handle_auto_clamped` +* :class:`bpy.types.ThemeImageEditor.handle_free` +* :class:`bpy.types.ThemeImageEditor.handle_sel_align` +* :class:`bpy.types.ThemeImageEditor.handle_sel_auto` +* :class:`bpy.types.ThemeImageEditor.handle_sel_auto_clamped` +* :class:`bpy.types.ThemeImageEditor.handle_sel_free` + +bpy.types.ThemeView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeView3D.view_overlay` + +bpy.types.UILayout +------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.UILayout.template_preview` (id, show_buttons, parent, slot, preview_id), *was (id, show_buttons, parent, slot)* + +2.71 to 2.72 +============ + +bpy.types.EditObjectActuator +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.EditObjectActuator.track_axis` +* :class:`bpy.types.EditObjectActuator.up_axis` + +bpy.types.BlendData +------------------- + +Added +^^^^^ + +* :class:`bpy.types.BlendData.version` + +bpy.types.BoneGroups +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.BoneGroups.new` +* :class:`bpy.types.BoneGroups.remove` + +bpy.types.BrushCapabilities +--------------------------- + +Added +^^^^^ + +* :class:`bpy.types.BrushCapabilities.has_smooth_stroke` + +bpy.types.ColorRamp +------------------- + +Added +^^^^^ + +* :class:`bpy.types.ColorRamp.color_mode` +* :class:`bpy.types.ColorRamp.hue_interpolation` + +bpy.types.ColorRampElement +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ColorRampElement.alpha` + +bpy.types.FollowTrackConstraint +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.FollowTrackConstraint.use_undistorted_position` + +bpy.types.Event +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Event.is_tablet` +* :class:`bpy.types.Event.pressure` +* :class:`bpy.types.Event.tilt` + +bpy.types.Brush +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Brush.blur_kernel_radius` +* :class:`bpy.types.Brush.blur_mode` +* :class:`bpy.types.Brush.fill_threshold` +* :class:`bpy.types.Brush.grad_spacing` +* :class:`bpy.types.Brush.gradient` +* :class:`bpy.types.Brush.gradient_fill_mode` +* :class:`bpy.types.Brush.gradient_stroke_mode` +* :class:`bpy.types.Brush.image_paint_capabilities` +* :class:`bpy.types.Brush.paint_curve` +* :class:`bpy.types.Brush.secondary_color` +* :class:`bpy.types.Brush.sharp_threshold` +* :class:`bpy.types.Brush.use_curve` +* :class:`bpy.types.Brush.use_gradient` +* :class:`bpy.types.Brush.use_line` +* :class:`bpy.types.Brush.use_pressure_masking` + +Renamed +^^^^^^^ + +* **use_drag_dot** -> :class:`bpy.types.Brush.use_restore_mesh` + +bpy.types.Curve +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Curve.validate_material_indices` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Curve.transform` (matrix, shape_keys), *was (matrix)* + +bpy.types.Lattice +----------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Lattice.transform` (matrix, shape_keys), *was (matrix)* + +bpy.types.Library +----------------- + +Added +^^^^^ + +* :class:`bpy.types.Library.packed_file` + +bpy.types.Material +------------------ + +Added +^^^^^ + +* :class:`bpy.types.Material.line_color` +* :class:`bpy.types.Material.line_priority` +* :class:`bpy.types.Material.paint_active_slot` +* :class:`bpy.types.Material.paint_clone_slot` +* :class:`bpy.types.Material.texture_paint_images` +* :class:`bpy.types.Material.texture_paint_slots` + +bpy.types.Mesh +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Mesh.validate_material_indices` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Mesh.transform` (matrix, shape_keys), *was (matrix)* + +bpy.types.WindowManager +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.WindowManager.piemenu_begin__internal` +* :class:`bpy.types.WindowManager.piemenu_end__internal` +* :class:`bpy.types.WindowManager.popup_menu_pie` + +bpy.types.BevelModifier +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.BevelModifier.material` + +bpy.types.HookModifier +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.HookModifier.center` + +bpy.types.SolidifyModifier +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SolidifyModifier.use_rim_only` + +bpy.types.ShaderNodeBsdfAnisotropic +----------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeBsdfAnisotropic.distribution` + +bpy.types.Paint +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Paint.palette` + +bpy.types.ImagePaint +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.ImagePaint.canvas` +* :class:`bpy.types.ImagePaint.clone_image` +* :class:`bpy.types.ImagePaint.detect_data` +* :class:`bpy.types.ImagePaint.missing_materials` +* :class:`bpy.types.ImagePaint.missing_stencil` +* :class:`bpy.types.ImagePaint.missing_texture` +* :class:`bpy.types.ImagePaint.missing_uvs` +* :class:`bpy.types.ImagePaint.mode` +* :class:`bpy.types.ImagePaint.stencil_color` +* :class:`bpy.types.ImagePaint.stencil_image` + +bpy.types.IMAGE_UV_sculpt +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.IMAGE_UV_sculpt.prop_unified_color` +* :class:`bpy.types.IMAGE_UV_sculpt.prop_unified_color_picker` + +bpy.types.CyclesCameraSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesCameraSettings.aperture_ratio` + +bpy.types.CyclesMaterialSettings +-------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesMaterialSettings.volume_sampling` + +bpy.types.CyclesRenderSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesRenderSettings.caustics_reflective` +* :class:`bpy.types.CyclesRenderSettings.caustics_refractive` + +Removed +^^^^^^^ + +* **no_caustics** +* **volume_homogeneous_sampling** + +bpy.types.CyclesVisibilitySettings +---------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesVisibilitySettings.scatter` + +bpy.types.CyclesWorldSettings +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesWorldSettings.volume_sampling` + +bpy.types.OperatorStrokeElement +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.OperatorStrokeElement.size` + +bpy.types.RenderEngine +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderEngine.bl_use_texture_preview` +* :class:`bpy.types.RenderEngine.layer_override` + +bpy.types.RenderSettings +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.RenderSettings.preview_start_resolution` +* :class:`bpy.types.RenderSettings.use_render_cache` + +bpy.types.MouseSensor +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.MouseSensor.material` +* :class:`bpy.types.MouseSensor.property` +* :class:`bpy.types.MouseSensor.use_material` +* :class:`bpy.types.MouseSensor.use_x_ray` + +bpy.types.SpaceUVEditor +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceUVEditor.show_texpaint` + +bpy.types.ThemeImageEditor +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeImageEditor.handle_vertex` +* :class:`bpy.types.ThemeImageEditor.handle_vertex_select` +* :class:`bpy.types.ThemeImageEditor.handle_vertex_size` +* :class:`bpy.types.ThemeImageEditor.paint_curve_handle` +* :class:`bpy.types.ThemeImageEditor.paint_curve_pivot` + +bpy.types.ThemeUserInterface +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeUserInterface.wcol_pie_menu` + +bpy.types.ThemeView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeView3D.paint_curve_handle` +* :class:`bpy.types.ThemeView3D.paint_curve_pivot` +* :class:`bpy.types.ThemeView3D.split_normal` + +bpy.types.UILayout +------------------ + +Added +^^^^^ + +* :class:`bpy.types.UILayout.menu_pie` +* :class:`bpy.types.UILayout.template_palette` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.UILayout.template_curve_mapping` (data, property, type, levels, brush, use_negative_slope), *was (data, property, type, levels, brush)* + +bpy.types.UnifiedPaintSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.UnifiedPaintSettings.color` +* :class:`bpy.types.UnifiedPaintSettings.secondary_color` +* :class:`bpy.types.UnifiedPaintSettings.use_unified_color` + +bpy.types.UserPreferencesFilePaths +---------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesFilePaths.render_cache_directory` + +bpy.types.UserPreferencesSystem +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesSystem.font_path_ui` +* :class:`bpy.types.UserPreferencesSystem.is_occlusion_query_supported` +* :class:`bpy.types.UserPreferencesSystem.select_method` + +bpy.types.UserPreferencesView +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesView.pie_animation_timeout` +* :class:`bpy.types.UserPreferencesView.pie_initial_timeout` +* :class:`bpy.types.UserPreferencesView.pie_menu_radius` +* :class:`bpy.types.UserPreferencesView.pie_menu_threshold` + +2.72 to 2.73 +============ + +bpy.types.ActionGroup +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.ActionGroup.is_custom_color_set` + +bpy.types.BoneGroup +------------------- + +Added +^^^^^ + +* :class:`bpy.types.BoneGroup.is_custom_color_set` + +bpy.types.StretchToConstraint +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.StretchToConstraint.bulge_max` +* :class:`bpy.types.StretchToConstraint.bulge_min` +* :class:`bpy.types.StretchToConstraint.bulge_smooth` +* :class:`bpy.types.StretchToConstraint.use_bulge_max` +* :class:`bpy.types.StretchToConstraint.use_bulge_min` + +bpy.types.DopeSheet +------------------- + +Added +^^^^^ + +* :class:`bpy.types.DopeSheet.show_gpencil` + +bpy.types.FreestyleSettings +--------------------------- + +Added +^^^^^ + +* :class:`bpy.types.FreestyleSettings.use_view_map_cache` + +bpy.types.GPencilLayer +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPencilLayer.after_color` +* :class:`bpy.types.GPencilLayer.before_color` +* :class:`bpy.types.GPencilLayer.fill_alpha` +* :class:`bpy.types.GPencilLayer.fill_color` +* :class:`bpy.types.GPencilLayer.ghost_after_range` +* :class:`bpy.types.GPencilLayer.ghost_before_range` +* :class:`bpy.types.GPencilLayer.use_ghost_custom_colors` +* :class:`bpy.types.GPencilLayer.use_volumetric_strokes` + +Removed +^^^^^^^ + +* **ghost_range_max** + +bpy.types.GPencilStroke +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPencilStroke.select` + +bpy.types.GPencilStrokePoint +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPencilStrokePoint.select` + +bpy.types.GreasePencilLayers +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GreasePencilLayers.active_index` + +bpy.types.FreestyleLineStyle +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.FreestyleLineStyle.chain_count` +* :class:`bpy.types.FreestyleLineStyle.use_chain_count` + +bpy.types.GreasePencil +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.GreasePencil.animation_data` +* :class:`bpy.types.GreasePencil.use_stroke_edit_mode` + +bpy.types.Image +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Image.generated_color` +* :class:`bpy.types.Image.render_slots` + +Removed +^^^^^^^ + +* **render_slot** + +bpy.types.Scene +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Scene.uvedit_aspect` + +bpy.types.CyclesLampSettings +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesLampSettings.max_bounces` + +bpy.types.CyclesMaterialSettings +-------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesMaterialSettings.volume_interpolation` + +bpy.types.CyclesWorldSettings +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesWorldSettings.volume_interpolation` + +bpy.types.RenderEngine +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderEngine.error_set` + +bpy.types.RenderPass +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderPass.debug_type` + +bpy.types.SculptToolCapabilities +-------------------------------- + +Renamed +^^^^^^^ + +* **has_strength** -> :class:`bpy.types.SculptToolCapabilities.has_strength_pressure` + +bpy.types.SceneSequence +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.SceneSequence.use_grease_pencil` + +bpy.types.SpaceSequenceEditor +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceSequenceEditor.show_backdrop` +* :class:`bpy.types.SpaceSequenceEditor.show_strip_offset` +* :class:`bpy.types.SpaceSequenceEditor.waveform_draw_type` + +bpy.types.SpaceView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceView3D.show_world` + +bpy.types.ThemeClipEditor +------------------------- + +Removed +^^^^^^^ + +* **grid** + +bpy.types.ThemeNodeEditor +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeNodeEditor.wire_inner` + +bpy.types.ThemeUserInterface +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeUserInterface.widget_emboss` + +bpy.types.ToolSettings +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.ToolSettings.grease_pencil_source` + +bpy.types.UILayout +------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.UILayout.operator` (operator, text, text_ctxt, translate, icon, emboss, icon_value), *was (operator, text, text_ctxt, translate, icon, emboss)* + +bpy.types.UserPreferencesSystem +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesSystem.virtual_pixel_mode` + +bpy.types.UserPreferencesView +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesView.pie_menu_confirm` + +2.73 to 2.74 +============ + +bpy.types.SteeringActuator +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SteeringActuator.lock_z_velocity` + +bpy.types.BackgroundImage +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.BackgroundImage.rotation` +* :class:`bpy.types.BackgroundImage.use_flip_x` +* :class:`bpy.types.BackgroundImage.use_flip_y` + +bpy.types.BrushCapabilities +--------------------------- + +Removed +^^^^^^^ + +* **has_texture_angle** +* **has_texture_angle_source** + +bpy.types.ClothCollisionSettings +-------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ClothCollisionSettings.damping` + +bpy.types.ClothSettings +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.ClothSettings.bending_damping` +* :class:`bpy.types.ClothSettings.density_strength` +* :class:`bpy.types.ClothSettings.density_target` +* :class:`bpy.types.ClothSettings.voxel_cell_size` + +Removed +^^^^^^^ + +* **pre_roll** + +bpy.types.SplineIKConstraint +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SplineIKConstraint.bulge` +* :class:`bpy.types.SplineIKConstraint.bulge_max` +* :class:`bpy.types.SplineIKConstraint.bulge_min` +* :class:`bpy.types.SplineIKConstraint.bulge_smooth` +* :class:`bpy.types.SplineIKConstraint.use_bulge_max` +* :class:`bpy.types.SplineIKConstraint.use_bulge_min` + +bpy.types.FCurve +---------------- + +Added +^^^^^ + +* :class:`bpy.types.FCurve.convert_to_keyframes` +* :class:`bpy.types.FCurve.convert_to_samples` + +bpy.types.FileSelectParams +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.FileSelectParams.filter_search` + +bpy.types.GPencilLayer +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPencilLayer.is_fill_visible` +* :class:`bpy.types.GPencilLayer.is_stroke_visible` + +bpy.types.Brush +--------------- + +Removed +^^^^^^^ + +* **texture_angle_source_no_random** +* **texture_angle_source_random** +* **use_rake** +* **use_random_rotation** + +bpy.types.Camera +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Camera.gpu_dof` +* :class:`bpy.types.Camera.show_safe_center` + +Renamed +^^^^^^^ + +* **show_title_safe** -> :class:`bpy.types.Camera.show_safe_areas` + +bpy.types.Image +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Image.use_deinterlace` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Image.pack` (as_png, data, data_len), *was (as_png)* + +bpy.types.Key +------------- + +Removed +^^^^^^^ + +* **slurph** + +bpy.types.Mesh +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Mesh.create_normals_split` +* :class:`bpy.types.Mesh.has_custom_normals` +* :class:`bpy.types.Mesh.normals_split_custom_set` +* :class:`bpy.types.Mesh.normals_split_custom_set_from_vertices` +* :class:`bpy.types.Mesh.vertex_layers_float` +* :class:`bpy.types.Mesh.vertex_layers_int` +* :class:`bpy.types.Mesh.vertex_layers_string` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Mesh.calc_normals_split` (), *was (split_angle)* +* :class:`bpy.types.Mesh.validate` (verbose, clean_customdata), *was (verbose)* + +bpy.types.Object +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Object.calc_matrix_camera` +* :class:`bpy.types.Object.camera_fit_coords` + +bpy.types.ParticleSettings +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ParticleSettings.bending_random` +* :class:`bpy.types.ParticleSettings.clump_curve` +* :class:`bpy.types.ParticleSettings.clump_noise_size` +* :class:`bpy.types.ParticleSettings.kink_amplitude_random` +* :class:`bpy.types.ParticleSettings.kink_axis_random` +* :class:`bpy.types.ParticleSettings.kink_extra_steps` +* :class:`bpy.types.ParticleSettings.roughness_curve` +* :class:`bpy.types.ParticleSettings.show_guide_hairs` +* :class:`bpy.types.ParticleSettings.show_hair_grid` +* :class:`bpy.types.ParticleSettings.use_clump_curve` +* :class:`bpy.types.ParticleSettings.use_clump_noise` +* :class:`bpy.types.ParticleSettings.use_roughness_curve` + +bpy.types.Scene +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Scene.safe_areas` + +bpy.types.Screen +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Screen.use_follow` + +bpy.types.Sound +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Sound.pack` +* :class:`bpy.types.Sound.unpack` + +bpy.types.VectorFont +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.VectorFont.pack` +* :class:`bpy.types.VectorFont.unpack` + +bpy.types.KeyingSet +------------------- + +Added +^^^^^ + +* :class:`bpy.types.KeyingSet.use_insertkey_needed` +* :class:`bpy.types.KeyingSet.use_insertkey_override_needed` +* :class:`bpy.types.KeyingSet.use_insertkey_override_visual` +* :class:`bpy.types.KeyingSet.use_insertkey_override_xyz_to_rgb` +* :class:`bpy.types.KeyingSet.use_insertkey_visual` +* :class:`bpy.types.KeyingSet.use_insertkey_xyz_to_rgb` + +Removed +^^^^^^^ + +* **bl_options** + +bpy.types.KeyingSetPath +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.KeyingSetPath.use_insertkey_needed` +* :class:`bpy.types.KeyingSetPath.use_insertkey_override_needed` +* :class:`bpy.types.KeyingSetPath.use_insertkey_override_visual` +* :class:`bpy.types.KeyingSetPath.use_insertkey_override_xyz_to_rgb` +* :class:`bpy.types.KeyingSetPath.use_insertkey_visual` +* :class:`bpy.types.KeyingSetPath.use_insertkey_xyz_to_rgb` + +Removed +^^^^^^^ + +* **bl_options** + +bpy.types.ClothModifier +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.ClothModifier.hair_grid_max` +* :class:`bpy.types.ClothModifier.hair_grid_min` +* :class:`bpy.types.ClothModifier.hair_grid_resolution` +* :class:`bpy.types.ClothModifier.solver_result` + +bpy.types.HookModifier +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.HookModifier.falloff_curve` +* :class:`bpy.types.HookModifier.falloff_type` +* :class:`bpy.types.HookModifier.use_falloff_uniform` + +Renamed +^^^^^^^ + +* **falloff** -> :class:`bpy.types.HookModifier.falloff_radius` +* **force** -> :class:`bpy.types.HookModifier.strength` + +bpy.types.Node +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Node.shading_compatibility` + +bpy.types.CompositorNodePlaneTrackDeform +---------------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CompositorNodePlaneTrackDeform.motion_blur_samples` +* :class:`bpy.types.CompositorNodePlaneTrackDeform.motion_blur_shutter` +* :class:`bpy.types.CompositorNodePlaneTrackDeform.use_motion_blur` + +bpy.types.NodeFrame +------------------- + +Added +^^^^^ + +* :class:`bpy.types.NodeFrame.text` + +bpy.types.ShaderNodeTexCoord +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeTexCoord.object` + +bpy.types.Paint +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Paint.cavity_curve` +* :class:`bpy.types.Paint.use_cavity` + +bpy.types.ImagePaint +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.ImagePaint.dither` + +bpy.types.ParticleEdit +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.ParticleEdit.shape_object` + +bpy.types.CyclesCameraSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesCameraSettings.latitude_max` +* :class:`bpy.types.CyclesCameraSettings.latitude_min` +* :class:`bpy.types.CyclesCameraSettings.longitude_max` +* :class:`bpy.types.CyclesCameraSettings.longitude_min` + +bpy.types.RegionView3D +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.RegionView3D.window_matrix` + +bpy.types.SequenceProxy +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.SequenceProxy.use_overwrite` + +bpy.types.SpaceFileBrowser +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceFileBrowser.bookmarks` +* :class:`bpy.types.SpaceFileBrowser.bookmarks_active` +* :class:`bpy.types.SpaceFileBrowser.recent_folders` +* :class:`bpy.types.SpaceFileBrowser.recent_folders_active` +* :class:`bpy.types.SpaceFileBrowser.system_bookmarks` +* :class:`bpy.types.SpaceFileBrowser.system_bookmarks_active` +* :class:`bpy.types.SpaceFileBrowser.system_folders` +* :class:`bpy.types.SpaceFileBrowser.system_folders_active` + +bpy.types.SpaceOutliner +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceOutliner.use_sort_alpha` + +bpy.types.SpaceSequenceEditor +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceSequenceEditor.show_safe_areas` +* :class:`bpy.types.SpaceSequenceEditor.show_safe_center` + +Removed +^^^^^^^ + +* **show_safe_margin** + +bpy.types.SpaceTextEditor +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceTextEditor.region_location_from_cursor` + +bpy.types.SpaceView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceView3D.fx_settings` + +bpy.types.BrushTextureSlot +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.BrushTextureSlot.has_random_texture_angle` +* :class:`bpy.types.BrushTextureSlot.has_texture_angle` +* :class:`bpy.types.BrushTextureSlot.has_texture_angle_source` +* :class:`bpy.types.BrushTextureSlot.random_angle` +* :class:`bpy.types.BrushTextureSlot.use_rake` +* :class:`bpy.types.BrushTextureSlot.use_random` + +bpy.types.ParticleSettingsTextureSlot +------------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ParticleSettingsTextureSlot.kink_amp_factor` +* :class:`bpy.types.ParticleSettingsTextureSlot.kink_freq_factor` +* :class:`bpy.types.ParticleSettingsTextureSlot.use_map_kink_amp` +* :class:`bpy.types.ParticleSettingsTextureSlot.use_map_kink_freq` + +Removed +^^^^^^^ + +* **kink_factor** +* **use_map_kink** + +bpy.types.ThemeClipEditor +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeClipEditor.gp_vertex` +* :class:`bpy.types.ThemeClipEditor.gp_vertex_select` +* :class:`bpy.types.ThemeClipEditor.gp_vertex_size` + +bpy.types.ThemeImageEditor +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeImageEditor.gp_vertex` +* :class:`bpy.types.ThemeImageEditor.gp_vertex_select` +* :class:`bpy.types.ThemeImageEditor.gp_vertex_size` + +bpy.types.ThemeNodeEditor +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeNodeEditor.gp_vertex` +* :class:`bpy.types.ThemeNodeEditor.gp_vertex_select` +* :class:`bpy.types.ThemeNodeEditor.gp_vertex_size` + +bpy.types.ThemeSequenceEditor +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeSequenceEditor.gp_vertex` +* :class:`bpy.types.ThemeSequenceEditor.gp_vertex_select` +* :class:`bpy.types.ThemeSequenceEditor.gp_vertex_size` + +bpy.types.ThemeTimeline +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeTimeline.time_grease_pencil` +* :class:`bpy.types.ThemeTimeline.time_keyframe` + +bpy.types.ThemeView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeView3D.clipping_border_3d` +* :class:`bpy.types.ThemeView3D.gp_vertex` +* :class:`bpy.types.ThemeView3D.gp_vertex_select` +* :class:`bpy.types.ThemeView3D.gp_vertex_size` + +bpy.types.UILayout +------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.UILayout.template_list` (listtype_name, list_id, dataptr, propname, active_dataptr, active_propname, item_dyntip_propname, rows, maxrows, type, columns), *was (listtype_name, list_id, dataptr, propname, active_dataptr, active_propname, rows, maxrows, type, columns)* + +bpy.types.UserPreferencesSystem +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesSystem.pixel_size` + +bpy.types.UserPreferencesView +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesView.use_gl_warn_support` + +bpy.types.VoxelData +------------------- + +Added +^^^^^ + +* :class:`bpy.types.VoxelData.hair_data_type` + +2.74 to 2.75 +============ + +bpy.types.BakePixel +------------------- + +Added +^^^^^ + +* :class:`bpy.types.BakePixel.object_id` + +bpy.types.BlendData +------------------- + +Added +^^^^^ + +* :class:`bpy.types.BlendData.palettes` + +bpy.types.BlendDataImages +------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataImages.new` (name, width, height, alpha, float_buffer, stereo3d), *was (name, width, height, alpha, float_buffer)* + +bpy.types.BlendDataSounds +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.BlendDataSounds.load` +* :class:`bpy.types.BlendDataSounds.remove` + +bpy.types.DopeSheet +------------------- + +Added +^^^^^ + +* :class:`bpy.types.DopeSheet.filter_text` +* :class:`bpy.types.DopeSheet.use_filter_text` + +bpy.types.FileSelectParams +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.FileSelectParams.thumbnail_size` + +bpy.types.GPUDOFSettings +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.GPUDOFSettings.blades` +* :class:`bpy.types.GPUDOFSettings.is_hq_supported` +* :class:`bpy.types.GPUDOFSettings.use_high_quality` + +bpy.types.Camera +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Camera.stereo` + +bpy.types.Image +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Image.buffers_free` +* :class:`bpy.types.Image.is_multiview` +* :class:`bpy.types.Image.is_stereo_3d` +* :class:`bpy.types.Image.packed_files` +* :class:`bpy.types.Image.stereo_3d_format` +* :class:`bpy.types.Image.use_multiview` +* :class:`bpy.types.Image.views_format` + +bpy.types.SunLamp +----------------- + +Added +^^^^^ + +* :class:`bpy.types.SunLamp.show_shadow_box` + +bpy.types.Mesh +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Mesh.vertex_paint_masks` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Mesh.calc_tessface` (free_mpoly), *was ()* + +bpy.types.Object +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Object.cache_release` +* :class:`bpy.types.Object.shape_key_remove` + +bpy.types.Scene +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Scene.depsgraph` + +bpy.types.ImageFormatSettings +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ImageFormatSettings.stereo_3d_format` +* :class:`bpy.types.ImageFormatSettings.views_format` + +bpy.types.ImageUser +------------------- + +Added +^^^^^ + +* :class:`bpy.types.ImageUser.multilayer_view` + +Removed +^^^^^^^ + +* **multilayer_pass** + +bpy.types.LodLevel +------------------ + +Added +^^^^^ + +* :class:`bpy.types.LodLevel.object_hysteresis_percentage` +* :class:`bpy.types.LodLevel.use_object_hysteresis` + +bpy.types.DecimateModifier +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.DecimateModifier.vertex_group_factor` + +bpy.types.CompositorNodeImage +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CompositorNodeImage.has_layers` +* :class:`bpy.types.CompositorNodeImage.has_views` +* :class:`bpy.types.CompositorNodeImage.view` + +bpy.types.TextureNodeImage +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.TextureNodeImage.image_user` + +bpy.types.Operator +------------------ + +Added +^^^^^ + +* :class:`bpy.types.Operator.macros` +* :class:`bpy.types.Operator.options` + +bpy.types.Sculpt +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Sculpt.detail_percent` + +bpy.types.PointCache +-------------------- + +Renamed +^^^^^^^ + +* **frames_skipped** -> :class:`bpy.types.PointCache.is_frame_skip` + +bpy.types.CyclesLampSettings +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesLampSettings.is_portal` + +bpy.types.CyclesRenderSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesRenderSettings.use_animated_seed` + +bpy.types.Region +---------------- + +Removed +^^^^^^^ + +* **callback_add** + +bpy.types.RenderEngine +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderEngine.active_view_set` +* :class:`bpy.types.RenderEngine.bl_use_shading_nodes_custom` +* :class:`bpy.types.RenderEngine.camera_model_matrix` +* :class:`bpy.types.RenderEngine.camera_shift_x` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.RenderEngine.bake` (scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result), *was (scene, object, pass_type, pixel_array, num_pixels, depth, result)* +* :class:`bpy.types.RenderEngine.begin_result` (x, y, w, h, layer, view), *was (x, y, w, h, layer)* + +bpy.types.CYCLES +---------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.CYCLES.bake` (self, scene, obj, pass_type, object_id, pixel_array, num_pixels, depth, result), *was (self, scene, obj, pass_type, pixel_array, num_pixels, depth, result)* + +bpy.types.RenderLayer +--------------------- + +Removed +^^^^^^^ + +* **rect** + +bpy.types.RenderPass +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderPass.view_id` + +bpy.types.RenderResult +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderResult.views` + +bpy.types.RenderSettings +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.RenderSettings.simplify_child_particles_render` +* :class:`bpy.types.RenderSettings.simplify_subdivision_render` +* :class:`bpy.types.RenderSettings.stereo_views` +* :class:`bpy.types.RenderSettings.use_multiview` +* :class:`bpy.types.RenderSettings.views` +* :class:`bpy.types.RenderSettings.views_format` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.RenderSettings.frame_path` (frame, preview, view), *was (frame)* + +bpy.types.SceneGameData +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.SceneGameData.scene_hysteresis_percentage` +* :class:`bpy.types.SceneGameData.use_scene_hysteresis` + +bpy.types.Sensor +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Sensor.tick_skip` + +Removed +^^^^^^^ + +* **frequency** + +bpy.types.EffectSequence +------------------------ + +Removed +^^^^^^^ + +* **use_proxy_custom_directory** +* **use_proxy_custom_file** + +bpy.types.ImageSequence +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.ImageSequence.stereo_3d_format` +* :class:`bpy.types.ImageSequence.use_multiview` +* :class:`bpy.types.ImageSequence.views_format` + +Removed +^^^^^^^ + +* **use_proxy_custom_directory** +* **use_proxy_custom_file** + +bpy.types.MetaSequence +---------------------- + +Removed +^^^^^^^ + +* **use_proxy_custom_directory** +* **use_proxy_custom_file** + +bpy.types.MovieSequence +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.MovieSequence.stereo_3d_format` +* :class:`bpy.types.MovieSequence.use_multiview` +* :class:`bpy.types.MovieSequence.views_format` + +Removed +^^^^^^^ + +* **use_proxy_custom_directory** +* **use_proxy_custom_file** + +bpy.types.SceneSequence +----------------------- + +Removed +^^^^^^^ + +* **use_proxy_custom_directory** +* **use_proxy_custom_file** + +bpy.types.SequenceEditor +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.SequenceEditor.proxy_dir` +* :class:`bpy.types.SequenceEditor.proxy_storage` + +bpy.types.SequenceProxy +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.SequenceProxy.use_proxy_custom_directory` +* :class:`bpy.types.SequenceProxy.use_proxy_custom_file` + +bpy.types.SpaceImageEditor +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceImageEditor.show_stereo_3d` + +bpy.types.SpaceSequenceEditor +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceSequenceEditor.show_metadata` + +bpy.types.SpaceView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceView3D.show_stereo_3d_cameras` +* :class:`bpy.types.SpaceView3D.show_stereo_3d_convergence_plane` +* :class:`bpy.types.SpaceView3D.show_stereo_3d_volume` +* :class:`bpy.types.SpaceView3D.stereo_3d_camera` +* :class:`bpy.types.SpaceView3D.stereo_3d_convergence_plane_alpha` +* :class:`bpy.types.SpaceView3D.stereo_3d_eye` +* :class:`bpy.types.SpaceView3D.stereo_3d_volume_alpha` + +bpy.types.SpaceUVEditor +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceUVEditor.show_metadata` + +bpy.types.ThemeImageEditor +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeImageEditor.metadatabg` +* :class:`bpy.types.ThemeImageEditor.metadatatext` + +bpy.types.ThemeSequenceEditor +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeSequenceEditor.metadatabg` +* :class:`bpy.types.ThemeSequenceEditor.metadatatext` + +bpy.types.ToolSettings +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.ToolSettings.lock_markers` +* :class:`bpy.types.ToolSettings.use_proportional_action` +* :class:`bpy.types.ToolSettings.use_proportional_fcurve` + +bpy.types.UILayout +------------------ + +Added +^^^^^ + +* :class:`bpy.types.UILayout.template_image_stereo_3d` +* :class:`bpy.types.UILayout.template_image_views` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.UILayout.menu` (menu, text, text_ctxt, translate, icon, icon_value), *was (menu, text, text_ctxt, translate, icon)* +* :class:`bpy.types.UILayout.template_icon_view` (data, property, show_labels), *was (data, property)* +* :class:`bpy.types.UILayout.template_image` (data, property, image_user, compact, multiview), *was (data, property, image_user, compact)* + +bpy.types.UserPreferencesView +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesView.view_frame_keyframes` +* :class:`bpy.types.UserPreferencesView.view_frame_seconds` +* :class:`bpy.types.UserPreferencesView.view_frame_type` + +bpy.types.Window +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Window.stereo_3d_display` + +2.75 to 2.76 +============ + +bpy.types.ActionFCurves +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.ActionFCurves.find` + +bpy.types.BlendDataBrushes +-------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataBrushes.new` (name, mode), *was (name)* + +bpy.types.FileSelectParams +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.FileSelectParams.filter_id` +* :class:`bpy.types.FileSelectParams.filter_id_category` +* :class:`bpy.types.FileSelectParams.recursion_level` +* :class:`bpy.types.FileSelectParams.use_filter_blendid` +* :class:`bpy.types.FileSelectParams.use_library_browsing` + +bpy.types.GameObjectSettings +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GameObjectSettings.angular_velocity_max` +* :class:`bpy.types.GameObjectSettings.angular_velocity_min` + +bpy.types.ID +------------ + +Added +^^^^^ + +* :class:`bpy.types.ID.preview` + +bpy.types.Brush +--------------- + +Removed +^^^^^^^ + +* **use_wrap** + +bpy.types.ImagePreview +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.ImagePreview.icon_pixels_float` +* :class:`bpy.types.ImagePreview.image_pixels_float` + +bpy.types.ImageUser +------------------- + +Added +^^^^^ + +* :class:`bpy.types.ImageUser.multilayer_pass` + +bpy.types.BevelModifier +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.BevelModifier.loop_slide` + +bpy.types.SubsurfModifier +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SubsurfModifier.use_opensubdiv` + +bpy.types.ShaderNodeTexImage +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeTexImage.extension` + +bpy.types.Paint +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Paint.tile_offset` +* :class:`bpy.types.Paint.tile_x` +* :class:`bpy.types.Paint.tile_y` +* :class:`bpy.types.Paint.tile_z` + +bpy.types.CyclesObjectBlurSettings +---------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesObjectBlurSettings.use_camera_cull` + +bpy.types.CyclesRenderSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesRenderSettings.camera_cull_margin` +* :class:`bpy.types.CyclesRenderSettings.use_camera_cull` + +bpy.types.CyclesWorldSettings +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesWorldSettings.max_bounces` + +bpy.types.RenderSettings +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.RenderSettings.use_stamp_strip_meta` + +bpy.types.SmokeDomainSettings +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SmokeDomainSettings.velocity_grid` + +bpy.types.SpaceClipEditor +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceClipEditor.show_metadata` + +bpy.types.SpaceNodeEditor +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceNodeEditor.insert_offset_direction` +* :class:`bpy.types.SpaceNodeEditor.use_insert_offset` + +bpy.types.ToolSettings +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.ToolSettings.use_snap_grid_absolute` + +bpy.types.UILayout +------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.UILayout.template_icon_view` (data, property, show_labels, scale), *was (data, property, show_labels)* + +bpy.types.UserPreferencesEdit +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesEdit.node_margin` + +bpy.types.UserPreferencesInput +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesInput.ndof_deadzone` + +bpy.types.UserPreferencesSystem +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesSystem.opensubdiv_compute_type` + +2.76 to 2.77 +============ + +bpy.types.AnimDataDrivers +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.AnimDataDrivers.find` + +bpy.types.BakeSettings +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.BakeSettings.pass_filter` +* :class:`bpy.types.BakeSettings.use_pass_ambient_occlusion` +* :class:`bpy.types.BakeSettings.use_pass_color` +* :class:`bpy.types.BakeSettings.use_pass_diffuse` +* :class:`bpy.types.BakeSettings.use_pass_direct` +* :class:`bpy.types.BakeSettings.use_pass_emit` +* :class:`bpy.types.BakeSettings.use_pass_glossy` +* :class:`bpy.types.BakeSettings.use_pass_indirect` +* :class:`bpy.types.BakeSettings.use_pass_subsurface` +* :class:`bpy.types.BakeSettings.use_pass_transmission` + +bpy.types.BlendData +------------------- + +Removed +^^^^^^^ + +* **scripts** + +bpy.types.BlendDataFonts +------------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataFonts.load` (filepath, check_existing), *was (filepath)* + +bpy.types.BlendDataImages +------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataImages.load` (filepath, check_existing), *was (filepath)* + +bpy.types.BlendDataMasks +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.BlendDataMasks.is_updated` + +bpy.types.BlendDataMovieClips +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.BlendDataMovieClips.is_updated` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataMovieClips.load` (filepath, check_existing), *was (filepath)* + +bpy.types.BlendDataSounds +------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataSounds.load` (filepath, check_existing), *was (filepath)* + +bpy.types.DopeSheet +------------------- + +Added +^^^^^ + +* :class:`bpy.types.DopeSheet.show_gpencil_3d_only` + +bpy.types.FileSelectParams +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.FileSelectParams.display_size` + +Removed +^^^^^^^ + +* **thumbnail_size** + +bpy.types.GameObjectSettings +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GameObjectSettings.jump_max` + +bpy.types.ID +------------ + +Added +^^^^^ + +* :class:`bpy.types.ID.user_of_id` + +bpy.types.Brush +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Brush.rake_factor` + +bpy.types.FreestyleLineStyle +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.FreestyleLineStyle.animation_data` + +bpy.types.GreasePencil +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.GreasePencil.use_onion_skinning` + +Removed +^^^^^^^ + +* **draw_mode** +* **use_stroke_endpoints** + +bpy.types.Object +---------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Object.closest_point_on_mesh` (origin, distance), *was (point, max_dist)* +* :class:`bpy.types.Object.ray_cast` (origin, direction, distance), *was (start, end)* + +bpy.types.Scene +--------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Scene.ray_cast` (origin, direction, distance), *was (start, end)* + +bpy.types.ImageFormatSettings +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ImageFormatSettings.tiff_codec` + +bpy.types.ImagePackedFile +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ImagePackedFile.save` + +bpy.types.DataTransferModifier +------------------------------ + +Removed +^^^^^^^ + +* **data_types_loops_uv** +* **data_types_loops_vcol** +* **data_types_verts_vgroup** + +bpy.types.DecimateModifier +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.DecimateModifier.symmetry_axis` +* :class:`bpy.types.DecimateModifier.use_symmetry` + +bpy.types.Node +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Node.insert_link` + +bpy.types.CompositorNodeBlur +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CompositorNodeBlur.use_extended_bounds` + +bpy.types.CompositorNodeBokehBlur +--------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CompositorNodeBokehBlur.use_extended_bounds` + +bpy.types.CompositorNodeStabilize +--------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CompositorNodeStabilize.invert` + +bpy.types.ShaderNodeTexEnvironment +---------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeTexEnvironment.interpolation` + +bpy.types.ShaderNodeTexPointDensity +----------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeTexPointDensity.cache_point_density` +* :class:`bpy.types.ShaderNodeTexPointDensity.calc_point_density_minmax` + +bpy.types.ShaderNodeTexWave +--------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeTexWave.wave_profile` + +bpy.types.PoseBone +------------------ + +Added +^^^^^ + +* :class:`bpy.types.PoseBone.custom_shape_scale` +* :class:`bpy.types.PoseBone.use_custom_shape_bone_size` + +bpy.types.EnumProperty +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.EnumProperty.enum_items_static` + +bpy.types.CyclesRenderSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesRenderSettings.debug_opencl_device_type` +* :class:`bpy.types.CyclesRenderSettings.debug_opencl_kernel_type` +* :class:`bpy.types.CyclesRenderSettings.debug_use_cpu_avx` +* :class:`bpy.types.CyclesRenderSettings.debug_use_cpu_avx2` +* :class:`bpy.types.CyclesRenderSettings.debug_use_cpu_sse2` +* :class:`bpy.types.CyclesRenderSettings.debug_use_cpu_sse3` +* :class:`bpy.types.CyclesRenderSettings.debug_use_cpu_sse41` +* :class:`bpy.types.CyclesRenderSettings.debug_use_opencl_debug` +* :class:`bpy.types.CyclesRenderSettings.debug_use_qbvh` +* :class:`bpy.types.CyclesRenderSettings.motion_blur_position` +* :class:`bpy.types.CyclesRenderSettings.pixel_filter_type` +* :class:`bpy.types.CyclesRenderSettings.rolling_shutter_duration` +* :class:`bpy.types.CyclesRenderSettings.rolling_shutter_type` + +Removed +^^^^^^^ + +* **use_cache** + +bpy.types.RenderEngine +---------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.RenderEngine.bake` (scene, object, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result), *was (scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result)* + +bpy.types.CYCLES +---------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.CYCLES.bake` (self, scene, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result), *was (self, scene, obj, pass_type, object_id, pixel_array, num_pixels, depth, result)* + +bpy.types.RenderLayer +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderLayer.use_ao` + +bpy.types.RenderSettings +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.RenderSettings.motion_blur_shutter_curve` + +Removed +^^^^^^^ + +* **use_free_unused_nodes** + +bpy.types.SceneRenderLayer +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SceneRenderLayer.use_ao` + +bpy.types.SculptToolCapabilities +-------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SculptToolCapabilities.has_rake_factor` + +bpy.types.TextSequence +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.TextSequence.align_y` +* :class:`bpy.types.TextSequence.wrap_width` + +Renamed +^^^^^^^ + +* **align** -> :class:`bpy.types.TextSequence.align_x` + +bpy.types.WipeSequence +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.WipeSequence.input_2` + +bpy.types.SceneSequence +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.SceneSequence.use_sequence` + +bpy.types.SoundSequence +----------------------- + +Removed +^^^^^^^ + +* **filepath** + +bpy.types.SequenceModifier +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SequenceModifier.mask_time` + +bpy.types.ShapeKey +------------------ + +Added +^^^^^ + +* :class:`bpy.types.ShapeKey.normals_polygon_get` +* :class:`bpy.types.ShapeKey.normals_split_get` +* :class:`bpy.types.ShapeKey.normals_vertex_get` + +bpy.types.SmokeDomainSettings +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SmokeDomainSettings.cache_file_format` +* :class:`bpy.types.SmokeDomainSettings.data_depth` +* :class:`bpy.types.SmokeDomainSettings.openvdb_cache_compress_type` + +bpy.types.SpaceGraphEditor +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceGraphEditor.cursor_position_x` + +bpy.types.ThemeSequenceEditor +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeSequenceEditor.text_strip` + +bpy.types.ThemeView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeView3D.text_grease_pencil` +* :class:`bpy.types.ThemeView3D.text_keyframe` + +bpy.types.ToolSettings +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.ToolSettings.gpencil_sculpt` +* :class:`bpy.types.ToolSettings.gpencil_stroke_placement_image_editor` +* :class:`bpy.types.ToolSettings.gpencil_stroke_placement_sequencer_preview` +* :class:`bpy.types.ToolSettings.gpencil_stroke_placement_view2d` +* :class:`bpy.types.ToolSettings.gpencil_stroke_placement_view3d` +* :class:`bpy.types.ToolSettings.use_gpencil_additive_drawing` +* :class:`bpy.types.ToolSettings.use_gpencil_stroke_endpoints` + +Renamed +^^^^^^^ + +* **use_grease_pencil_sessions** -> :class:`bpy.types.ToolSettings.use_gpencil_continuous_drawing` + +bpy.types.UserPreferencesSystem +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesSystem.font_path_ui_mono` + +Removed +^^^^^^^ + +* **is_occlusion_query_supported** +* **use_vertex_buffer_objects** + +bpy.types.UserPreferencesView +----------------------------- + +Removed +^^^^^^^ + +* **use_gl_warn_support** + +2.77 to 2.78 +============ + +bpy.types.AnimData +------------------ + +Added +^^^^^ + +* :class:`bpy.types.AnimData.use_tweak_mode` + +bpy.types.BlendData +------------------- + +Added +^^^^^ + +* :class:`bpy.types.BlendData.cache_files` +* :class:`bpy.types.BlendData.paint_curves` + +bpy.types.BlendDataActions +-------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataActions.remove` (action, do_unlink), *was (action)* + +bpy.types.BlendDataArmatures +---------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataArmatures.remove` (armature, do_unlink), *was (armature)* + +bpy.types.BlendDataBrushes +-------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataBrushes.remove` (brush, do_unlink), *was (brush)* + +bpy.types.BlendDataCameras +-------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataCameras.remove` (camera, do_unlink), *was (camera)* + +bpy.types.BlendDataCurves +------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataCurves.remove` (curve, do_unlink), *was (curve)* + +bpy.types.BlendDataFonts +------------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataFonts.remove` (vfont, do_unlink), *was (vfont)* + +bpy.types.BlendDataGreasePencils +-------------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataGreasePencils.remove` (grease_pencil, do_unlink), *was (grease_pencil)* + +bpy.types.BlendDataGroups +------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataGroups.remove` (group, do_unlink), *was (group)* + +bpy.types.BlendDataImages +------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataImages.remove` (image, do_unlink), *was (image)* + +bpy.types.BlendDataLamps +------------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataLamps.remove` (lamp, do_unlink), *was (lamp)* + +bpy.types.BlendDataLattices +--------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataLattices.remove` (lattice, do_unlink), *was (lattice)* + +bpy.types.BlendDataLineStyles +----------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataLineStyles.remove` (linestyle, do_unlink), *was (linestyle)* + +bpy.types.BlendDataMasks +------------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataMasks.remove` (mask, do_unlink), *was (mask)* + +bpy.types.BlendDataMaterials +---------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataMaterials.remove` (material, do_unlink), *was (material)* + +bpy.types.BlendDataMeshes +------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataMeshes.remove` (mesh, do_unlink), *was (mesh)* + +bpy.types.BlendDataMetaBalls +---------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataMetaBalls.remove` (metaball, do_unlink), *was (metaball)* + +bpy.types.BlendDataMovieClips +----------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataMovieClips.remove` (clip, do_unlink), *was (clip)* + +bpy.types.BlendDataNodeTrees +---------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataNodeTrees.remove` (tree, do_unlink), *was (tree)* + +bpy.types.BlendDataObjects +-------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataObjects.remove` (object, do_unlink), *was (object)* + +bpy.types.BlendDataPalettes +--------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataPalettes.remove` (palette, do_unlink), *was (palette)* + +bpy.types.BlendDataParticles +---------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataParticles.remove` (particle, do_unlink), *was (particle)* + +bpy.types.BlendDataScenes +------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataScenes.remove` (scene, do_unlink), *was (scene)* + +bpy.types.BlendDataSounds +------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataSounds.remove` (sound, do_unlink), *was (sound)* + +bpy.types.BlendDataSpeakers +--------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataSpeakers.remove` (speaker, do_unlink), *was (speaker)* + +bpy.types.BlendDataTexts +------------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataTexts.remove` (text, do_unlink), *was (text)* + +bpy.types.BlendDataTextures +--------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataTextures.remove` (texture, do_unlink), *was (texture)* + +bpy.types.BlendDataWorlds +------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.BlendDataWorlds.remove` (world, do_unlink), *was (world)* + +bpy.types.Bone +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Bone.bbone_curveinx` +* :class:`bpy.types.Bone.bbone_curveiny` +* :class:`bpy.types.Bone.bbone_curveoutx` +* :class:`bpy.types.Bone.bbone_curveouty` +* :class:`bpy.types.Bone.bbone_rollin` +* :class:`bpy.types.Bone.bbone_rollout` +* :class:`bpy.types.Bone.bbone_scalein` +* :class:`bpy.types.Bone.bbone_scaleout` +* :class:`bpy.types.Bone.use_endroll_as_inroll` + +bpy.types.CameraStereoData +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CameraStereoData.pole_merge_angle_from` +* :class:`bpy.types.CameraStereoData.pole_merge_angle_to` +* :class:`bpy.types.CameraStereoData.use_pole_merge` +* :class:`bpy.types.CameraStereoData.use_spherical_stereo` + +bpy.types.ClothSettings +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.ClothSettings.time_scale` +* :class:`bpy.types.ClothSettings.use_dynamic_mesh` + +bpy.types.CopyLocationConstraint +-------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CopyLocationConstraint.use_bbone_shape` + +bpy.types.CopyTransformsConstraint +---------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CopyTransformsConstraint.use_bbone_shape` + +bpy.types.DampedTrackConstraint +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.DampedTrackConstraint.use_bbone_shape` + +bpy.types.LimitDistanceConstraint +--------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.LimitDistanceConstraint.use_bbone_shape` + +bpy.types.LockedTrackConstraint +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.LockedTrackConstraint.use_bbone_shape` + +bpy.types.PivotConstraint +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.PivotConstraint.use_bbone_shape` + +bpy.types.StretchToConstraint +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.StretchToConstraint.use_bbone_shape` + +bpy.types.TrackToConstraint +--------------------------- + +Added +^^^^^ + +* :class:`bpy.types.TrackToConstraint.use_bbone_shape` + +bpy.types.DopeSheet +------------------- + +Added +^^^^^ + +* :class:`bpy.types.DopeSheet.use_datablock_sort` +* :class:`bpy.types.DopeSheet.use_multi_word_filter` + +bpy.types.Driver +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Driver.use_self` + +bpy.types.DriverVariable +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.DriverVariable.is_name_valid` + +bpy.types.EditBone +------------------ + +Added +^^^^^ + +* :class:`bpy.types.EditBone.bbone_curveinx` +* :class:`bpy.types.EditBone.bbone_curveiny` +* :class:`bpy.types.EditBone.bbone_curveoutx` +* :class:`bpy.types.EditBone.bbone_curveouty` +* :class:`bpy.types.EditBone.bbone_rollin` +* :class:`bpy.types.EditBone.bbone_rollout` +* :class:`bpy.types.EditBone.bbone_scalein` +* :class:`bpy.types.EditBone.bbone_scaleout` +* :class:`bpy.types.EditBone.use_endroll_as_inroll` + +bpy.types.FCurveKeyframePoints +------------------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.FCurveKeyframePoints.insert` (frame, value, options, keyframe_type), *was (frame, value, options)* + +bpy.types.GPencilLayer +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPencilLayer.is_parented` +* :class:`bpy.types.GPencilLayer.matrix_inverse` +* :class:`bpy.types.GPencilLayer.parent` +* :class:`bpy.types.GPencilLayer.parent_bone` +* :class:`bpy.types.GPencilLayer.parent_type` +* :class:`bpy.types.GPencilLayer.tint_color` +* :class:`bpy.types.GPencilLayer.tint_factor` +* :class:`bpy.types.GPencilLayer.unlock_color` + +Removed +^^^^^^^ + +* **color** +* **fill_alpha** +* **fill_color** +* **is_fill_visible** +* **is_stroke_visible** + +Renamed +^^^^^^^ + +* **alpha** -> :class:`bpy.types.GPencilLayer.opacity` +* **line_width** -> :class:`bpy.types.GPencilLayer.line_change` + +bpy.types.GPencilSculptSettings +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPencilSculptSettings.affect_position` +* :class:`bpy.types.GPencilSculptSettings.affect_strength` +* :class:`bpy.types.GPencilSculptSettings.affect_thickness` +* :class:`bpy.types.GPencilSculptSettings.selection_alpha` + +bpy.types.GPencilStroke +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPencilStroke.color` +* :class:`bpy.types.GPencilStroke.colorname` +* :class:`bpy.types.GPencilStroke.draw_cyclic` +* :class:`bpy.types.GPencilStroke.line_width` +* :class:`bpy.types.GPencilStroke.triangles` + +bpy.types.GPencilStrokePoint +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPencilStrokePoint.strength` + +bpy.types.GPencilStrokePoints +----------------------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.GPencilStrokePoints.add` (count, pressure, strength), *was (count)* + +bpy.types.GPencilStrokes +------------------------ + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.GPencilStrokes.new` (colorname), *was ()* + +bpy.types.ID +------------ + +Added +^^^^^ + +* :class:`bpy.types.ID.user_remap` + +bpy.types.TextCurve +------------------- + +Added +^^^^^ + +* :class:`bpy.types.TextCurve.align_x` +* :class:`bpy.types.TextCurve.align_y` + +Removed +^^^^^^^ + +* **align** + +bpy.types.GreasePencil +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.GreasePencil.palettes` +* :class:`bpy.types.GreasePencil.show_stroke_direction` + +bpy.types.PointLamp +------------------- + +Added +^^^^^ + +* :class:`bpy.types.PointLamp.constant_coefficient` +* :class:`bpy.types.PointLamp.linear_coefficient` +* :class:`bpy.types.PointLamp.quadratic_coefficient` + +bpy.types.SpotLamp +------------------ + +Added +^^^^^ + +* :class:`bpy.types.SpotLamp.constant_coefficient` +* :class:`bpy.types.SpotLamp.linear_coefficient` +* :class:`bpy.types.SpotLamp.quadratic_coefficient` + +bpy.types.Library +----------------- + +Added +^^^^^ + +* :class:`bpy.types.Library.reload` + +bpy.types.Mesh +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Mesh.flip_normals` +* :class:`bpy.types.Mesh.split_faces` + +bpy.types.MovieClip +------------------- + +Added +^^^^^ + +* :class:`bpy.types.MovieClip.animation_data` + +bpy.types.ParticleSettings +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ParticleSettings.collision_group` + +bpy.types.Scene +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Scene.alembic_export` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Scene.collada_export` (filepath, apply_modifiers, export_mesh_type, selected, include_children, include_armatures, include_shapekeys, deform_bones_only, active_uv_only, include_uv_textures, include_material_textures, use_texture_copies, use_ngons, use_object_instantiation, use_blender_profile, sort_by_name, open_sim, export_transformation_type), *was (filepath, apply_modifiers, export_mesh_type, selected, include_children, include_armatures, include_shapekeys, deform_bones_only, active_uv_only, include_uv_textures, include_material_textures, use_texture_copies, use_ngons, use_object_instantiation, sort_by_name, open_sim, export_transformation_type)* + +bpy.types.WholeCharacter +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.WholeCharacter.doBBone` + +bpy.types.MeshPolygon +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.MeshPolygon.flip` + +bpy.types.BooleanModifier +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.BooleanModifier.double_threshold` +* :class:`bpy.types.BooleanModifier.solver` + +bpy.types.HookModifier +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.HookModifier.matrix_inverse` + +bpy.types.NormalEditModifier +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.NormalEditModifier.mix_limit` + +bpy.types.ShrinkwrapModifier +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShrinkwrapModifier.invert_vertex_group` + +bpy.types.SimpleDeformModifier +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.SimpleDeformModifier.invert_vertex_group` + +bpy.types.MovieTrackingStabilization +------------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.MovieTrackingStabilization.active_rotation_track_index` +* :class:`bpy.types.MovieTrackingStabilization.anchor_frame` +* :class:`bpy.types.MovieTrackingStabilization.rotation_tracks` +* :class:`bpy.types.MovieTrackingStabilization.show_tracks_expanded` +* :class:`bpy.types.MovieTrackingStabilization.target_position` +* :class:`bpy.types.MovieTrackingStabilization.target_rotation` +* :class:`bpy.types.MovieTrackingStabilization.target_scale` +* :class:`bpy.types.MovieTrackingStabilization.use_stabilize_scale` + +Removed +^^^^^^^ + +* **rotation_track** + +bpy.types.MovieTrackingTrack +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.MovieTrackingTrack.weight_stab` + +bpy.types.CompositorNodeColorBalance +------------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CompositorNodeColorBalance.offset_basis` + +bpy.types.ShaderNodeTexPointDensity +----------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ShaderNodeTexPointDensity.vertex_attribute_name` + +Renamed +^^^^^^^ + +* **color_source** -> :class:`bpy.types.ShaderNodeTexPointDensity.particle_color_source` +* **color_source** -> :class:`bpy.types.ShaderNodeTexPointDensity.vertex_color_source` + +bpy.types.PointDensity +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.PointDensity.vertex_attribute_name` + +Renamed +^^^^^^^ + +* **color_source** -> :class:`bpy.types.PointDensity.particle_color_source` +* **color_source** -> :class:`bpy.types.PointDensity.vertex_color_source` + +bpy.types.PoseBone +------------------ + +Added +^^^^^ + +* :class:`bpy.types.PoseBone.bbone_curveinx` +* :class:`bpy.types.PoseBone.bbone_curveiny` +* :class:`bpy.types.PoseBone.bbone_curveoutx` +* :class:`bpy.types.PoseBone.bbone_curveouty` +* :class:`bpy.types.PoseBone.bbone_custom_handle_end` +* :class:`bpy.types.PoseBone.bbone_custom_handle_start` +* :class:`bpy.types.PoseBone.bbone_rollin` +* :class:`bpy.types.PoseBone.bbone_rollout` +* :class:`bpy.types.PoseBone.bbone_scalein` +* :class:`bpy.types.PoseBone.bbone_scaleout` +* :class:`bpy.types.PoseBone.use_bbone_custom_handles` +* :class:`bpy.types.PoseBone.use_bbone_relative_end_handle` +* :class:`bpy.types.PoseBone.use_bbone_relative_start_handle` + +bpy.types.BoolProperty +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.BoolProperty.is_array` + +bpy.types.FloatProperty +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.FloatProperty.is_array` + +bpy.types.IntProperty +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.IntProperty.is_array` + +bpy.types.CyclesMaterialSettings +-------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CyclesMaterialSettings.displacement_method` + +bpy.types.CyclesMeshSettings +---------------------------- + +Removed +^^^^^^^ + +* **dicing_rate** +* **displacement_method** +* **use_subdivision** + +bpy.types.CyclesRenderSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesRenderSettings.debug_bvh_time_steps` +* :class:`bpy.types.CyclesRenderSettings.debug_use_cuda_adaptive_compile` +* :class:`bpy.types.CyclesRenderSettings.debug_use_hair_bvh` +* :class:`bpy.types.CyclesRenderSettings.dicing_rate` +* :class:`bpy.types.CyclesRenderSettings.distance_cull_margin` +* :class:`bpy.types.CyclesRenderSettings.light_sampling_threshold` +* :class:`bpy.types.CyclesRenderSettings.max_subdivisions` +* :class:`bpy.types.CyclesRenderSettings.preview_dicing_rate` +* :class:`bpy.types.CyclesRenderSettings.texture_limit` +* :class:`bpy.types.CyclesRenderSettings.texture_limit_render` +* :class:`bpy.types.CyclesRenderSettings.use_distance_cull` + +bpy.types.RenderEngine +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderEngine.active_view_get` +* :class:`bpy.types.RenderEngine.bl_use_spherical_stereo` +* :class:`bpy.types.RenderEngine.use_spherical_stereo` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.RenderEngine.camera_model_matrix` (camera, use_spherical_stereo, r_model_matrix), *was (camera, r_model_matrix)* +* :class:`bpy.types.RenderEngine.camera_shift_x` (camera, use_spherical_stereo), *was (camera)* + +bpy.types.RenderSettings +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.RenderSettings.use_spherical_stereo` +* :class:`bpy.types.RenderSettings.use_stamp_labels` +* :class:`bpy.types.RenderSettings.use_stamp_memory` +* :class:`bpy.types.RenderSettings.use_world_space_shading` + +bpy.types.SceneGameData +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.SceneGameData.use_glsl_environment_lighting` + +bpy.types.SceneGameRecastData +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SceneGameRecastData.partitioning` + +bpy.types.TextSequence +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.TextSequence.color` +* :class:`bpy.types.TextSequence.shadow_color` + +bpy.types.SmokeDomainSettings +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SmokeDomainSettings.heat_grid` + +bpy.types.SoftBodySettings +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SoftBodySettings.collision_group` + +bpy.types.SpaceNLA +------------------ + +Added +^^^^^ + +* :class:`bpy.types.SpaceNLA.show_local_markers` + +bpy.types.ThemeDopeSheet +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.ThemeDopeSheet.keyframe_scale_factor` + +bpy.types.ThemeFileBrowser +-------------------------- + +Removed +^^^^^^^ + +* **active_file** +* **active_file_text** +* **scroll_handle** +* **scrollbar** +* **space_list** + +bpy.types.ToolSettings +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.ToolSettings.curve_paint_settings` +* :class:`bpy.types.ToolSettings.gpencil_brushes` +* :class:`bpy.types.ToolSettings.keyframe_type` +* :class:`bpy.types.ToolSettings.use_gpencil_draw_onback` + +bpy.types.UILayout +------------------ + +Added +^^^^^ + +* :class:`bpy.types.UILayout.template_cache_file` + +bpy.types.UserPreferences +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferences.version` + +bpy.types.UserPreferencesEdit +----------------------------- + +Removed +^^^^^^^ + +* **use_grease_pencil_smooth_stroke** + +bpy.types.UserPreferencesInput +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesInput.use_ndof` + +bpy.types.UserPreferencesSystem +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesSystem.legacy_compute_device_type` + +Removed +^^^^^^^ + +* **compute_device** +* **compute_device_type** + +2.78 to 2.79 +============ + +bpy.types.DupliObject +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.DupliObject.random_id` + +bpy.types.FFmpegSettings +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.FFmpegSettings.constant_rate_factor` +* :class:`bpy.types.FFmpegSettings.ffmpeg_preset` +* :class:`bpy.types.FFmpegSettings.max_b_frames` +* :class:`bpy.types.FFmpegSettings.use_max_b_frames` + +bpy.types.FieldSettings +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.FieldSettings.use_gravity_falloff` + +bpy.types.GPencilLayer +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPencilLayer.use_ghosts_always` + +bpy.types.GPencilSculptSettings +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPencilSculptSettings.lockaxis` + +bpy.types.Header +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Header.is_extended` + +bpy.types.ID +------------ + +Added +^^^^^ + +* :class:`bpy.types.ID.make_local` + +bpy.types.Mesh +-------------- + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Mesh.split_faces` (free_loop_normals), *was ()* + +bpy.types.Scene +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Scene.frame_float` +* :class:`bpy.types.Scene.show_subframe` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Scene.alembic_export` (filepath, frame_start, frame_end, xform_samples, geom_samples, shutter_open, shutter_close, selected_only, uvs, normals, vcolors, apply_subdiv, flatten, visible_layers_only, renderable_only, face_sets, subdiv_schema, export_hair, export_particles, compression_type, packuv, scale, triangulate, quad_method, ngon_method), *was (filepath, frame_start, frame_end, xform_samples, geom_samples, shutter_open, shutter_close, selected_only, uvs, normals, vcolors, apply_subdiv, flatten, visible_layers_only, renderable_only, face_sets, subdiv_schema, compression_type, packuv, scale)* +* :class:`bpy.types.Scene.collada_export` (filepath, apply_modifiers, export_mesh_type, selected, include_children, include_armatures, include_shapekeys, deform_bones_only, active_uv_only, export_texture_type, use_texture_copies, triangulate, use_object_instantiation, use_blender_profile, sort_by_name, export_transformation_type, open_sim, limit_precision, keep_bind_info), *was (filepath, apply_modifiers, export_mesh_type, selected, include_children, include_armatures, include_shapekeys, deform_bones_only, active_uv_only, include_uv_textures, include_material_textures, use_texture_copies, use_ngons, use_object_instantiation, use_blender_profile, sort_by_name, open_sim, export_transformation_type)* + +bpy.types.Macro +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Macro.bl_undo_group` + +bpy.types.Menu +-------------- + +Added +^^^^^ + +* :class:`bpy.types.Menu.is_extended` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.Menu.path_menu` (self, searchpaths, operator), *was (self, searchpaths, operator, props_default, filter_ext)* + +bpy.types.GPENCIL_PIE_sculpt +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPENCIL_PIE_sculpt.is_extended` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.GPENCIL_PIE_sculpt.path_menu` (self, searchpaths, operator), *was (self, searchpaths, operator, props_default, filter_ext)* + +bpy.types.GPENCIL_PIE_settings_palette +-------------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPENCIL_PIE_settings_palette.is_extended` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.GPENCIL_PIE_settings_palette.path_menu` (self, searchpaths, operator), *was (self, searchpaths, operator, props_default, filter_ext)* + +bpy.types.GPENCIL_PIE_tool_palette +---------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPENCIL_PIE_tool_palette.is_extended` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.GPENCIL_PIE_tool_palette.path_menu` (self, searchpaths, operator), *was (self, searchpaths, operator, props_default, filter_ext)* + +bpy.types.GPENCIL_PIE_tools_more +-------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPENCIL_PIE_tools_more.is_extended` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.GPENCIL_PIE_tools_more.path_menu` (self, searchpaths, operator), *was (self, searchpaths, operator, props_default, filter_ext)* + +bpy.types.DisplaceModifier +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.DisplaceModifier.space` + +bpy.types.MirrorModifier +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.MirrorModifier.mirror_offset_u` +* :class:`bpy.types.MirrorModifier.mirror_offset_v` + +bpy.types.ScrewModifier +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.ScrewModifier.merge_threshold` +* :class:`bpy.types.ScrewModifier.use_merge_vertices` + +bpy.types.MotionPath +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.MotionPath.color` +* :class:`bpy.types.MotionPath.line_thickness` +* :class:`bpy.types.MotionPath.lines` +* :class:`bpy.types.MotionPath.use_custom_color` + +bpy.types.CompositorNodeBrightContrast +-------------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CompositorNodeBrightContrast.use_premultiply` + +bpy.types.CompositorNodeHueSat +------------------------------ + +Removed +^^^^^^^ + +* **color_hue** +* **color_saturation** +* **color_value** + +bpy.types.CompositorNodeSwitchView +---------------------------------- + +Removed +^^^^^^^ + +* **check** + +bpy.types.Operator +------------------ + +Added +^^^^^ + +* :class:`bpy.types.Operator.bl_undo_group` +* :class:`bpy.types.Operator.is_repeat` + +bpy.types.Sculpt +---------------- + +Added +^^^^^ + +* :class:`bpy.types.Sculpt.constant_detail_resolution` + +Removed +^^^^^^^ + +* **constant_detail** + +bpy.types.Panel +--------------- + +Added +^^^^^ + +* :class:`bpy.types.Panel.is_extended` + +bpy.types.IMAGE_UV_sculpt +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.IMAGE_UV_sculpt.is_extended` + +bpy.types.IMAGE_UV_sculpt_curve +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.IMAGE_UV_sculpt_curve.is_extended` + +bpy.types.CyclesObjectSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesObjectSettings.is_shadow_catcher` + +bpy.types.CyclesRenderSettings +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.CyclesRenderSettings.ao_bounces` +* :class:`bpy.types.CyclesRenderSettings.ao_bounces_render` +* :class:`bpy.types.CyclesRenderSettings.debug_opencl_kernel_single_program` +* :class:`bpy.types.CyclesRenderSettings.debug_opencl_mem_limit` +* :class:`bpy.types.CyclesRenderSettings.debug_use_cpu_split_kernel` +* :class:`bpy.types.CyclesRenderSettings.debug_use_cuda_split_kernel` + +bpy.types.PropertyGroupItem +--------------------------- + +Added +^^^^^ + +* :class:`bpy.types.PropertyGroupItem.id` + +bpy.types.RenderEngine +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderEngine.add_pass` +* :class:`bpy.types.RenderEngine.register_pass` +* :class:`bpy.types.RenderEngine.update_render_passes` + +Function Arguments +^^^^^^^^^^^^^^^^^^ + +* :class:`bpy.types.RenderEngine.end_result` (result, cancel, highlight, do_merge_results), *was (result, cancel, do_merge_results)* + +bpy.types.CYCLES +---------------- + +Added +^^^^^ + +* :class:`bpy.types.CYCLES.update_render_passes` + +bpy.types.RenderPass +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderPass.fullname` + +Removed +^^^^^^^ + +* **debug_type** +* **type** + +bpy.types.RenderPasses +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.RenderPasses.find_by_name` + +bpy.types.RenderSettings +------------------------ + +Removed +^^^^^^^ + +* **sequencer_gl_render** +* **use_sequencer_gl_preview** + +bpy.types.RigidBodyConstraint +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.RigidBodyConstraint.spring_damping_ang_x` +* :class:`bpy.types.RigidBodyConstraint.spring_damping_ang_y` +* :class:`bpy.types.RigidBodyConstraint.spring_damping_ang_z` +* :class:`bpy.types.RigidBodyConstraint.spring_stiffness_ang_x` +* :class:`bpy.types.RigidBodyConstraint.spring_stiffness_ang_y` +* :class:`bpy.types.RigidBodyConstraint.spring_stiffness_ang_z` +* :class:`bpy.types.RigidBodyConstraint.use_spring_ang_x` +* :class:`bpy.types.RigidBodyConstraint.use_spring_ang_y` +* :class:`bpy.types.RigidBodyConstraint.use_spring_ang_z` + +bpy.types.SceneRenderLayer +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SceneRenderLayer.cycles` +* :class:`bpy.types.SceneRenderLayer.update_render_passes` + +bpy.types.SmokeDomainSettings +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SmokeDomainSettings.axis_slice_method` +* :class:`bpy.types.SmokeDomainSettings.coba_field` +* :class:`bpy.types.SmokeDomainSettings.color_ramp` +* :class:`bpy.types.SmokeDomainSettings.display_thickness` +* :class:`bpy.types.SmokeDomainSettings.draw_velocity` +* :class:`bpy.types.SmokeDomainSettings.slice_axis` +* :class:`bpy.types.SmokeDomainSettings.slice_depth` +* :class:`bpy.types.SmokeDomainSettings.slice_method` +* :class:`bpy.types.SmokeDomainSettings.slice_per_voxel` +* :class:`bpy.types.SmokeDomainSettings.use_color_ramp` +* :class:`bpy.types.SmokeDomainSettings.vector_draw_type` +* :class:`bpy.types.SmokeDomainSettings.vector_scale` + +bpy.types.SpaceNodeEditor +------------------------- + +Removed +^^^^^^^ + +* **show_highlight** + +bpy.types.SpaceView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceView3D.active_layer` + +bpy.types.SpaceUVEditor +----------------------- + +Added +^^^^^ + +* :class:`bpy.types.SpaceUVEditor.other_uv_filter` + +bpy.types.ThemeGraphEditor +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeGraphEditor.vertex_bevel` + +bpy.types.ThemeImageEditor +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeImageEditor.vertex_bevel` + +bpy.types.ThemeView3D +--------------------- + +Added +^^^^^ + +* :class:`bpy.types.ThemeView3D.edge_bevel` +* :class:`bpy.types.ThemeView3D.vertex_bevel` + +bpy.types.ToolSettings +---------------------- + +Added +^^^^^ + +* :class:`bpy.types.ToolSettings.gpencil_interpolate` + +bpy.types.UIList +---------------- + +Added +^^^^^ + +* :class:`bpy.types.UIList.is_extended` + +bpy.types.CLIP_UL_tracking_objects +---------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.CLIP_UL_tracking_objects.is_extended` + +bpy.types.FILEBROWSER_UL_dir +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.FILEBROWSER_UL_dir.is_extended` + +bpy.types.GPENCIL_UL_brush +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPENCIL_UL_brush.is_extended` + +bpy.types.GPENCIL_UL_layer +-------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPENCIL_UL_layer.is_extended` + +bpy.types.GPENCIL_UL_palettecolor +--------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.GPENCIL_UL_palettecolor.is_extended` + +bpy.types.MASK_UL_layers +------------------------ + +Added +^^^^^ + +* :class:`bpy.types.MASK_UL_layers.is_extended` + +bpy.types.MATERIAL_UL_matslots +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.MATERIAL_UL_matslots.is_extended` + +bpy.types.MESH_UL_shape_keys +---------------------------- + +Added +^^^^^ + +* :class:`bpy.types.MESH_UL_shape_keys.is_extended` + +bpy.types.MESH_UL_uvmaps_vcols +------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.MESH_UL_uvmaps_vcols.is_extended` + +bpy.types.MESH_UL_vgroups +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.MESH_UL_vgroups.is_extended` + +bpy.types.NODE_UL_interface_sockets +----------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.NODE_UL_interface_sockets.is_extended` + +bpy.types.PARTICLE_UL_particle_systems +-------------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.PARTICLE_UL_particle_systems.is_extended` + +bpy.types.PHYSICS_UL_dynapaint_surfaces +--------------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.PHYSICS_UL_dynapaint_surfaces.is_extended` + +bpy.types.RENDERLAYER_UL_linesets +--------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.RENDERLAYER_UL_linesets.is_extended` + +bpy.types.RENDERLAYER_UL_renderlayers +------------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.RENDERLAYER_UL_renderlayers.is_extended` + +bpy.types.RENDERLAYER_UL_renderviews +------------------------------------ + +Added +^^^^^ + +* :class:`bpy.types.RENDERLAYER_UL_renderviews.is_extended` + +bpy.types.SCENE_UL_keying_set_paths +----------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.SCENE_UL_keying_set_paths.is_extended` + +bpy.types.TEXTURE_UL_texpaintslots +---------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.TEXTURE_UL_texpaintslots.is_extended` + +bpy.types.TEXTURE_UL_texslots +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.TEXTURE_UL_texslots.is_extended` + +bpy.types.UI_UL_list +-------------------- + +Added +^^^^^ + +* :class:`bpy.types.UI_UL_list.is_extended` + +bpy.types.UserPreferences +------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferences.app_template` + +bpy.types.UserPreferencesSystem +------------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesSystem.use_select_pick_depth` + +Removed +^^^^^^^ + +* **use_textured_fonts** +* **virtual_pixel_mode** + +bpy.types.UserPreferencesView +----------------------------- + +Added +^^^^^ + +* :class:`bpy.types.UserPreferencesView.ui_line_width` +* :class:`bpy.types.UserPreferencesView.ui_scale` +* :class:`bpy.types.UserPreferencesView.use_cursor_lock_adjust` diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 3b0e8f52c83..08c3e729ed9 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -1010,9 +1010,9 @@ def pymodule2sphinx(basepath, module_name, module, title): context_type_map = { "active_base": ("ObjectBase", False), "active_bone": ("EditBone", False), + "active_gpencil_brush": ("GPencilSculptBrush", False), "active_gpencil_frame": ("GreasePencilLayer", True), "active_gpencil_layer": ("GPencilLayer", True), - "active_gpencil_brush": ("GPencilSculptBrush", False), "active_gpencil_palette": ("GPencilPalette", True), "active_gpencil_palettecolor": ("GPencilPaletteColor", True), "active_node": ("Node", False), @@ -1063,6 +1063,7 @@ context_type_map = { "selected_bones": ("EditBone", True), "selected_editable_bases": ("ObjectBase", True), "selected_editable_bones": ("EditBone", True), + "selected_editable_fcurves": ("FCurce", True), "selected_editable_objects": ("Object", True), "selected_editable_sequences": ("Sequence", True), "selected_nodes": ("Node", True), @@ -1639,6 +1640,11 @@ def write_sphinx_conf_py(basepath): fw("version = '%s - API'\n" % BLENDER_VERSION_DOTS) fw("release = '%s - API'\n" % BLENDER_VERSION_DOTS) + # Quiet file not in table-of-contents warnings. + fw("exclude_patterns = [\n") + fw(" 'include__bmesh.rst',\n") + fw("]\n\n") + if ARGS.sphinx_theme != 'default': fw("html_theme = '%s'\n" % ARGS.sphinx_theme) @@ -1659,6 +1665,24 @@ def write_sphinx_conf_py(basepath): fw("}\n\n") fw("latex_documents = [ ('contents', 'contents.tex', 'Blender Index', 'Blender Foundation', 'manual'), ]\n") + + # Workaround for useless links leading to compile errors + # See https://github.com/sphinx-doc/sphinx/issues/3866 + fw(r""" +from sphinx.domains.python import PythonDomain + +class PatchedPythonDomain(PythonDomain): + def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): + if 'refspecific' in node: + del node['refspecific'] + return super(PatchedPythonDomain, self).resolve_xref( + env, fromdocname, builder, typ, target, node, contnode) + +def setup(sphinx): + sphinx.override_domain(PatchedPythonDomain) +""") + # end workaround + file.close() @@ -1697,9 +1721,6 @@ def write_rst_contents(basepath): for info, info_desc in INFO_DOCS: fw(" %s <%s>\n\n" % (info_desc, info)) fw("\n") - fw("- :ref:`Blender/Python Add-on Tutorial: a step by step guide on") - fw(" how to write an add-on from scratch <blender_manual:advanced_scripting_addon_tutorial>`\n") - fw("\n") fw(title_string("Application Modules", "=", double=True)) fw(".. toctree::\n") diff --git a/extern/carve/carve-capi.cc b/extern/carve/carve-capi.cc index 5648977ad27..d6666a52c10 100644 --- a/extern/carve/carve-capi.cc +++ b/extern/carve/carve-capi.cc @@ -568,6 +568,22 @@ void cleanupFaceEdgeAttrsCallback(const MeshSet<3> *left, &descr->orig_face_edge_mapping); } +void copyVertexAttrsCallback(const carve::mesh::MeshSet<3>::vertex_t *orig_vert, + const carve::mesh::MeshSet<3>::vertex_t *new_vert, + void *descr_v) +{ + CarveMeshDescr *descr = (CarveMeshDescr *) descr_v; + if (!descr->orig_vert_mapping.hasAttribute(orig_vert)) { + return; + } + if (descr->orig_vert_mapping.hasAttribute(new_vert)) { + return; + } + OrigIndex attr = descr->orig_vert_mapping.getAttribute(orig_vert); + descr->orig_vert_mapping.setAttribute(new_vert, attr); + descr->orig_vert_mapping.removeAttribute(orig_vert); +} + } // namespace CarveMeshDescr *carve_addMesh(struct ImportMeshData *import_data, @@ -751,6 +767,7 @@ bool carve_performBooleanOperation(CarveMeshDescr *left_mesh, // done properly. The only way to make such situations working is to // union intersecting meshes of the same operand. carve_unionIntersections(&csg, &left, &right, + copyVertexAttrsCallback, cleanupFaceEdgeAttrsCallback, (void *) output_descr); diff --git a/extern/carve/carve-util.cc b/extern/carve/carve-util.cc index 0dff1deb750..78997c72e71 100644 --- a/extern/carve/carve-util.cc +++ b/extern/carve/carve-util.cc @@ -141,6 +141,11 @@ void carve_getRescaleMinMax(const MeshSet<3> *left, namespace { +struct UnionIntersectionContext { + VertexAttrsCallback vertex_attr_callback; + void *user_data; +}; + void copyMeshes(const std::vector<MeshSet<3>::mesh_t*> &meshes, std::vector<MeshSet<3>::mesh_t*> *new_meshes) { @@ -154,24 +159,73 @@ void copyMeshes(const std::vector<MeshSet<3>::mesh_t*> &meshes, } } -MeshSet<3> *meshSetFromMeshes(const std::vector<MeshSet<3>::mesh_t*> &meshes) +struct NewMeshMapping { + std::map<const MeshSet<3>::edge_t*, MeshSet<3>::vertex_t*> orig_edge_vert; +}; + +void prepareNewMeshMapping(const std::vector<MeshSet<3>::mesh_t*> &meshes, + NewMeshMapping *mapping) { - std::vector<MeshSet<3>::mesh_t*> new_meshes; + for (size_t m = 0; m < meshes.size(); ++m) { + MeshSet<3>::mesh_t *mesh = meshes[m]; + for (size_t f = 0; f < mesh->faces.size(); ++f) { + MeshSet<3>::face_t *face = mesh->faces[f]; + MeshSet<3>::edge_t *edge = face->edge; + do { + mapping->orig_edge_vert[edge] = edge->vert; + edge = edge->next; + } while (edge != face->edge); + } + } +} - copyMeshes(meshes, &new_meshes); +void runNewMeshSetHooks(UnionIntersectionContext *ctx, + NewMeshMapping *mapping, + MeshSet<3> *mesh_set) +{ + for (size_t m = 0; m < mesh_set->meshes.size(); ++m) { + MeshSet<3>::mesh_t *mesh = mesh_set->meshes[m]; + for (size_t f = 0; f < mesh->faces.size(); ++f) { + MeshSet<3>::face_t *face = mesh->faces[f]; + MeshSet<3>::edge_t *edge = face->edge; + do { + const MeshSet<3>::vertex_t *orig_vert = mapping->orig_edge_vert[edge]; + const MeshSet<3>::vertex_t *new_vert = edge->vert; + ctx->vertex_attr_callback(orig_vert, new_vert, ctx->user_data); + edge = edge->next; + } while (edge != face->edge); + } + } +} - return new MeshSet<3>(new_meshes); +MeshSet<3> *newMeshSetFromMeshesWithAttrs( + UnionIntersectionContext *ctx, + std::vector<MeshSet<3>::mesh_t*> &meshes) +{ + NewMeshMapping mapping; + prepareNewMeshMapping(meshes, &mapping); + MeshSet<3> *mesh_set = new MeshSet<3>(meshes); + runNewMeshSetHooks(ctx, &mapping, mesh_set); + return mesh_set; } -MeshSet<3> *meshSetFromTwoMeshes(const std::vector<MeshSet<3>::mesh_t*> &left_meshes, - const std::vector<MeshSet<3>::mesh_t*> &right_meshes) + +MeshSet<3> *meshSetFromMeshes(UnionIntersectionContext *ctx, + const std::vector<MeshSet<3>::mesh_t*> &meshes) { std::vector<MeshSet<3>::mesh_t*> new_meshes; + copyMeshes(meshes, &new_meshes); + return newMeshSetFromMeshesWithAttrs(ctx, new_meshes); +} +MeshSet<3> *meshSetFromTwoMeshes(UnionIntersectionContext *ctx, + const std::vector<MeshSet<3>::mesh_t*> &left_meshes, + const std::vector<MeshSet<3>::mesh_t*> &right_meshes) +{ + std::vector<MeshSet<3>::mesh_t*> new_meshes; copyMeshes(left_meshes, &new_meshes); copyMeshes(right_meshes, &new_meshes); - - return new MeshSet<3>(new_meshes); + return newMeshSetFromMeshesWithAttrs(ctx, new_meshes); } bool checkEdgeFaceIntersections_do(Intersections &intersections, @@ -349,7 +403,8 @@ void getIntersectedOperandMeshes(std::vector<MeshSet<3>::mesh_t*> *meshes, } } -MeshSet<3> *getIntersectedOperand(std::vector<MeshSet<3>::mesh_t*> *meshes, +MeshSet<3> *getIntersectedOperand(UnionIntersectionContext *ctx, + std::vector<MeshSet<3>::mesh_t*> *meshes, const MeshSet<3>::aabb_t &otherAABB, RTreeCache *rtree_cache, IntersectCache *intersect_cache) @@ -360,13 +415,14 @@ MeshSet<3> *getIntersectedOperand(std::vector<MeshSet<3>::mesh_t*> *meshes, if (operandMeshes.size() == 0) return NULL; - return meshSetFromMeshes(operandMeshes); + return meshSetFromMeshes(ctx, operandMeshes); } MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg, MeshSet<3> *poly, const MeshSet<3> *other_poly, const MeshSet<3>::aabb_t &otherAABB, + VertexAttrsCallback vertex_attr_callback, UnionIntersectionsCallback callback, void *user_data) { @@ -380,7 +436,12 @@ MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg, RTreeCache rtree_cache; IntersectCache intersect_cache; - MeshSet<3> *left = getIntersectedOperand(&orig_meshes, + UnionIntersectionContext ctx; + ctx.vertex_attr_callback = vertex_attr_callback; + ctx.user_data = user_data; + + MeshSet<3> *left = getIntersectedOperand(&ctx, + &orig_meshes, otherAABB, &rtree_cache, &intersect_cache); @@ -391,7 +452,8 @@ MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg, } while (orig_meshes.size()) { - MeshSet<3> *right = getIntersectedOperand(&orig_meshes, + MeshSet<3> *right = getIntersectedOperand(&ctx, + &orig_meshes, otherAABB, &rtree_cache, &intersect_cache); @@ -422,7 +484,9 @@ MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg, catch (carve::exception e) { std::cerr << "CSG failed, exception " << e.str() << std::endl; - MeshSet<3> *result = meshSetFromTwoMeshes(left->meshes, right->meshes); + MeshSet<3> *result = meshSetFromTwoMeshes(&ctx, + left->meshes, + right->meshes); callback(result, other_poly, user_data); @@ -448,7 +512,9 @@ MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg, // Append all meshes which doesn't have intersection with another operand as-is. if (orig_meshes.size()) { - MeshSet<3> *result = meshSetFromTwoMeshes(left->meshes, orig_meshes); + MeshSet<3> *result = meshSetFromTwoMeshes(&ctx, + left->meshes, + orig_meshes); delete left; left = result; @@ -464,6 +530,7 @@ MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg, void carve_unionIntersections(carve::csg::CSG *csg, MeshSet<3> **left_r, MeshSet<3> **right_r, + VertexAttrsCallback vertex_attr_callback, UnionIntersectionsCallback callback, void *user_data) { @@ -477,9 +544,9 @@ void carve_unionIntersections(carve::csg::CSG *csg, MeshSet<3>::aabb_t rightAABB = right->getAABB();; left = unionIntersectingMeshes(csg, left, right, rightAABB, - callback, user_data); + vertex_attr_callback, callback, user_data); right = unionIntersectingMeshes(csg, right, left, leftAABB, - callback, user_data); + vertex_attr_callback, callback, user_data); if (left != *left_r) { delete *left_r; diff --git a/extern/carve/carve-util.h b/extern/carve/carve-util.h index 3edf1bb1c02..e8f62cd2751 100644 --- a/extern/carve/carve-util.h +++ b/extern/carve/carve-util.h @@ -70,6 +70,10 @@ void carve_getRescaleMinMax(const carve::mesh::MeshSet<3> *left, carve::geom3d::Vector *min, carve::geom3d::Vector *max); +typedef void (*VertexAttrsCallback) (const carve::mesh::MeshSet<3>::vertex_t *orig_vert, + const carve::mesh::MeshSet<3>::vertex_t *new_vert, + void *userdata); + typedef void (*UnionIntersectionsCallback) (const carve::mesh::MeshSet<3> *left, const carve::mesh::MeshSet<3> *right, void *userdata); @@ -77,6 +81,7 @@ typedef void (*UnionIntersectionsCallback) (const carve::mesh::MeshSet<3> *left, void carve_unionIntersections(carve::csg::CSG *csg, carve::mesh::MeshSet<3> **left_r, carve::mesh::MeshSet<3> **right_r, + VertexAttrsCallback vertex_attr_callback, UnionIntersectionsCallback callback, void *user_data); @@ -148,6 +153,13 @@ namespace carve { void setAttribute(const meshset_t::vertex_t *v, const attr_t &attr) { attrs[v] = attr; } + + void removeAttribute(const meshset_t::vertex_t *v) { + typename attrmap_t::iterator it = attrs.find(v); + if (it != attrs.end()) { + attrs.erase(it); + } + } }; template<typename attr_t> diff --git a/extern/cuew/README.blender b/extern/cuew/README.blender index 7b77935d750..a53a927c25f 100644 --- a/extern/cuew/README.blender +++ b/extern/cuew/README.blender @@ -1,5 +1,5 @@ Project: Cuda Wrangler URL: https://github.com/CudaWrangler/cuew License: Apache 2.0 -Upstream version: 63d2a0f +Upstream version: cbf465b Local modifications: None diff --git a/extern/cuew/include/cuew.h b/extern/cuew/include/cuew.h index 4cce29d38ab..0eace96bc3f 100644 --- a/extern/cuew/include/cuew.h +++ b/extern/cuew/include/cuew.h @@ -27,7 +27,7 @@ extern "C" { #define CUEW_VERSION_MAJOR 1 #define CUEW_VERSION_MINOR 2 -#define CUDA_VERSION 7050 +#define CUDA_VERSION 8000 #define CU_IPC_HANDLE_SIZE 64 #define CU_STREAM_LEGACY ((CUstream)0x1) #define CU_STREAM_PER_THREAD ((CUstream)0x2) @@ -51,6 +51,8 @@ extern "C" { #define CU_LAUNCH_PARAM_BUFFER_POINTER ((void*)0x01) #define CU_LAUNCH_PARAM_BUFFER_SIZE ((void*)0x02) #define CU_PARAM_TR_DEFAULT -1 +#define CU_DEVICE_CPU ((CUdevice)-1) +#define CU_DEVICE_INVALID ((CUdevice)-2) /* Functions which changed 3.1 -> 3.2 for 64 bit stuff, * the cuda library has both the old ones for compatibility and new @@ -114,12 +116,30 @@ extern "C" { #define cuGLGetDevices cuGLGetDevices_v2 /* Types. */ +#ifdef _MSC_VER +typedef unsigned __int32 cuuint32_t; +typedef unsigned __int64 cuuint64_t; +#else +#include <stdint.h> +typedef uint32_t cuuint32_t; +typedef uint64_t cuuint64_t; +#endif + #if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) || defined (__aarch64__) typedef unsigned long long CUdeviceptr; #else typedef unsigned int CUdeviceptr; #endif + +#ifdef _WIN32 +# define CUDAAPI __stdcall +# define CUDA_CB __stdcall +#else +# define CUDAAPI +# define CUDA_CB +#endif + typedef int CUdevice; typedef struct CUctx_st* CUcontext; typedef struct CUmod_st* CUmodule; @@ -180,6 +200,53 @@ typedef enum CUevent_flags_enum { CU_EVENT_INTERPROCESS = 0x4, } CUevent_flags; +typedef enum CUstreamWaitValue_flags_enum { + CU_STREAM_WAIT_VALUE_GEQ = 0x0, + CU_STREAM_WAIT_VALUE_EQ = 0x1, + CU_STREAM_WAIT_VALUE_AND = 0x2, + CU_STREAM_WAIT_VALUE_FLUSH = (1 << 30), +} CUstreamWaitValue_flags; + +typedef enum CUstreamWriteValue_flags_enum { + CU_STREAM_WRITE_VALUE_DEFAULT = 0x0, + CU_STREAM_WRITE_VALUE_NO_MEMORY_BARRIER = 0x1, +} CUstreamWriteValue_flags; + +typedef enum CUstreamBatchMemOpType_enum { + CU_STREAM_MEM_OP_WAIT_VALUE_32 = 1, + CU_STREAM_MEM_OP_WRITE_VALUE_32 = 2, + CU_STREAM_MEM_OP_FLUSH_REMOTE_WRITES = 3, +} CUstreamBatchMemOpType; + +typedef union CUstreamBatchMemOpParams_union { + CUstreamBatchMemOpType operation; + struct CUstreamMemOpWaitValueParams_st { + CUstreamBatchMemOpType operation; + CUdeviceptr address; + union { + cuuint32_t value; + cuuint64_t pad; + }; + unsigned int flags; + CUdeviceptr alias; + } waitValue; + struct CUstreamMemOpWriteValueParams_st { + CUstreamBatchMemOpType operation; + CUdeviceptr address; + union { + cuuint32_t value; + cuuint64_t pad; + }; + unsigned int flags; + CUdeviceptr alias; + } writeValue; + struct CUstreamMemOpFlushRemoteWritesParams_st { + CUstreamBatchMemOpType operation; + unsigned int flags; + } flushRemoteWrites; + cuuint64_t pad[6]; +} CUstreamBatchMemOpParams; + typedef enum CUoccupancy_flags_enum { CU_OCCUPANCY_DEFAULT = 0x0, CU_OCCUPANCY_DISABLE_CACHING_OVERRIDE = 0x1, @@ -299,6 +366,12 @@ typedef enum CUdevice_attribute_enum { CU_DEVICE_ATTRIBUTE_MANAGED_MEMORY = 83, CU_DEVICE_ATTRIBUTE_MULTI_GPU_BOARD = 84, CU_DEVICE_ATTRIBUTE_MULTI_GPU_BOARD_GROUP_ID = 85, + CU_DEVICE_ATTRIBUTE_HOST_NATIVE_ATOMIC_SUPPORTED = 86, + CU_DEVICE_ATTRIBUTE_SINGLE_TO_DOUBLE_PRECISION_PERF_RATIO = 87, + CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS = 88, + CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS = 89, + CU_DEVICE_ATTRIBUTE_COMPUTE_PREEMPTION_SUPPORTED = 90, + CU_DEVICE_ATTRIBUTE_CAN_USE_HOST_POINTER_FOR_REGISTERED_MEM = 91, CU_DEVICE_ATTRIBUTE_MAX, } CUdevice_attribute; @@ -360,11 +433,26 @@ typedef enum CUmemorytype_enum { typedef enum CUcomputemode_enum { CU_COMPUTEMODE_DEFAULT = 0, - CU_COMPUTEMODE_EXCLUSIVE = 1, CU_COMPUTEMODE_PROHIBITED = 2, CU_COMPUTEMODE_EXCLUSIVE_PROCESS = 3, } CUcomputemode; +typedef enum CUmem_advise_enum { + CU_MEM_ADVISE_SET_READ_MOSTLY = 1, + CU_MEM_ADVISE_UNSET_READ_MOSTLY = 2, + CU_MEM_ADVISE_SET_PREFERRED_LOCATION = 3, + CU_MEM_ADVISE_UNSET_PREFERRED_LOCATION = 4, + CU_MEM_ADVISE_SET_ACCESSED_BY = 5, + CU_MEM_ADVISE_UNSET_ACCESSED_BY = 6, +} CUmem_advise; + +typedef enum CUmem_range_attribute_enum { + CU_MEM_RANGE_ATTRIBUTE_READ_MOSTLY = 1, + CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION = 2, + CU_MEM_RANGE_ATTRIBUTE_ACCESSED_BY = 3, + CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION = 4, +} CUmem_range_attribute; + typedef enum CUjit_option_enum { CU_JIT_MAX_REGISTERS = 0, CU_JIT_THREADS_PER_BLOCK, @@ -381,6 +469,8 @@ typedef enum CUjit_option_enum { CU_JIT_LOG_VERBOSE, CU_JIT_GENERATE_LINE_INFO, CU_JIT_CACHE_MODE, + CU_JIT_NEW_SM3X_OPT, + CU_JIT_FAST_COMPILE, CU_JIT_NUM_OPTIONS, } CUjit_option; @@ -397,6 +487,10 @@ typedef enum CUjit_target_enum { CU_TARGET_COMPUTE_37 = 37, CU_TARGET_COMPUTE_50 = 50, CU_TARGET_COMPUTE_52 = 52, + CU_TARGET_COMPUTE_53 = 53, + CU_TARGET_COMPUTE_60 = 60, + CU_TARGET_COMPUTE_61 = 61, + CU_TARGET_COMPUTE_62 = 62, } CUjit_target; typedef enum CUjit_fallback_enum { @@ -490,6 +584,7 @@ typedef enum cudaError_enum { CUDA_ERROR_PEER_ACCESS_UNSUPPORTED = 217, CUDA_ERROR_INVALID_PTX = 218, CUDA_ERROR_INVALID_GRAPHICS_CONTEXT = 219, + CUDA_ERROR_NVLINK_UNCORRECTABLE = 220, CUDA_ERROR_INVALID_SOURCE = 300, CUDA_ERROR_FILE_NOT_FOUND = 301, CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND = 302, @@ -521,8 +616,14 @@ typedef enum cudaError_enum { CUDA_ERROR_UNKNOWN = 999, } CUresult; -typedef void* CUstreamCallback; -typedef size_t* CUoccupancyB2DSize; +typedef enum CUdevice_P2PAttribute_enum { + CU_DEVICE_P2P_ATTRIBUTE_PERFORMANCE_RANK = 0x01, + CU_DEVICE_P2P_ATTRIBUTE_ACCESS_SUPPORTED = 0x02, + CU_DEVICE_P2P_ATTRIBUTE_NATIVE_ATOMIC_SUPPORTED = 0x03, +} CUdevice_P2PAttribute; + +typedef void (CUDA_CB *CUstreamCallback)(CUstream hStream, CUresult status, void* userData); +typedef size_t (CUDA_CB *CUoccupancyB2DSize)(int blockSize); typedef struct CUDA_MEMCPY2D_st { size_t srcXInBytes; @@ -654,7 +755,8 @@ typedef struct CUDA_TEXTURE_DESC_st { float mipmapLevelBias; float minMipmapLevelClamp; float maxMipmapLevelClamp; - int reserved[16]; + float borderColor[4]; + int reserved[12]; } CUDA_TEXTURE_DESC; typedef enum CUresourceViewFormat_enum { @@ -736,21 +838,16 @@ typedef enum { NVRTC_ERROR_INVALID_OPTION = 5, NVRTC_ERROR_COMPILATION = 6, NVRTC_ERROR_BUILTIN_OPERATION_FAILURE = 7, + NVRTC_ERROR_NO_NAME_EXPRESSIONS_AFTER_COMPILATION = 8, + NVRTC_ERROR_NO_LOWERED_NAMES_BEFORE_COMPILATION = 9, + NVRTC_ERROR_NAME_EXPRESSION_NOT_VALID = 10, + NVRTC_ERROR_INTERNAL_ERROR = 11, } nvrtcResult; typedef struct _nvrtcProgram* nvrtcProgram; - -#ifdef _WIN32 -# define CUDAAPI __stdcall -# define CUDA_CB __stdcall -#else -# define CUDAAPI -# define CUDA_CB -#endif - /* Function types. */ -typedef CUresult CUDAAPI tcuGetErrorString(CUresult error, const char* pStr); -typedef CUresult CUDAAPI tcuGetErrorName(CUresult error, const char* pStr); +typedef CUresult CUDAAPI tcuGetErrorString(CUresult error, const char** pStr); +typedef CUresult CUDAAPI tcuGetErrorName(CUresult error, const char** pStr); typedef CUresult CUDAAPI tcuInit(unsigned int Flags); typedef CUresult CUDAAPI tcuDriverGetVersion(int* driverVersion); typedef CUresult CUDAAPI tcuDeviceGet(CUdevice* device, int ordinal); @@ -786,26 +883,26 @@ typedef CUresult CUDAAPI tcuCtxAttach(CUcontext* pctx, unsigned int flags); typedef CUresult CUDAAPI tcuCtxDetach(CUcontext ctx); typedef CUresult CUDAAPI tcuModuleLoad(CUmodule* module, const char* fname); typedef CUresult CUDAAPI tcuModuleLoadData(CUmodule* module, const void* image); -typedef CUresult CUDAAPI tcuModuleLoadDataEx(CUmodule* module, const void* image, unsigned int numOptions, CUjit_option* options, void* optionValues); +typedef CUresult CUDAAPI tcuModuleLoadDataEx(CUmodule* module, const void* image, unsigned int numOptions, CUjit_option* options, void** optionValues); typedef CUresult CUDAAPI tcuModuleLoadFatBinary(CUmodule* module, const void* fatCubin); typedef CUresult CUDAAPI tcuModuleUnload(CUmodule hmod); typedef CUresult CUDAAPI tcuModuleGetFunction(CUfunction* hfunc, CUmodule hmod, const char* name); typedef CUresult CUDAAPI tcuModuleGetGlobal_v2(CUdeviceptr* dptr, size_t* bytes, CUmodule hmod, const char* name); typedef CUresult CUDAAPI tcuModuleGetTexRef(CUtexref* pTexRef, CUmodule hmod, const char* name); typedef CUresult CUDAAPI tcuModuleGetSurfRef(CUsurfref* pSurfRef, CUmodule hmod, const char* name); -typedef CUresult CUDAAPI tcuLinkCreate_v2(unsigned int numOptions, CUjit_option* options, void* optionValues, CUlinkState* stateOut); -typedef CUresult CUDAAPI tcuLinkAddData_v2(CUlinkState state, CUjitInputType type, void* data, size_t size, const char* name, unsigned int numOptions, CUjit_option* options, void* optionValues); -typedef CUresult CUDAAPI tcuLinkAddFile_v2(CUlinkState state, CUjitInputType type, const char* path, unsigned int numOptions, CUjit_option* options, void* optionValues); -typedef CUresult CUDAAPI tcuLinkComplete(CUlinkState state, void* cubinOut, size_t* sizeOut); +typedef CUresult CUDAAPI tcuLinkCreate_v2(unsigned int numOptions, CUjit_option* options, void** optionValues, CUlinkState* stateOut); +typedef CUresult CUDAAPI tcuLinkAddData_v2(CUlinkState state, CUjitInputType type, void* data, size_t size, const char* name, unsigned int numOptions, CUjit_option* options, void** optionValues); +typedef CUresult CUDAAPI tcuLinkAddFile_v2(CUlinkState state, CUjitInputType type, const char* path, unsigned int numOptions, CUjit_option* options, void** optionValues); +typedef CUresult CUDAAPI tcuLinkComplete(CUlinkState state, void** cubinOut, size_t* sizeOut); typedef CUresult CUDAAPI tcuLinkDestroy(CUlinkState state); typedef CUresult CUDAAPI tcuMemGetInfo_v2(size_t* free, size_t* total); typedef CUresult CUDAAPI tcuMemAlloc_v2(CUdeviceptr* dptr, size_t bytesize); typedef CUresult CUDAAPI tcuMemAllocPitch_v2(CUdeviceptr* dptr, size_t* pPitch, size_t WidthInBytes, size_t Height, unsigned int ElementSizeBytes); typedef CUresult CUDAAPI tcuMemFree_v2(CUdeviceptr dptr); typedef CUresult CUDAAPI tcuMemGetAddressRange_v2(CUdeviceptr* pbase, size_t* psize, CUdeviceptr dptr); -typedef CUresult CUDAAPI tcuMemAllocHost_v2(void* pp, size_t bytesize); +typedef CUresult CUDAAPI tcuMemAllocHost_v2(void** pp, size_t bytesize); typedef CUresult CUDAAPI tcuMemFreeHost(void* p); -typedef CUresult CUDAAPI tcuMemHostAlloc(void* pp, size_t bytesize, unsigned int Flags); +typedef CUresult CUDAAPI tcuMemHostAlloc(void** pp, size_t bytesize, unsigned int Flags); typedef CUresult CUDAAPI tcuMemHostGetDevicePointer_v2(CUdeviceptr* pdptr, void* p, unsigned int Flags); typedef CUresult CUDAAPI tcuMemHostGetFlags(unsigned int* pFlags, void* p); typedef CUresult CUDAAPI tcuMemAllocManaged(CUdeviceptr* dptr, size_t bytesize, unsigned int flags); @@ -863,8 +960,12 @@ typedef CUresult CUDAAPI tcuMipmappedArrayCreate(CUmipmappedArray* pHandle, cons typedef CUresult CUDAAPI tcuMipmappedArrayGetLevel(CUarray* pLevelArray, CUmipmappedArray hMipmappedArray, unsigned int level); typedef CUresult CUDAAPI tcuMipmappedArrayDestroy(CUmipmappedArray hMipmappedArray); typedef CUresult CUDAAPI tcuPointerGetAttribute(void* data, CUpointer_attribute attribute, CUdeviceptr ptr); +typedef CUresult CUDAAPI tcuMemPrefetchAsync(CUdeviceptr devPtr, size_t count, CUdevice dstDevice, CUstream hStream); +typedef CUresult CUDAAPI tcuMemAdvise(CUdeviceptr devPtr, size_t count, CUmem_advise advice, CUdevice device); +typedef CUresult CUDAAPI tcuMemRangeGetAttribute(void* data, size_t dataSize, CUmem_range_attribute attribute, CUdeviceptr devPtr, size_t count); +typedef CUresult CUDAAPI tcuMemRangeGetAttributes(void** data, size_t* dataSizes, CUmem_range_attribute* attributes, size_t numAttributes, CUdeviceptr devPtr, size_t count); typedef CUresult CUDAAPI tcuPointerSetAttribute(const void* value, CUpointer_attribute attribute, CUdeviceptr ptr); -typedef CUresult CUDAAPI tcuPointerGetAttributes(unsigned int numAttributes, CUpointer_attribute* attributes, void* data, CUdeviceptr ptr); +typedef CUresult CUDAAPI tcuPointerGetAttributes(unsigned int numAttributes, CUpointer_attribute* attributes, void** data, CUdeviceptr ptr); typedef CUresult CUDAAPI tcuStreamCreate(CUstream* phStream, unsigned int Flags); typedef CUresult CUDAAPI tcuStreamCreateWithPriority(CUstream* phStream, unsigned int flags, int priority); typedef CUresult CUDAAPI tcuStreamGetPriority(CUstream hStream, int* priority); @@ -881,10 +982,13 @@ typedef CUresult CUDAAPI tcuEventQuery(CUevent hEvent); typedef CUresult CUDAAPI tcuEventSynchronize(CUevent hEvent); typedef CUresult CUDAAPI tcuEventDestroy_v2(CUevent hEvent); typedef CUresult CUDAAPI tcuEventElapsedTime(float* pMilliseconds, CUevent hStart, CUevent hEnd); +typedef CUresult CUDAAPI tcuStreamWaitValue32(CUstream stream, CUdeviceptr addr, cuuint32_t value, unsigned int flags); +typedef CUresult CUDAAPI tcuStreamWriteValue32(CUstream stream, CUdeviceptr addr, cuuint32_t value, unsigned int flags); +typedef CUresult CUDAAPI tcuStreamBatchMemOp(CUstream stream, unsigned int count, CUstreamBatchMemOpParams* paramArray, unsigned int flags); typedef CUresult CUDAAPI tcuFuncGetAttribute(int* pi, CUfunction_attribute attrib, CUfunction hfunc); typedef CUresult CUDAAPI tcuFuncSetCacheConfig(CUfunction hfunc, CUfunc_cache config); typedef CUresult CUDAAPI tcuFuncSetSharedMemConfig(CUfunction hfunc, CUsharedconfig config); -typedef CUresult CUDAAPI tcuLaunchKernel(CUfunction f, unsigned int gridDimX, unsigned int gridDimY, unsigned int gridDimZ, unsigned int blockDimX, unsigned int blockDimY, unsigned int blockDimZ, unsigned int sharedMemBytes, CUstream hStream, void* kernelParams, void* extra); +typedef CUresult CUDAAPI tcuLaunchKernel(CUfunction f, unsigned int gridDimX, unsigned int gridDimY, unsigned int gridDimZ, unsigned int blockDimX, unsigned int blockDimY, unsigned int blockDimZ, unsigned int sharedMemBytes, CUstream hStream, void** kernelParams, void** extra); typedef CUresult CUDAAPI tcuFuncSetBlockShape(CUfunction hfunc, int x, int y, int z); typedef CUresult CUDAAPI tcuFuncSetSharedSize(CUfunction hfunc, unsigned int bytes); typedef CUresult CUDAAPI tcuParamSetSize(CUfunction hfunc, unsigned int numbytes); @@ -910,6 +1014,7 @@ typedef CUresult CUDAAPI tcuTexRefSetMipmapFilterMode(CUtexref hTexRef, CUfilter typedef CUresult CUDAAPI tcuTexRefSetMipmapLevelBias(CUtexref hTexRef, float bias); typedef CUresult CUDAAPI tcuTexRefSetMipmapLevelClamp(CUtexref hTexRef, float minMipmapLevelClamp, float maxMipmapLevelClamp); typedef CUresult CUDAAPI tcuTexRefSetMaxAnisotropy(CUtexref hTexRef, unsigned int maxAniso); +typedef CUresult CUDAAPI tcuTexRefSetBorderColor(CUtexref hTexRef, float* pBorderColor); typedef CUresult CUDAAPI tcuTexRefSetFlags(CUtexref hTexRef, unsigned int Flags); typedef CUresult CUDAAPI tcuTexRefGetAddress_v2(CUdeviceptr* pdptr, CUtexref hTexRef); typedef CUresult CUDAAPI tcuTexRefGetArray(CUarray* phArray, CUtexref hTexRef); @@ -921,6 +1026,7 @@ typedef CUresult CUDAAPI tcuTexRefGetMipmapFilterMode(CUfilter_mode* pfm, CUtexr typedef CUresult CUDAAPI tcuTexRefGetMipmapLevelBias(float* pbias, CUtexref hTexRef); typedef CUresult CUDAAPI tcuTexRefGetMipmapLevelClamp(float* pminMipmapLevelClamp, float* pmaxMipmapLevelClamp, CUtexref hTexRef); typedef CUresult CUDAAPI tcuTexRefGetMaxAnisotropy(int* pmaxAniso, CUtexref hTexRef); +typedef CUresult CUDAAPI tcuTexRefGetBorderColor(float* pBorderColor, CUtexref hTexRef); typedef CUresult CUDAAPI tcuTexRefGetFlags(unsigned int* pFlags, CUtexref hTexRef); typedef CUresult CUDAAPI tcuTexRefCreate(CUtexref* pTexRef); typedef CUresult CUDAAPI tcuTexRefDestroy(CUtexref hTexRef); @@ -935,6 +1041,7 @@ typedef CUresult CUDAAPI tcuSurfObjectCreate(CUsurfObject* pSurfObject, const CU typedef CUresult CUDAAPI tcuSurfObjectDestroy(CUsurfObject surfObject); typedef CUresult CUDAAPI tcuSurfObjectGetResourceDesc(CUDA_RESOURCE_DESC* pResDesc, CUsurfObject surfObject); typedef CUresult CUDAAPI tcuDeviceCanAccessPeer(int* canAccessPeer, CUdevice dev, CUdevice peerDev); +typedef CUresult CUDAAPI tcuDeviceGetP2PAttribute(int* value, CUdevice_P2PAttribute attrib, CUdevice srcDevice, CUdevice dstDevice); typedef CUresult CUDAAPI tcuCtxEnablePeerAccess(CUcontext peerContext, unsigned int Flags); typedef CUresult CUDAAPI tcuCtxDisablePeerAccess(CUcontext peerContext); typedef CUresult CUDAAPI tcuGraphicsUnregisterResource(CUgraphicsResource resource); @@ -944,7 +1051,7 @@ typedef CUresult CUDAAPI tcuGraphicsResourceGetMappedPointer_v2(CUdeviceptr* pDe typedef CUresult CUDAAPI tcuGraphicsResourceSetMapFlags_v2(CUgraphicsResource resource, unsigned int flags); typedef CUresult CUDAAPI tcuGraphicsMapResources(unsigned int count, CUgraphicsResource* resources, CUstream hStream); typedef CUresult CUDAAPI tcuGraphicsUnmapResources(unsigned int count, CUgraphicsResource* resources, CUstream hStream); -typedef CUresult CUDAAPI tcuGetExportTable(const void* ppExportTable, const CUuuid* pExportTableId); +typedef CUresult CUDAAPI tcuGetExportTable(const void** ppExportTable, const CUuuid* pExportTableId); typedef CUresult CUDAAPI tcuGraphicsGLRegisterBuffer(CUgraphicsResource* pCudaResource, GLuint buffer, unsigned int Flags); typedef CUresult CUDAAPI tcuGraphicsGLRegisterImage(CUgraphicsResource* pCudaResource, GLuint image, GLenum target, unsigned int Flags); @@ -961,13 +1068,15 @@ typedef CUresult CUDAAPI tcuGLUnmapBufferObjectAsync(GLuint buffer, CUstream hSt typedef const char* CUDAAPI tnvrtcGetErrorString(nvrtcResult result); typedef nvrtcResult CUDAAPI tnvrtcVersion(int* major, int* minor); -typedef nvrtcResult CUDAAPI tnvrtcCreateProgram(nvrtcProgram* prog, const char* src, const char* name, int numHeaders, const char* headers, const char* includeNames); +typedef nvrtcResult CUDAAPI tnvrtcCreateProgram(nvrtcProgram* prog, const char* src, const char* name, int numHeaders, const char** headers, const char** includeNames); typedef nvrtcResult CUDAAPI tnvrtcDestroyProgram(nvrtcProgram* prog); -typedef nvrtcResult CUDAAPI tnvrtcCompileProgram(nvrtcProgram prog, int numOptions, const char* options); +typedef nvrtcResult CUDAAPI tnvrtcCompileProgram(nvrtcProgram prog, int numOptions, const char** options); typedef nvrtcResult CUDAAPI tnvrtcGetPTXSize(nvrtcProgram prog, size_t* ptxSizeRet); typedef nvrtcResult CUDAAPI tnvrtcGetPTX(nvrtcProgram prog, char* ptx); typedef nvrtcResult CUDAAPI tnvrtcGetProgramLogSize(nvrtcProgram prog, size_t* logSizeRet); typedef nvrtcResult CUDAAPI tnvrtcGetProgramLog(nvrtcProgram prog, char* log); +typedef nvrtcResult CUDAAPI tnvrtcAddNameExpression(nvrtcProgram prog, const char* name_expression); +typedef nvrtcResult CUDAAPI tnvrtcGetLoweredName(nvrtcProgram prog, const char* name_expression, const char** lowered_name); /* Function declarations. */ @@ -1085,6 +1194,10 @@ extern tcuMipmappedArrayCreate *cuMipmappedArrayCreate; extern tcuMipmappedArrayGetLevel *cuMipmappedArrayGetLevel; extern tcuMipmappedArrayDestroy *cuMipmappedArrayDestroy; extern tcuPointerGetAttribute *cuPointerGetAttribute; +extern tcuMemPrefetchAsync *cuMemPrefetchAsync; +extern tcuMemAdvise *cuMemAdvise; +extern tcuMemRangeGetAttribute *cuMemRangeGetAttribute; +extern tcuMemRangeGetAttributes *cuMemRangeGetAttributes; extern tcuPointerSetAttribute *cuPointerSetAttribute; extern tcuPointerGetAttributes *cuPointerGetAttributes; extern tcuStreamCreate *cuStreamCreate; @@ -1103,6 +1216,9 @@ extern tcuEventQuery *cuEventQuery; extern tcuEventSynchronize *cuEventSynchronize; extern tcuEventDestroy_v2 *cuEventDestroy_v2; extern tcuEventElapsedTime *cuEventElapsedTime; +extern tcuStreamWaitValue32 *cuStreamWaitValue32; +extern tcuStreamWriteValue32 *cuStreamWriteValue32; +extern tcuStreamBatchMemOp *cuStreamBatchMemOp; extern tcuFuncGetAttribute *cuFuncGetAttribute; extern tcuFuncSetCacheConfig *cuFuncSetCacheConfig; extern tcuFuncSetSharedMemConfig *cuFuncSetSharedMemConfig; @@ -1132,6 +1248,7 @@ extern tcuTexRefSetMipmapFilterMode *cuTexRefSetMipmapFilterMode; extern tcuTexRefSetMipmapLevelBias *cuTexRefSetMipmapLevelBias; extern tcuTexRefSetMipmapLevelClamp *cuTexRefSetMipmapLevelClamp; extern tcuTexRefSetMaxAnisotropy *cuTexRefSetMaxAnisotropy; +extern tcuTexRefSetBorderColor *cuTexRefSetBorderColor; extern tcuTexRefSetFlags *cuTexRefSetFlags; extern tcuTexRefGetAddress_v2 *cuTexRefGetAddress_v2; extern tcuTexRefGetArray *cuTexRefGetArray; @@ -1143,6 +1260,7 @@ extern tcuTexRefGetMipmapFilterMode *cuTexRefGetMipmapFilterMode; extern tcuTexRefGetMipmapLevelBias *cuTexRefGetMipmapLevelBias; extern tcuTexRefGetMipmapLevelClamp *cuTexRefGetMipmapLevelClamp; extern tcuTexRefGetMaxAnisotropy *cuTexRefGetMaxAnisotropy; +extern tcuTexRefGetBorderColor *cuTexRefGetBorderColor; extern tcuTexRefGetFlags *cuTexRefGetFlags; extern tcuTexRefCreate *cuTexRefCreate; extern tcuTexRefDestroy *cuTexRefDestroy; @@ -1157,6 +1275,7 @@ extern tcuSurfObjectCreate *cuSurfObjectCreate; extern tcuSurfObjectDestroy *cuSurfObjectDestroy; extern tcuSurfObjectGetResourceDesc *cuSurfObjectGetResourceDesc; extern tcuDeviceCanAccessPeer *cuDeviceCanAccessPeer; +extern tcuDeviceGetP2PAttribute *cuDeviceGetP2PAttribute; extern tcuCtxEnablePeerAccess *cuCtxEnablePeerAccess; extern tcuCtxDisablePeerAccess *cuCtxDisablePeerAccess; extern tcuGraphicsUnregisterResource *cuGraphicsUnregisterResource; @@ -1190,6 +1309,8 @@ extern tnvrtcGetPTXSize *nvrtcGetPTXSize; extern tnvrtcGetPTX *nvrtcGetPTX; extern tnvrtcGetProgramLogSize *nvrtcGetProgramLogSize; extern tnvrtcGetProgramLog *nvrtcGetProgramLog; +extern tnvrtcAddNameExpression *nvrtcAddNameExpression; +extern tnvrtcGetLoweredName *nvrtcGetLoweredName; enum { diff --git a/extern/cuew/src/cuew.c b/extern/cuew/src/cuew.c index c96ea2c1959..962059bfcce 100644 --- a/extern/cuew/src/cuew.c +++ b/extern/cuew/src/cuew.c @@ -184,6 +184,10 @@ tcuMipmappedArrayCreate *cuMipmappedArrayCreate; tcuMipmappedArrayGetLevel *cuMipmappedArrayGetLevel; tcuMipmappedArrayDestroy *cuMipmappedArrayDestroy; tcuPointerGetAttribute *cuPointerGetAttribute; +tcuMemPrefetchAsync *cuMemPrefetchAsync; +tcuMemAdvise *cuMemAdvise; +tcuMemRangeGetAttribute *cuMemRangeGetAttribute; +tcuMemRangeGetAttributes *cuMemRangeGetAttributes; tcuPointerSetAttribute *cuPointerSetAttribute; tcuPointerGetAttributes *cuPointerGetAttributes; tcuStreamCreate *cuStreamCreate; @@ -202,6 +206,9 @@ tcuEventQuery *cuEventQuery; tcuEventSynchronize *cuEventSynchronize; tcuEventDestroy_v2 *cuEventDestroy_v2; tcuEventElapsedTime *cuEventElapsedTime; +tcuStreamWaitValue32 *cuStreamWaitValue32; +tcuStreamWriteValue32 *cuStreamWriteValue32; +tcuStreamBatchMemOp *cuStreamBatchMemOp; tcuFuncGetAttribute *cuFuncGetAttribute; tcuFuncSetCacheConfig *cuFuncSetCacheConfig; tcuFuncSetSharedMemConfig *cuFuncSetSharedMemConfig; @@ -231,6 +238,7 @@ tcuTexRefSetMipmapFilterMode *cuTexRefSetMipmapFilterMode; tcuTexRefSetMipmapLevelBias *cuTexRefSetMipmapLevelBias; tcuTexRefSetMipmapLevelClamp *cuTexRefSetMipmapLevelClamp; tcuTexRefSetMaxAnisotropy *cuTexRefSetMaxAnisotropy; +tcuTexRefSetBorderColor *cuTexRefSetBorderColor; tcuTexRefSetFlags *cuTexRefSetFlags; tcuTexRefGetAddress_v2 *cuTexRefGetAddress_v2; tcuTexRefGetArray *cuTexRefGetArray; @@ -242,6 +250,7 @@ tcuTexRefGetMipmapFilterMode *cuTexRefGetMipmapFilterMode; tcuTexRefGetMipmapLevelBias *cuTexRefGetMipmapLevelBias; tcuTexRefGetMipmapLevelClamp *cuTexRefGetMipmapLevelClamp; tcuTexRefGetMaxAnisotropy *cuTexRefGetMaxAnisotropy; +tcuTexRefGetBorderColor *cuTexRefGetBorderColor; tcuTexRefGetFlags *cuTexRefGetFlags; tcuTexRefCreate *cuTexRefCreate; tcuTexRefDestroy *cuTexRefDestroy; @@ -256,6 +265,7 @@ tcuSurfObjectCreate *cuSurfObjectCreate; tcuSurfObjectDestroy *cuSurfObjectDestroy; tcuSurfObjectGetResourceDesc *cuSurfObjectGetResourceDesc; tcuDeviceCanAccessPeer *cuDeviceCanAccessPeer; +tcuDeviceGetP2PAttribute *cuDeviceGetP2PAttribute; tcuCtxEnablePeerAccess *cuCtxEnablePeerAccess; tcuCtxDisablePeerAccess *cuCtxDisablePeerAccess; tcuGraphicsUnregisterResource *cuGraphicsUnregisterResource; @@ -289,6 +299,8 @@ tnvrtcGetPTXSize *nvrtcGetPTXSize; tnvrtcGetPTX *nvrtcGetPTX; tnvrtcGetProgramLogSize *nvrtcGetProgramLogSize; tnvrtcGetProgramLog *nvrtcGetProgramLog; +tnvrtcAddNameExpression *nvrtcAddNameExpression; +tnvrtcGetLoweredName *nvrtcGetLoweredName; static DynamicLibrary dynamic_library_open_find(const char **paths) { @@ -486,6 +498,10 @@ int cuewInit(void) { CUDA_LIBRARY_FIND(cuMipmappedArrayGetLevel); CUDA_LIBRARY_FIND(cuMipmappedArrayDestroy); CUDA_LIBRARY_FIND(cuPointerGetAttribute); + CUDA_LIBRARY_FIND(cuMemPrefetchAsync); + CUDA_LIBRARY_FIND(cuMemAdvise); + CUDA_LIBRARY_FIND(cuMemRangeGetAttribute); + CUDA_LIBRARY_FIND(cuMemRangeGetAttributes); CUDA_LIBRARY_FIND(cuPointerSetAttribute); CUDA_LIBRARY_FIND(cuPointerGetAttributes); CUDA_LIBRARY_FIND(cuStreamCreate); @@ -504,6 +520,9 @@ int cuewInit(void) { CUDA_LIBRARY_FIND(cuEventSynchronize); CUDA_LIBRARY_FIND(cuEventDestroy_v2); CUDA_LIBRARY_FIND(cuEventElapsedTime); + CUDA_LIBRARY_FIND(cuStreamWaitValue32); + CUDA_LIBRARY_FIND(cuStreamWriteValue32); + CUDA_LIBRARY_FIND(cuStreamBatchMemOp); CUDA_LIBRARY_FIND(cuFuncGetAttribute); CUDA_LIBRARY_FIND(cuFuncSetCacheConfig); CUDA_LIBRARY_FIND(cuFuncSetSharedMemConfig); @@ -533,6 +552,7 @@ int cuewInit(void) { CUDA_LIBRARY_FIND(cuTexRefSetMipmapLevelBias); CUDA_LIBRARY_FIND(cuTexRefSetMipmapLevelClamp); CUDA_LIBRARY_FIND(cuTexRefSetMaxAnisotropy); + CUDA_LIBRARY_FIND(cuTexRefSetBorderColor); CUDA_LIBRARY_FIND(cuTexRefSetFlags); CUDA_LIBRARY_FIND(cuTexRefGetAddress_v2); CUDA_LIBRARY_FIND(cuTexRefGetArray); @@ -544,6 +564,7 @@ int cuewInit(void) { CUDA_LIBRARY_FIND(cuTexRefGetMipmapLevelBias); CUDA_LIBRARY_FIND(cuTexRefGetMipmapLevelClamp); CUDA_LIBRARY_FIND(cuTexRefGetMaxAnisotropy); + CUDA_LIBRARY_FIND(cuTexRefGetBorderColor); CUDA_LIBRARY_FIND(cuTexRefGetFlags); CUDA_LIBRARY_FIND(cuTexRefCreate); CUDA_LIBRARY_FIND(cuTexRefDestroy); @@ -558,6 +579,7 @@ int cuewInit(void) { CUDA_LIBRARY_FIND(cuSurfObjectDestroy); CUDA_LIBRARY_FIND(cuSurfObjectGetResourceDesc); CUDA_LIBRARY_FIND(cuDeviceCanAccessPeer); + CUDA_LIBRARY_FIND(cuDeviceGetP2PAttribute); CUDA_LIBRARY_FIND(cuCtxEnablePeerAccess); CUDA_LIBRARY_FIND(cuCtxDisablePeerAccess); CUDA_LIBRARY_FIND(cuGraphicsUnregisterResource); @@ -593,6 +615,8 @@ int cuewInit(void) { NVRTC_LIBRARY_FIND(nvrtcGetPTX); NVRTC_LIBRARY_FIND(nvrtcGetProgramLogSize); NVRTC_LIBRARY_FIND(nvrtcGetProgramLog); + NVRTC_LIBRARY_FIND(nvrtcAddNameExpression); + NVRTC_LIBRARY_FIND(nvrtcGetLoweredName); } result = CUEW_SUCCESS; @@ -630,6 +654,7 @@ const char *cuewErrorString(CUresult result) { case CUDA_ERROR_PEER_ACCESS_UNSUPPORTED: return "Peer access unsupported"; case CUDA_ERROR_INVALID_PTX: return "Invalid ptx"; case CUDA_ERROR_INVALID_GRAPHICS_CONTEXT: return "Invalid graphics context"; + case CUDA_ERROR_NVLINK_UNCORRECTABLE: return "Nvlink uncorrectable"; case CUDA_ERROR_INVALID_SOURCE: return "Invalid source"; case CUDA_ERROR_FILE_NOT_FOUND: return "File not found"; case CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND: return "Link to a shared object failed to resolve"; diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c index 96ec9a33270..b5340efdcb2 100644 --- a/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c +++ b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c @@ -137,7 +137,7 @@ struct Knot { /* Initially point to contiguous memory, however we may re-assign */ double *tan[2]; -} Knot; +}; struct KnotRemoveState { @@ -1102,7 +1102,7 @@ int curve_fit_cubic_to_points_refit_db( uint **r_corner_index_array, uint *r_corner_index_len) { const uint knots_len = points_len; - struct Knot *knots = malloc(sizeof(Knot) * knots_len); + struct Knot *knots = malloc(sizeof(struct Knot) * knots_len); #ifndef USE_CORNER_DETECT (void)r_corner_index_array; diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h index 1e9528f9ed9..38670be56fd 100644 --- a/intern/atomic/atomic_ops.h +++ b/intern/atomic/atomic_ops.h @@ -100,6 +100,7 @@ ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x); ATOMIC_INLINE size_t atomic_fetch_and_add_z(size_t *p, size_t x); ATOMIC_INLINE size_t atomic_fetch_and_sub_z(size_t *p, size_t x); ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new); +ATOMIC_INLINE size_t atomic_fetch_and_update_max_z(size_t *p, size_t x); /* Uses CAS loop, see warning below. */ ATOMIC_INLINE unsigned int atomic_add_and_fetch_u(unsigned int *p, unsigned int x); ATOMIC_INLINE unsigned int atomic_sub_and_fetch_u(unsigned int *p, unsigned int x); @@ -107,6 +108,8 @@ ATOMIC_INLINE unsigned int atomic_fetch_and_add_u(unsigned int *p, unsigned int ATOMIC_INLINE unsigned int atomic_fetch_and_sub_u(unsigned int *p, unsigned int x); ATOMIC_INLINE unsigned int atomic_cas_u(unsigned int *v, unsigned int old, unsigned int _new); +ATOMIC_INLINE void *atomic_cas_ptr(void **v, void *old, void *_new); + /* WARNING! Float 'atomics' are really faked ones, those are actually closer to some kind of spinlock-sync'ed operation, * which means they are only efficient if collisions are highly unlikely (i.e. if probability of two threads * working on the same pointer at the same time is very low). */ diff --git a/intern/atomic/intern/atomic_ops_ext.h b/intern/atomic/intern/atomic_ops_ext.h index b72c94563fc..34158a0b45e 100644 --- a/intern/atomic/intern/atomic_ops_ext.h +++ b/intern/atomic/intern/atomic_ops_ext.h @@ -111,6 +111,17 @@ ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new) #endif } +ATOMIC_INLINE size_t atomic_fetch_and_update_max_z(size_t *p, size_t x) +{ + size_t prev_value; + while((prev_value = *p) < x) { + if(atomic_cas_z(p, prev_value, x) == prev_value) { + break; + } + } + return prev_value; +} + /******************************************************************************/ /* unsigned operations. */ ATOMIC_INLINE unsigned int atomic_add_and_fetch_u(unsigned int *p, unsigned int x) @@ -169,6 +180,18 @@ ATOMIC_INLINE unsigned int atomic_cas_u(unsigned int *v, unsigned int old, unsig } /******************************************************************************/ +/* Pointer operations. */ + +ATOMIC_INLINE void *atomic_cas_ptr(void **v, void *old, void *_new) +{ +#if (LG_SIZEOF_PTR == 8) + return (void *)atomic_cas_uint64((uint64_t *)v, *(uint64_t *)&old, *(uint64_t *)&_new); +#elif (LG_SIZEOF_PTR == 4) + return (void *)atomic_cas_uint32((uint32_t *)v, *(uint32_t *)&old, *(uint32_t *)&_new); +#endif +} + +/******************************************************************************/ /* float operations. */ ATOMIC_INLINE float atomic_add_and_fetch_fl(float *p, const float x) diff --git a/intern/atomic/intern/atomic_ops_utils.h b/intern/atomic/intern/atomic_ops_utils.h index bfec9918c16..c190b655e0a 100644 --- a/intern/atomic/intern/atomic_ops_utils.h +++ b/intern/atomic/intern/atomic_ops_utils.h @@ -52,8 +52,8 @@ #ifndef __ATOMIC_OPS_UTILS_H__ #define __ATOMIC_OPS_UTILS_H__ -/* needed for int types */ -#include "../../../source/blender/blenlib/BLI_sys_types.h" +#include <stdint.h> +#include <stddef.h> #include <stdlib.h> #include <limits.h> @@ -63,12 +63,7 @@ #if defined(_MSC_VER) # define ATOMIC_INLINE static __forceinline #else -# if (defined(__APPLE__) && defined(__ppc__)) -/* static inline __attribute__ here breaks osx ppc gcc42 build */ -# define ATOMIC_INLINE static __attribute__((always_inline)) -# else -# define ATOMIC_INLINE static inline __attribute__((always_inline)) -# endif +# define ATOMIC_INLINE static inline __attribute__((always_inline)) #endif #ifndef LIKELY diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.cpp b/intern/audaspace/intern/AUD_SoftwareDevice.cpp index f9d65aa2363..10e42a82b76 100644 --- a/intern/audaspace/intern/AUD_SoftwareDevice.cpp +++ b/intern/audaspace/intern/AUD_SoftwareDevice.cpp @@ -89,7 +89,7 @@ bool AUD_SoftwareDevice::AUD_SoftwareHandle::pause(bool keep) } AUD_SoftwareDevice::AUD_SoftwareHandle::AUD_SoftwareHandle(AUD_SoftwareDevice* device, boost::shared_ptr<AUD_IReader> reader, boost::shared_ptr<AUD_PitchReader> pitch, boost::shared_ptr<AUD_ResampleReader> resampler, boost::shared_ptr<AUD_ChannelMapperReader> mapper, bool keep) : - m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(1.0f), m_old_volume(1.0f), m_loopcount(0), + m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(0.0f), m_old_volume(0.0f), m_loopcount(0), m_relative(true), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits<float>::max()), m_distance_reference(1.0f), m_attenuation(1.0f), m_cone_angle_outer(M_PI), m_cone_angle_inner(M_PI), m_cone_volume_outer(0), m_flags(AUD_RENDER_CONE), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING), m_device(device) diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index c53a9f91cc0..5844c2480d6 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -41,61 +41,65 @@ elseif(WIN32 AND MSVC) set(CYCLES_AVX2_ARCH_FLAGS "/arch:SSE2") endif() + # Unlike GCC/clang we still use fast math, because there is no fine + # grained control and the speedup we get here is too big to ignore. + set(CYCLES_KERNEL_FLAGS "/fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") + # there is no /arch:SSE3, but intrinsics are available anyway if(CMAKE_CL_64) - set(CYCLES_SSE2_KERNEL_FLAGS "/fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") - set(CYCLES_SSE3_KERNEL_FLAGS "/fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") - set(CYCLES_SSE41_KERNEL_FLAGS "/fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") - set(CYCLES_AVX_KERNEL_FLAGS "${CYCLES_AVX_ARCH_FLAGS} /fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") - set(CYCLES_AVX2_KERNEL_FLAGS "${CYCLES_AVX2_ARCH_FLAGS} /fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") + set(CYCLES_SSE2_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS}") + set(CYCLES_SSE3_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS}") + set(CYCLES_SSE41_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS}") + set(CYCLES_AVX_KERNEL_FLAGS "${CYCLES_AVX_ARCH_FLAGS} ${CYCLES_KERNEL_FLAGS}") + set(CYCLES_AVX2_KERNEL_FLAGS "${CYCLES_AVX2_ARCH_FLAGS} ${CYCLES_KERNEL_FLAGS}") else() - set(CYCLES_SSE2_KERNEL_FLAGS "/arch:SSE2 /fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") - set(CYCLES_SSE3_KERNEL_FLAGS "/arch:SSE2 /fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") - set(CYCLES_SSE41_KERNEL_FLAGS "/arch:SSE2 /fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") - set(CYCLES_AVX_KERNEL_FLAGS "${CYCLES_AVX_ARCH_FLAGS} /fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") - set(CYCLES_AVX2_KERNEL_FLAGS "${CYCLES_AVX2_ARCH_FLAGS} /fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") + set(CYCLES_SSE2_KERNEL_FLAGS "/arch:SSE2 ${CYCLES_KERNEL_FLAGS}") + set(CYCLES_SSE3_KERNEL_FLAGS "/arch:SSE2 ${CYCLES_KERNEL_FLAGS}") + set(CYCLES_SSE41_KERNEL_FLAGS "/arch:SSE2 ${CYCLES_KERNEL_FLAGS}") + set(CYCLES_AVX_KERNEL_FLAGS "${CYCLES_AVX_ARCH_FLAGS} ${CYCLES_KERNEL_FLAGS}") + set(CYCLES_AVX2_KERNEL_FLAGS "${CYCLES_AVX2_ARCH_FLAGS} ${CYCLES_KERNEL_FLAGS}") endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CYCLES_KERNEL_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ox") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Ox") set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /Ox") - - set(CYCLES_KERNEL_FLAGS "/fp:fast -D_CRT_SECURE_NO_WARNINGS /GS-") -elseif(CMAKE_COMPILER_IS_GNUCC) +elseif(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) check_cxx_compiler_flag(-msse CXX_HAS_SSE) check_cxx_compiler_flag(-mavx CXX_HAS_AVX) check_cxx_compiler_flag(-mavx2 CXX_HAS_AVX2) - set(CYCLES_KERNEL_FLAGS "-ffast-math") - if(CXX_HAS_SSE) - set(CYCLES_SSE2_KERNEL_FLAGS "-ffast-math -msse -msse2 -mfpmath=sse") - set(CYCLES_SSE3_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse") - set(CYCLES_SSE41_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mfpmath=sse") - endif() - if(CXX_HAS_AVX) - set(CYCLES_AVX_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mfpmath=sse") - endif() - if(CXX_HAS_AVX2) - set(CYCLES_AVX2_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c -mfpmath=sse") + + # Assume no signal trapping for better code generation. + set(CYCLES_KERNEL_FLAGS "-fno-trapping-math") + # Avoid overhead of setting errno for NaNs. + set(CYCLES_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS} -fno-math-errno") + # Let compiler optimize 0.0 - x without worrying about signed zeros. + set(CYCLES_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS} -fno-signed-zeros") + + if(CMAKE_COMPILER_IS_GNUCC) + # Assume no signal trapping for better code generation. + set(CYCLES_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS} -fno-signaling-nans") + # Assume a fixed rounding mode for better constant folding. + set(CYCLES_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS} -fno-rounding-math") endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math -fno-finite-math-only") -elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - check_cxx_compiler_flag(-msse CXX_HAS_SSE) - check_cxx_compiler_flag(-mavx CXX_HAS_AVX) - check_cxx_compiler_flag(-mavx2 CXX_HAS_AVX2) - set(CYCLES_KERNEL_FLAGS "-ffast-math") + if(CXX_HAS_SSE) - set(CYCLES_SSE2_KERNEL_FLAGS "-ffast-math -msse -msse2") - set(CYCLES_SSE3_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3") - set(CYCLES_SSE41_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1") - endif() - if(CXX_HAS_AVX) - set(CYCLES_AVX_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx") - endif() - if(CXX_HAS_AVX2) - set(CYCLES_AVX2_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c") + if(CMAKE_COMPILER_IS_GNUCC) + set(CYCLES_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS} -mfpmath=sse") + endif() + + set(CYCLES_SSE2_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS} -msse -msse2") + set(CYCLES_SSE3_KERNEL_FLAGS "${CYCLES_SSE2_KERNEL_FLAGS} -msse3 -mssse3") + set(CYCLES_SSE41_KERNEL_FLAGS "${CYCLES_SSE3_KERNEL_FLAGS} -msse4.1") + if(CXX_HAS_AVX) + set(CYCLES_AVX_KERNEL_FLAGS "${CYCLES_SSE41_KERNEL_FLAGS} -mavx") + endif() + if(CXX_HAS_AVX2) + set(CYCLES_AVX2_KERNEL_FLAGS "${CYCLES_SSE41_KERNEL_FLAGS} -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c") + endif() endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math -fno-finite-math-only") + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CYCLES_KERNEL_FLAGS}") endif() if(CXX_HAS_SSE) diff --git a/intern/cycles/blender/addon/presets.py b/intern/cycles/blender/addon/presets.py index 82c4ffc6e50..17efb00abdb 100644 --- a/intern/cycles/blender/addon/presets.py +++ b/intern/cycles/blender/addon/presets.py @@ -32,14 +32,11 @@ class AddPresetIntegrator(AddPresetBase, Operator): preset_values = [ "cycles.max_bounces", - "cycles.min_bounces", "cycles.diffuse_bounces", "cycles.glossy_bounces", "cycles.transmission_bounces", "cycles.volume_bounces", - "cycles.transparent_min_bounces", "cycles.transparent_max_bounces", - "cycles.use_transparent_shadows", "cycles.caustics_reflective", "cycles.caustics_refractive", "cycles.blur_glossy" diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 68474529ed3..7b16ef1d543 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -205,13 +205,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): name="AA Samples", description="Number of antialiasing samples to render for each pixel", min=1, max=2097151, - default=4, + default=128, ) cls.preview_aa_samples = IntProperty( name="AA Samples", description="Number of antialiasing samples to render in the viewport, unlimited if 0", min=0, max=2097151, - default=4, + default=32, ) cls.diffuse_samples = IntProperty( name="Diffuse Samples", @@ -308,17 +308,9 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Adaptively blur glossy shaders after blurry bounces, " "to reduce noise at the cost of accuracy", min=0.0, max=10.0, - default=0.0, + default=1.0, ) - cls.min_bounces = IntProperty( - name="Min Bounces", - description="Minimum number of bounces, setting this lower " - "than the maximum enables probabilistic path " - "termination (faster but noisier)", - min=0, max=1024, - default=3, - ) cls.max_bounces = IntProperty( name="Max Bounces", description="Total maximum number of bounces", @@ -351,26 +343,12 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): default=0, ) - cls.transparent_min_bounces = IntProperty( - name="Transparent Min Bounces", - description="Minimum number of transparent bounces, setting " - "this lower than the maximum enables " - "probabilistic path termination (faster but " - "noisier)", - min=0, max=1024, - default=8, - ) cls.transparent_max_bounces = IntProperty( name="Transparent Max Bounces", description="Maximum number of transparent bounces", min=0, max=1024, default=8, ) - cls.use_transparent_shadows = BoolProperty( - name="Transparent Shadows", - description="Use transparency of surfaces for rendering shadows", - default=True, - ) cls.volume_step_size = FloatProperty( name="Step Size", @@ -475,7 +453,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): "higher values will be scaled down to avoid too " "much noise and slow convergence at the cost of accuracy", min=0.0, max=1e8, - default=0.0, + default=10.0, ) cls.debug_tile_size = IntProperty( diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 49beebe5ab4..7ab47455c49 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -139,7 +139,7 @@ def draw_samples_info(layout, context): (ao * aa, ml * aa, sss * aa, vol * aa)) -class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel): bl_label = "Sampling" bl_options = {'DEFAULT_CLOSED'} @@ -214,7 +214,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): draw_samples_info(layout, context) -class CyclesRender_PT_geometry(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_geometry(CyclesButtonsPanel, Panel): bl_label = "Geometry" bl_options = {'DEFAULT_CLOSED'} @@ -270,7 +270,7 @@ class CyclesRender_PT_geometry(CyclesButtonsPanel, Panel): row.prop(ccscene, "maximum_width", text="Max Extension") -class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_light_paths(CyclesButtonsPanel, Panel): bl_label = "Light Paths" bl_options = {'DEFAULT_CLOSED'} @@ -292,8 +292,6 @@ class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel): sub = col.column(align=True) sub.label("Transparency:") sub.prop(cscene, "transparent_max_bounces", text="Max") - sub.prop(cscene, "transparent_min_bounces", text="Min") - sub.prop(cscene, "use_transparent_shadows", text="Shadows") col.separator() @@ -306,7 +304,6 @@ class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel): sub = col.column(align=True) sub.label(text="Bounces:") sub.prop(cscene, "max_bounces", text="Max") - sub.prop(cscene, "min_bounces", text="Min") sub = col.column(align=True) sub.prop(cscene, "diffuse_bounces", text="Diffuse") @@ -315,7 +312,7 @@ class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel): sub.prop(cscene, "volume_bounces", text="Volume") -class CyclesRender_PT_motion_blur(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_motion_blur(CyclesButtonsPanel, Panel): bl_label = "Motion Blur" bl_options = {'DEFAULT_CLOSED'} @@ -356,7 +353,7 @@ class CyclesRender_PT_motion_blur(CyclesButtonsPanel, Panel): row.prop(cscene, "rolling_shutter_duration") -class CyclesRender_PT_film(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_film(CyclesButtonsPanel, Panel): bl_label = "Film" def draw(self, context): @@ -378,7 +375,7 @@ class CyclesRender_PT_film(CyclesButtonsPanel, Panel): sub.prop(cscene, "filter_width", text="Width") -class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_performance(CyclesButtonsPanel, Panel): bl_label = "Performance" bl_options = {'DEFAULT_CLOSED'} @@ -399,6 +396,8 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): sub.enabled = rd.threads_mode == 'FIXED' sub.prop(rd, "threads") + col.separator() + sub = col.column(align=True) sub.label(text="Tiles:") sub.prop(cscene, "tile_order", text="") @@ -408,19 +407,10 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): sub.prop(cscene, "use_progressive_refine") - subsub = sub.column(align=True) - subsub.prop(rd, "use_save_buffers") - - col = split.column(align=True) - - col.label(text="Viewport:") - col.prop(cscene, "debug_bvh_type", text="") - col.separator() - col.prop(cscene, "preview_start_resolution") - - col.separator() + col = split.column() col.label(text="Final Render:") + col.prop(rd, "use_save_buffers") col.prop(rd, "use_persistent_data", text="Persistent Images") col.separator() @@ -433,8 +423,14 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): row.active = not cscene.debug_use_spatial_splits row.prop(cscene, "debug_bvh_time_steps") + col = layout.column() + col.label(text="Viewport Resolution:") + split = col.split() + split.prop(rd, "preview_pixel_size", text="") + split.prop(cscene, "preview_start_resolution") + -class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_layer_options(CyclesButtonsPanel, Panel): bl_label = "Layer" bl_context = "render_layer" @@ -470,7 +466,7 @@ class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel): col.prop(rl, "use_strand", "Use Hair") -class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_layer_passes(CyclesButtonsPanel, Panel): bl_label = "Passes" bl_context = "render_layer" bl_options = {'DEFAULT_CLOSED'} @@ -544,7 +540,7 @@ class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel): col.prop(crl, "pass_debug_ray_bounces") -class CyclesRender_PT_views(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_views(CyclesButtonsPanel, Panel): bl_label = "Views" bl_context = "render_layer" bl_options = {'DEFAULT_CLOSED'} @@ -587,7 +583,7 @@ class CyclesRender_PT_views(CyclesButtonsPanel, Panel): row.prop(rv, "camera_suffix", text="") -class CyclesRender_PT_denoising(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel): bl_label = "Denoising" bl_context = "render_layer" bl_options = {'DEFAULT_CLOSED'} @@ -652,7 +648,7 @@ class CyclesRender_PT_denoising(CyclesButtonsPanel, Panel): sub.prop(crl, "denoising_subsurface_indirect", text="Indirect", toggle=True) -class Cycles_PT_post_processing(CyclesButtonsPanel, Panel): +class CYCLES_PT_post_processing(CyclesButtonsPanel, Panel): bl_label = "Post Processing" bl_options = {'DEFAULT_CLOSED'} @@ -671,7 +667,7 @@ class Cycles_PT_post_processing(CyclesButtonsPanel, Panel): col.prop(rd, "dither_intensity", text="Dither", slider=True) -class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel): +class CYCLES_CAMERA_PT_dof(CyclesButtonsPanel, Panel): bl_label = "Depth of Field" bl_context = "data" @@ -722,7 +718,7 @@ class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel): sub.prop(ccam, "aperture_ratio", text="Ratio") -class Cycles_PT_context_material(CyclesButtonsPanel, Panel): +class CYCLES_PT_context_material(CyclesButtonsPanel, Panel): bl_label = "" bl_context = "material" bl_options = {'HIDE_HEADER'} @@ -782,7 +778,7 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel): split.separator() -class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel): +class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel): bl_label = "Motion Blur" bl_context = "object" bl_options = {'DEFAULT_CLOSED'} @@ -830,7 +826,7 @@ class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel): sub.prop(cob, "motion_steps", text="Steps") -class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel): +class CYCLES_OBJECT_PT_cycles_settings(CyclesButtonsPanel, Panel): bl_label = "Cycles Settings" bl_context = "object" bl_options = {'DEFAULT_CLOSED'} @@ -939,7 +935,7 @@ def panel_node_draw(layout, id_data, output_type, input_name): return True -class CyclesLamp_PT_preview(CyclesButtonsPanel, Panel): +class CYCLES_LAMP_PT_preview(CyclesButtonsPanel, Panel): bl_label = "Preview" bl_context = "data" bl_options = {'DEFAULT_CLOSED'} @@ -955,7 +951,7 @@ class CyclesLamp_PT_preview(CyclesButtonsPanel, Panel): self.layout.template_preview(context.lamp) -class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel): +class CYCLES_LAMP_PT_lamp(CyclesButtonsPanel, Panel): bl_label = "Lamp" bl_context = "data" @@ -1009,7 +1005,7 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel): layout.label(text="Not supported, interpreted as sun lamp") -class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel): +class CYCLES_LAMP_PT_nodes(CyclesButtonsPanel, Panel): bl_label = "Nodes" bl_context = "data" @@ -1027,7 +1023,7 @@ class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel): layout.prop(lamp, "color") -class CyclesLamp_PT_spot(CyclesButtonsPanel, Panel): +class CYCLES_LAMP_PT_spot(CyclesButtonsPanel, Panel): bl_label = "Spot Shape" bl_context = "data" @@ -1052,7 +1048,7 @@ class CyclesLamp_PT_spot(CyclesButtonsPanel, Panel): col.prop(lamp, "show_cone") -class CyclesWorld_PT_preview(CyclesButtonsPanel, Panel): +class CYCLES_WORLD_PT_preview(CyclesButtonsPanel, Panel): bl_label = "Preview" bl_context = "world" bl_options = {'DEFAULT_CLOSED'} @@ -1065,7 +1061,7 @@ class CyclesWorld_PT_preview(CyclesButtonsPanel, Panel): self.layout.template_preview(context.world) -class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel): +class CYCLES_WORLD_PT_surface(CyclesButtonsPanel, Panel): bl_label = "Surface" bl_context = "world" @@ -1082,7 +1078,7 @@ class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel): layout.prop(world, "horizon_color", text="Color") -class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel): +class CYCLES_WORLD_PT_volume(CyclesButtonsPanel, Panel): bl_label = "Volume" bl_context = "world" bl_options = {'DEFAULT_CLOSED'} @@ -1099,7 +1095,7 @@ class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel): panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume') -class CyclesWorld_PT_ambient_occlusion(CyclesButtonsPanel, Panel): +class CYCLES_WORLD_PT_ambient_occlusion(CyclesButtonsPanel, Panel): bl_label = "Ambient Occlusion" bl_context = "world" @@ -1124,7 +1120,7 @@ class CyclesWorld_PT_ambient_occlusion(CyclesButtonsPanel, Panel): row.prop(light, "distance", text="Distance") -class CyclesWorld_PT_mist(CyclesButtonsPanel, Panel): +class CYCLES_WORLD_PT_mist(CyclesButtonsPanel, Panel): bl_label = "Mist Pass" bl_context = "world" bl_options = {'DEFAULT_CLOSED'} @@ -1151,7 +1147,7 @@ class CyclesWorld_PT_mist(CyclesButtonsPanel, Panel): layout.prop(world.mist_settings, "falloff") -class CyclesWorld_PT_ray_visibility(CyclesButtonsPanel, Panel): +class CYCLES_WORLD_PT_ray_visibility(CyclesButtonsPanel, Panel): bl_label = "Ray Visibility" bl_context = "world" bl_options = {'DEFAULT_CLOSED'} @@ -1175,7 +1171,7 @@ class CyclesWorld_PT_ray_visibility(CyclesButtonsPanel, Panel): flow.prop(visibility, "scatter") -class CyclesWorld_PT_settings(CyclesButtonsPanel, Panel): +class CYCLES_WORLD_PT_settings(CyclesButtonsPanel, Panel): bl_label = "Settings" bl_context = "world" bl_options = {'DEFAULT_CLOSED'} @@ -1216,7 +1212,7 @@ class CyclesWorld_PT_settings(CyclesButtonsPanel, Panel): col.prop(cworld, "homogeneous_volume", text="Homogeneous") -class CyclesMaterial_PT_preview(CyclesButtonsPanel, Panel): +class CYCLES_MATERIAL_PT_preview(CyclesButtonsPanel, Panel): bl_label = "Preview" bl_context = "material" bl_options = {'DEFAULT_CLOSED'} @@ -1229,7 +1225,7 @@ class CyclesMaterial_PT_preview(CyclesButtonsPanel, Panel): self.layout.template_preview(context.material) -class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel): +class CYCLES_MATERIAL_PT_surface(CyclesButtonsPanel, Panel): bl_label = "Surface" bl_context = "material" @@ -1245,7 +1241,7 @@ class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel): layout.prop(mat, "diffuse_color") -class CyclesMaterial_PT_volume(CyclesButtonsPanel, Panel): +class CYCLES_MATERIAL_PT_volume(CyclesButtonsPanel, Panel): bl_label = "Volume" bl_context = "material" bl_options = {'DEFAULT_CLOSED'} @@ -1264,7 +1260,7 @@ class CyclesMaterial_PT_volume(CyclesButtonsPanel, Panel): panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume') -class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel): +class CYCLES_MATERIAL_PT_displacement(CyclesButtonsPanel, Panel): bl_label = "Displacement" bl_context = "material" @@ -1280,7 +1276,7 @@ class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel): panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement') -class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel): +class CYCLES_MATERIAL_PT_settings(CyclesButtonsPanel, Panel): bl_label = "Settings" bl_context = "material" bl_options = {'DEFAULT_CLOSED'} @@ -1335,7 +1331,7 @@ class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel): col.prop(mat, "pass_index") -class CyclesTexture_PT_context(CyclesButtonsPanel, Panel): +class CYCLES_TEXTURE_PT_context(CyclesButtonsPanel, Panel): bl_label = "" bl_context = "texture" bl_options = {'HIDE_HEADER'} @@ -1376,7 +1372,7 @@ class CyclesTexture_PT_context(CyclesButtonsPanel, Panel): split.prop(tex, "type", text="") -class CyclesTexture_PT_node(CyclesButtonsPanel, Panel): +class CYCLES_TEXTURE_PT_node(CyclesButtonsPanel, Panel): bl_label = "Node" bl_context = "texture" @@ -1393,7 +1389,7 @@ class CyclesTexture_PT_node(CyclesButtonsPanel, Panel): layout.template_node_view(ntree, node, None) -class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel): +class CYCLES_TEXTURE_PT_mapping(CyclesButtonsPanel, Panel): bl_label = "Mapping" bl_context = "texture" @@ -1426,7 +1422,7 @@ class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel): row.prop(mapping, "mapping_z", text="") -class CyclesTexture_PT_colors(CyclesButtonsPanel, Panel): +class CYCLES_TEXTURE_PT_colors(CyclesButtonsPanel, Panel): bl_label = "Color" bl_context = "texture" bl_options = {'DEFAULT_CLOSED'} @@ -1465,7 +1461,7 @@ class CyclesTexture_PT_colors(CyclesButtonsPanel, Panel): layout.template_color_ramp(mapping, "color_ramp", expand=True) -class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel): +class CYCLES_PARTICLE_PT_textures(CyclesButtonsPanel, Panel): bl_label = "Textures" bl_context = "particle" bl_options = {'DEFAULT_CLOSED'} @@ -1496,7 +1492,7 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel): layout.template_ID(slot, "texture", new="texture.new") -class CyclesRender_PT_bake(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_bake(CyclesButtonsPanel, Panel): bl_label = "Bake" bl_context = "render" bl_options = {'DEFAULT_CLOSED'} @@ -1569,7 +1565,7 @@ class CyclesRender_PT_bake(CyclesButtonsPanel, Panel): sub.prop(cbk, "cage_extrusion", text="Ray Distance") -class CyclesRender_PT_debug(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel): bl_label = "Debug" bl_context = "render" bl_options = {'DEFAULT_CLOSED'} @@ -1597,11 +1593,15 @@ class CyclesRender_PT_debug(CyclesButtonsPanel, Panel): col.prop(cscene, "debug_use_qbvh") col.prop(cscene, "debug_use_cpu_split_kernel") + col.separator() + col = layout.column() col.label('CUDA Flags:') col.prop(cscene, "debug_use_cuda_adaptive_compile") col.prop(cscene, "debug_use_cuda_split_kernel") + col.separator() + col = layout.column() col.label('OpenCL Flags:') col.prop(cscene, "debug_opencl_kernel_type", text="Kernel") @@ -1610,8 +1610,13 @@ class CyclesRender_PT_debug(CyclesButtonsPanel, Panel): col.prop(cscene, "debug_use_opencl_debug", text="Debug") col.prop(cscene, "debug_opencl_mem_limit") + col.separator() + + col = layout.column() + col.prop(cscene, "debug_bvh_type") + -class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel): +class CYCLES_PARTICLE_PT_curve_settings(CyclesButtonsPanel, Panel): bl_label = "Cycles Hair Settings" bl_context = "particle" @@ -1642,7 +1647,7 @@ class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel): row.prop(cpsys, "use_closetip", text="Close tip") -class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel): +class CYCLES_SCENE_PT_simplify(CyclesButtonsPanel, Panel): bl_label = "Simplify" bl_context = "scene" COMPAT_ENGINES = {'CYCLES'} @@ -1797,47 +1802,47 @@ def get_panels(): classes = ( CYCLES_MT_sampling_presets, CYCLES_MT_integrator_presets, - CyclesRender_PT_sampling, - CyclesRender_PT_geometry, - CyclesRender_PT_light_paths, - CyclesRender_PT_motion_blur, - CyclesRender_PT_film, - CyclesRender_PT_performance, - CyclesRender_PT_layer_options, - CyclesRender_PT_layer_passes, - CyclesRender_PT_views, - CyclesRender_PT_denoising, - Cycles_PT_post_processing, - CyclesCamera_PT_dof, - Cycles_PT_context_material, - CyclesObject_PT_motion_blur, - CyclesObject_PT_cycles_settings, + CYCLES_RENDER_PT_sampling, + CYCLES_RENDER_PT_geometry, + CYCLES_RENDER_PT_light_paths, + CYCLES_RENDER_PT_motion_blur, + CYCLES_RENDER_PT_film, + CYCLES_RENDER_PT_performance, + CYCLES_RENDER_PT_layer_options, + CYCLES_RENDER_PT_layer_passes, + CYCLES_RENDER_PT_views, + CYCLES_RENDER_PT_denoising, + CYCLES_PT_post_processing, + CYCLES_CAMERA_PT_dof, + CYCLES_PT_context_material, + CYCLES_OBJECT_PT_motion_blur, + CYCLES_OBJECT_PT_cycles_settings, CYCLES_OT_use_shading_nodes, - CyclesLamp_PT_preview, - CyclesLamp_PT_lamp, - CyclesLamp_PT_nodes, - CyclesLamp_PT_spot, - CyclesWorld_PT_preview, - CyclesWorld_PT_surface, - CyclesWorld_PT_volume, - CyclesWorld_PT_ambient_occlusion, - CyclesWorld_PT_mist, - CyclesWorld_PT_ray_visibility, - CyclesWorld_PT_settings, - CyclesMaterial_PT_preview, - CyclesMaterial_PT_surface, - CyclesMaterial_PT_volume, - CyclesMaterial_PT_displacement, - CyclesMaterial_PT_settings, - CyclesTexture_PT_context, - CyclesTexture_PT_node, - CyclesTexture_PT_mapping, - CyclesTexture_PT_colors, - CyclesParticle_PT_textures, - CyclesRender_PT_bake, - CyclesRender_PT_debug, - CyclesParticle_PT_CurveSettings, - CyclesScene_PT_simplify, + CYCLES_LAMP_PT_preview, + CYCLES_LAMP_PT_lamp, + CYCLES_LAMP_PT_nodes, + CYCLES_LAMP_PT_spot, + CYCLES_WORLD_PT_preview, + CYCLES_WORLD_PT_surface, + CYCLES_WORLD_PT_volume, + CYCLES_WORLD_PT_ambient_occlusion, + CYCLES_WORLD_PT_mist, + CYCLES_WORLD_PT_ray_visibility, + CYCLES_WORLD_PT_settings, + CYCLES_MATERIAL_PT_preview, + CYCLES_MATERIAL_PT_surface, + CYCLES_MATERIAL_PT_volume, + CYCLES_MATERIAL_PT_displacement, + CYCLES_MATERIAL_PT_settings, + CYCLES_TEXTURE_PT_context, + CYCLES_TEXTURE_PT_node, + CYCLES_TEXTURE_PT_mapping, + CYCLES_TEXTURE_PT_colors, + CYCLES_PARTICLE_PT_textures, + CYCLES_RENDER_PT_bake, + CYCLES_RENDER_PT_debug, + CYCLES_PARTICLE_PT_curve_settings, + CYCLES_SCENE_PT_simplify, ) diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py index b2a745500a1..efd794461d6 100644 --- a/intern/cycles/blender/addon/version_update.py +++ b/intern/cycles/blender/addon/version_update.py @@ -302,3 +302,16 @@ def do_versions(self): cscene = scene.cycles if not cscene.is_property_set("light_sampling_threshold"): cscene.light_sampling_threshold = 0.0 + + if bpy.data.version <= (2, 79, 0): + for scene in bpy.data.scenes: + cscene = scene.cycles + # Default changes + if not cscene.is_property_set("aa_samples"): + cscene.aa_samples = 4 + if not cscene.is_property_set("preview_aa_samples"): + cscene.preview_aa_samples = 4 + if not cscene.is_property_set("blur_glossy"): + cscene.blur_glossy = 0.0 + if not cscene.is_property_set("sample_clamp_indirect"): + cscene.sample_clamp_indirect = 0.0 diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index 40d6b25f2b7..b29711d30d3 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -544,7 +544,11 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render, if(tfm != cam->matrix) { VLOG(1) << "Camera " << b_ob.name() << " motion detected."; - if(motion_time == -1.0f) { + if(motion_time == 0.0f) { + /* When motion blur is not centered in frame, cam->matrix gets reset. */ + cam->matrix = tfm; + } + else if(motion_time == -1.0f) { cam->motion.pre = tfm; cam->use_motion = true; } @@ -573,7 +577,10 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render, float fov = 2.0f * atanf((0.5f * sensor_size) / bcam.lens / aspectratio); if(fov != cam->fov) { VLOG(1) << "Camera " << b_ob.name() << " FOV change detected."; - if(motion_time == -1.0f) { + if(motion_time == 0.0f) { + cam->fov = fov; + } + else if(motion_time == -1.0f) { cam->fov_pre = fov; cam->use_perspective_motion = true; } diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 3ebe2d8cf34..4091c44d379 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -50,8 +50,7 @@ enum { * Two triangles has vertex indices in the original Blender-side face. * If face is already a quad tri_b will not be initialized. */ -inline void face_split_tri_indices(const int num_verts, - const int face_flag, +inline void face_split_tri_indices(const int face_flag, int tri_a[3], int tri_b[3]) { @@ -59,36 +58,37 @@ inline void face_split_tri_indices(const int num_verts, tri_a[0] = 0; tri_a[1] = 1; tri_a[2] = 3; - if(num_verts == 4) { - tri_b[0] = 2; - tri_b[1] = 3; - tri_b[2] = 1; - } + + tri_b[0] = 2; + tri_b[1] = 3; + tri_b[2] = 1; } - else /*if(face_flag & FACE_FLAG_DIVIDE_13)*/ { + else { + /* Quad with FACE_FLAG_DIVIDE_13 or single triangle. */ tri_a[0] = 0; tri_a[1] = 1; tri_a[2] = 2; - if(num_verts == 4) { - tri_b[0] = 0; - tri_b[1] = 2; - tri_b[2] = 3; - } + + tri_b[0] = 0; + tri_b[1] = 2; + tri_b[2] = 3; } } /* Tangent Space */ struct MikkUserData { - MikkUserData(const BL::Mesh& mesh_, - BL::MeshTextureFaceLayer *layer_, - int num_faces_) - : mesh(mesh_), layer(layer_), num_faces(num_faces_) + MikkUserData(const BL::Mesh& b_mesh, + BL::MeshTextureFaceLayer *layer, + int num_faces) + : b_mesh(b_mesh), + layer(layer), + num_faces(num_faces) { tangent.resize(num_faces*4); } - BL::Mesh mesh; + BL::Mesh b_mesh; BL::MeshTextureFaceLayer *layer; int num_faces; vector<float4> tangent; @@ -103,7 +103,7 @@ static int mikk_get_num_faces(const SMikkTSpaceContext *context) static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const int face_num) { MikkUserData *userdata = (MikkUserData*)context->m_pUserData; - BL::MeshTessFace f = userdata->mesh.tessfaces[face_num]; + BL::MeshTessFace f = userdata->b_mesh.tessfaces[face_num]; int4 vi = get_int4(f.vertices_raw()); return (vi[3] == 0)? 3: 4; @@ -112,9 +112,9 @@ static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const i static void mikk_get_position(const SMikkTSpaceContext *context, float P[3], const int face_num, const int vert_num) { MikkUserData *userdata = (MikkUserData*)context->m_pUserData; - BL::MeshTessFace f = userdata->mesh.tessfaces[face_num]; + BL::MeshTessFace f = userdata->b_mesh.tessfaces[face_num]; int4 vi = get_int4(f.vertices_raw()); - BL::MeshVertex v = userdata->mesh.vertices[vi[vert_num]]; + BL::MeshVertex v = userdata->b_mesh.vertices[vi[vert_num]]; float3 vP = get_float3(v.co()); P[0] = vP.x; @@ -148,9 +148,9 @@ static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, float uv[1] = tfuv.y; } else { - int vert_idx = userdata->mesh.tessfaces[face_num].vertices()[vert_num]; + int vert_idx = userdata->b_mesh.tessfaces[face_num].vertices()[vert_num]; float3 orco = - get_float3(userdata->mesh.vertices[vert_idx].undeformed_co()); + get_float3(userdata->b_mesh.vertices[vert_idx].undeformed_co()); float2 tmp = map_to_sphere(make_float3(orco[0], orco[1], orco[2])); uv[0] = tmp.x; uv[1] = tmp.y; @@ -160,12 +160,12 @@ static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, float static void mikk_get_normal(const SMikkTSpaceContext *context, float N[3], const int face_num, const int vert_num) { MikkUserData *userdata = (MikkUserData*)context->m_pUserData; - BL::MeshTessFace f = userdata->mesh.tessfaces[face_num]; + BL::MeshTessFace f = userdata->b_mesh.tessfaces[face_num]; float3 vN; if(f.use_smooth()) { int4 vi = get_int4(f.vertices_raw()); - BL::MeshVertex v = userdata->mesh.vertices[vi[vert_num]]; + BL::MeshVertex v = userdata->b_mesh.vertices[vi[vert_num]]; vN = get_float3(v.normal()); } else { @@ -250,7 +250,7 @@ static void mikk_compute_tangents(BL::Mesh& b_mesh, for(int i = 0; i < nverts.size(); i++) { int tri_a[3], tri_b[3]; - face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b); + face_split_tri_indices(face_flags[i], tri_a, tri_b); tangent[0] = float4_to_float3(userdata.tangent[i*4 + tri_a[0]]); tangent[1] = float4_to_float3(userdata.tangent[i*4 + tri_a[1]]); @@ -376,7 +376,7 @@ static void attr_create_vertex_color(Scene *scene, for(l->data.begin(c); c != l->data.end(); ++c, ++i) { int tri_a[3], tri_b[3]; - face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b); + face_split_tri_indices(face_flags[i], tri_a, tri_b); uchar4 colors[4]; colors[0] = color_float_to_byte(color_srgb_to_scene_linear_v3(get_float3(c->color1()))); @@ -469,7 +469,7 @@ static void attr_create_uv_map(Scene *scene, for(l->data.begin(t); t != l->data.end(); ++t, ++i) { int tri_a[3], tri_b[3]; - face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b); + face_split_tri_indices(face_flags[i], tri_a, tri_b); float3 uvs[4]; uvs[0] = get_float3(t->uv1()); @@ -719,6 +719,11 @@ static void create_mesh(Scene *scene, int numngons = 0; bool use_loop_normals = b_mesh.use_auto_smooth() && (mesh->subdivision_type != Mesh::SUBDIVISION_CATMULL_CLARK); + /* If no faces, create empty mesh. */ + if(numfaces == 0) { + return; + } + BL::Mesh::vertices_iterator v; BL::Mesh::tessfaces_iterator f; BL::Mesh::polygons_iterator p; @@ -1079,7 +1084,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, } /* free derived mesh */ - b_data.meshes.remove(b_mesh, false); + b_data.meshes.remove(b_mesh, false, true, false); } } mesh->geometry_flags = requested_geometry_flags; @@ -1299,7 +1304,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, sync_curves(mesh, b_mesh, b_ob, true, time_index); /* free derived mesh */ - b_data.meshes.remove(b_mesh, false); + b_data.meshes.remove(b_mesh, false, true, false); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index a930c439370..63138c060fb 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -63,8 +63,25 @@ bool BlenderSync::object_is_mesh(BL::Object& b_ob) { BL::ID b_ob_data = b_ob.data(); - return (b_ob_data && (b_ob_data.is_a(&RNA_Mesh) || - b_ob_data.is_a(&RNA_Curve) || b_ob_data.is_a(&RNA_MetaBall))); + if(!b_ob_data) { + return false; + } + + if(b_ob.type() == BL::Object::type_CURVE) { + /* Skip exporting curves without faces, overhead can be + * significant if there are many for path animation. */ + BL::Curve b_curve(b_ob.data()); + + return (b_curve.bevel_object() || + b_curve.extrude() != 0.0f || + b_curve.bevel_depth() != 0.0f || + b_ob.modifiers.length()); + } + else { + return (b_ob_data.is_a(&RNA_Mesh) || + b_ob_data.is_a(&RNA_Curve) || + b_ob_data.is_a(&RNA_MetaBall)); + } } bool BlenderSync::object_is_light(BL::Object& b_ob) @@ -268,6 +285,29 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, return NULL; } + /* Visibility flags for both parent and child. */ + bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0; + uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY; + + if(b_parent.ptr.data != b_ob.ptr.data) { + visibility &= object_ray_visibility(b_parent); + } + + /* Make holdout objects on excluded layer invisible for non-camera rays. */ + if(use_holdout && (layer_flag & render_layer.exclude_layer)) { + visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA); + } + + /* Hide objects not on render layer from camera rays. */ + if(!(layer_flag & render_layer.layer)) { + visibility &= ~PATH_RAY_CAMERA; + } + + /* Don't export completely invisible objects. */ + if(visibility == 0) { + return NULL; + } + /* key to lookup object */ ObjectKey key(b_parent, persistent_id, b_ob); Object *object; @@ -308,8 +348,6 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, if(object_map.sync(&object, b_ob, b_parent, key)) object_updated = true; - bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0; - /* mesh sync */ object->mesh = sync_mesh(b_ob, object_updated, hide_tris); @@ -322,22 +360,6 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, object_updated = true; } - /* visibility flags for both parent and child */ - uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY; - if(b_parent.ptr.data != b_ob.ptr.data) { - visibility &= object_ray_visibility(b_parent); - } - - /* make holdout objects on excluded layer invisible for non-camera rays */ - if(use_holdout && (layer_flag & render_layer.exclude_layer)) { - visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA); - } - - /* hide objects not on render layer from camera rays */ - if(!(layer_flag & render_layer.layer)) { - visibility &= ~PATH_RAY_CAMERA; - } - if(visibility != object->visibility) { object->visibility = visibility; object_updated = true; diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 54973fd1b7f..e268c9a0d35 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -60,6 +60,8 @@ bool debug_flags_sync_from_scene(BL::Scene b_scene) /* Backup some settings for comparison. */ DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type; DebugFlags::OpenCL::KernelType opencl_kernel_type = flags.opencl.kernel_type; + /* Synchronize shared flags. */ + flags.viewport_static_bvh = get_enum(cscene, "debug_bvh_type"); /* Synchronize CPU flags. */ flags.cpu.avx2 = get_boolean(cscene, "debug_use_cpu_avx2"); flags.cpu.avx = get_boolean(cscene, "debug_use_cpu_avx"); diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 2b5dd5eadea..12de3da063f 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -129,9 +129,9 @@ void BlenderSession::create_session() scene = new Scene(scene_params, session_params.device); /* setup callbacks for builtin image support */ - scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7); - scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4); - scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4); + scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7, _8); + scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4, _5); + scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4, _5); /* create session */ session = new Session(session_params); @@ -1013,7 +1013,8 @@ void BlenderSession::builtin_image_info(const string &builtin_name, int &width, int &height, int &depth, - int &channels) + int &channels, + bool& free_cache) { /* empty image */ is_float = false; @@ -1021,6 +1022,7 @@ void BlenderSession::builtin_image_info(const string &builtin_name, height = 1; depth = 0; channels = 0; + free_cache = false; if(!builtin_data) return; @@ -1034,6 +1036,7 @@ void BlenderSession::builtin_image_info(const string &builtin_name, /* image data */ BL::Image b_image(b_id); + free_cache = !b_image.has_data(); is_float = b_image.is_float(); width = b_image.size()[0]; height = b_image.size()[1]; @@ -1094,7 +1097,8 @@ void BlenderSession::builtin_image_info(const string &builtin_name, bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels, - const size_t pixels_size) + const size_t pixels_size, + const bool free_cache) { if(!builtin_data) { return false; @@ -1115,7 +1119,6 @@ bool BlenderSession::builtin_image_pixels(const string &builtin_name, if(image_pixels && num_pixels * channels == pixels_size) { memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char)); - MEM_freeN(image_pixels); } else { if(channels == 1) { @@ -1134,6 +1137,16 @@ bool BlenderSession::builtin_image_pixels(const string &builtin_name, } } } + + if(image_pixels) { + MEM_freeN(image_pixels); + } + + /* Free image buffers to save memory during render. */ + if(free_cache) { + b_image.buffers_free(); + } + /* Premultiply, byte images are always straight for Blender. */ unsigned char *cp = pixels; for(size_t i = 0; i < num_pixels; i++, cp += channels) { @@ -1147,7 +1160,8 @@ bool BlenderSession::builtin_image_pixels(const string &builtin_name, bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels, - const size_t pixels_size) + const size_t pixels_size, + const bool free_cache) { if(!builtin_data) { return false; @@ -1172,7 +1186,6 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, if(image_pixels && num_pixels * channels == pixels_size) { memcpy(pixels, image_pixels, pixels_size * sizeof(float)); - MEM_freeN(image_pixels); } else { if(channels == 1) { @@ -1192,6 +1205,15 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, } } + if(image_pixels) { + MEM_freeN(image_pixels); + } + + /* Free image buffers to save memory during render. */ + if(free_cache) { + b_image.buffers_free(); + } + return true; } else if(b_id.is_a(&RNA_Object)) { diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index 536808c5b18..cbd2303d282 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -156,15 +156,18 @@ protected: int &width, int &height, int &depth, - int &channels); + int &channels, + bool &free_cache); bool builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels, - const size_t pixels_size); + const size_t pixels_size, + const bool free_cache); bool builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels, - const size_t pixels_size); + const size_t pixels_size, + const bool free_cache); /* Update tile manager to reflect resumable render settings. */ void update_resumable_tile_manager(int num_samples); diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 3a00384458a..42e3721883f 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -234,7 +234,6 @@ void BlenderSync::sync_integrator() Integrator *integrator = scene->integrator; Integrator previntegrator = *integrator; - integrator->min_bounce = get_int(cscene, "min_bounces"); integrator->max_bounce = get_int(cscene, "max_bounces"); integrator->max_diffuse_bounce = get_int(cscene, "diffuse_bounces"); @@ -243,8 +242,6 @@ void BlenderSync::sync_integrator() integrator->max_volume_bounce = get_int(cscene, "volume_bounces"); integrator->transparent_max_bounce = get_int(cscene, "transparent_max_bounces"); - integrator->transparent_min_bounce = get_int(cscene, "transparent_min_bounces"); - integrator->transparent_shadows = get_boolean(cscene, "use_transparent_shadows"); integrator->volume_max_steps = get_int(cscene, "volume_max_steps"); integrator->volume_step_size = get_float(cscene, "volume_step_size"); @@ -629,14 +626,10 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene, else if(shadingsystem == 1) params.shadingsystem = SHADINGSYSTEM_OSL; - if(background) + if(background || DebugFlags().viewport_static_bvh) params.bvh_type = SceneParams::BVH_STATIC; else - params.bvh_type = (SceneParams::BVHType)get_enum( - cscene, - "debug_bvh_type", - SceneParams::BVH_NUM_TYPES, - SceneParams::BVH_STATIC); + params.bvh_type = SceneParams::BVH_DYNAMIC; params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits"); params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh"); @@ -810,6 +803,7 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, } params.start_resolution = get_int(cscene, "preview_start_resolution"); + params.pixel_size = b_engine.get_preview_pixel_size(b_scene); /* other parameters */ if(b_scene.render().threads_mode() == BL::RenderSettings::threads_mode_FIXED) @@ -830,6 +824,7 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, params.progressive = false; params.start_resolution = INT_MAX; + params.pixel_size = 1; } else params.progressive = true; diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index ebbf325f95b..363e19f7a20 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -51,8 +51,8 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, bool calc_undeformed, Mesh::SubdivisionType subdivision_type) { - bool subsurf_mod_show_render; - bool subsurf_mod_show_viewport; + bool subsurf_mod_show_render = false; + bool subsurf_mod_show_viewport = false; if(subdivision_type != Mesh::SUBDIVISION_NONE) { BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index 33143e2d8aa..0ad3c8a7429 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -153,7 +153,6 @@ void BVH::pack_primitives() if(pack.prim_index[i] != -1) { int tob = pack.prim_object[i]; Object *ob = objects[tob]; - if((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { pack_triangle(i, (float4*)&pack.prim_tri_verts[3 * prim_triangle_index]); pack.prim_tri_index[i] = 3 * prim_triangle_index; @@ -162,11 +161,10 @@ void BVH::pack_primitives() else { pack.prim_tri_index[i] = -1; } - - pack.prim_visibility[i] = ob->visibility; - - if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE) + pack.prim_visibility[i] = ob->visibility_for_tracing(); + if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE) { pack.prim_visibility[i] |= PATH_RAY_CURVE; + } } else { pack.prim_tri_index[i] = -1; diff --git a/intern/cycles/bvh/bvh2.cpp b/intern/cycles/bvh/bvh2.cpp index 340ba7dcf53..9aa8e71dfd0 100644 --- a/intern/cycles/bvh/bvh2.cpp +++ b/intern/cycles/bvh/bvh2.cpp @@ -312,10 +312,8 @@ void BVH2::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) } } } - - visibility |= ob->visibility; + visibility |= ob->visibility_for_tracing(); } - /* TODO(sergey): De-duplicate with pack_leaf(). */ float4 leaf_data[BVH_NODE_LEAF_SIZE]; leaf_data[0].x = __int_as_float(c0); diff --git a/intern/cycles/bvh/bvh4.cpp b/intern/cycles/bvh/bvh4.cpp index 5034ab811d5..777de20423b 100644 --- a/intern/cycles/bvh/bvh4.cpp +++ b/intern/cycles/bvh/bvh4.cpp @@ -242,21 +242,21 @@ void BVH4::pack_unaligned_node(int idx, * so kernel might safely assume there are always 4 child nodes. */ - data[1][i] = 1.0f; - data[2][i] = 0.0f; - data[3][i] = 0.0f; + data[1][i] = NAN; + data[2][i] = NAN; + data[3][i] = NAN; - data[4][i] = 0.0f; - data[5][i] = 0.0f; - data[6][i] = 0.0f; + data[4][i] = NAN; + data[5][i] = NAN; + data[6][i] = NAN; - data[7][i] = 0.0f; - data[8][i] = 0.0f; - data[9][i] = 0.0f; + data[7][i] = NAN; + data[8][i] = NAN; + data[9][i] = NAN; - data[10][i] = -FLT_MAX; - data[11][i] = -FLT_MAX; - data[12][i] = -FLT_MAX; + data[10][i] = NAN; + data[11][i] = NAN; + data[12][i] = NAN; data[13][i] = __int_as_float(0); } @@ -438,10 +438,8 @@ void BVH4::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) } } } - - visibility |= ob->visibility; + visibility |= ob->visibility_for_tracing(); } - /* TODO(sergey): This is actually a copy of pack_leaf(), * but this chunk of code only knows actual data and has * no idea about BVHNode. diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 1880964355c..649ce52da05 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -529,7 +529,9 @@ BVHNode* BVHBuild::run() << " Allocation slop factor: " << ((prim_type.capacity() != 0) ? (float)prim_type.size() / prim_type.capacity() - : 1.0f) << "\n"; + : 1.0f) << "\n" + << " Maximum depth: " + << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_DEPTH)) << "\n"; } } @@ -671,7 +673,7 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level) return create_leaf_node(range, references); } } - /* Check whether unaligned split is better than the regulat one. */ + /* Check whether unaligned split is better than the regular one. */ if(unalignedSplitSAH < splitSAH) { do_unalinged_split = true; } @@ -865,7 +867,7 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, prim_time[start] = make_float2(ref->time_from(), ref->time_to()); } - uint visibility = objects[ref->prim_object()]->visibility; + const uint visibility = objects[ref->prim_object()]->visibility_for_tracing(); BVHNode *leaf_node = new LeafNode(ref->bounds(), visibility, start, start+1); leaf_node->time_from = ref->time_from(); leaf_node->time_to = ref->time_to(); @@ -939,7 +941,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, ref.time_to())); bounds[type_index].grow(ref.bounds()); - visibility[type_index] |= objects[ref.prim_object()]->visibility; + visibility[type_index] |= objects[ref.prim_object()]->visibility_for_tracing(); if(ref.prim_type() & PRIMITIVE_ALL_CURVE) { visibility[type_index] |= PATH_RAY_CURVE; } @@ -1040,7 +1042,6 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, */ start_index = spatial_free_index; spatial_free_index += range.size(); - /* Extend an array when needed. */ const size_t range_end = start_index + range.size(); if(prim_type.size() < range_end) { @@ -1066,8 +1067,6 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, prim_time.resize(range_end); } } - spatial_spin_lock.unlock(); - /* Perform actual data copy. */ if(new_leaf_data_size > 0) { memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size); @@ -1077,6 +1076,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2)*num_new_leaf_data); } } + spatial_spin_lock.unlock(); } else { /* For the regular BVH builder we simply copy new data starting at the diff --git a/intern/cycles/bvh/bvh_node.cpp b/intern/cycles/bvh/bvh_node.cpp index 4237c62ab5b..ab6df4d265d 100644 --- a/intern/cycles/bvh/bvh_node.cpp +++ b/intern/cycles/bvh/bvh_node.cpp @@ -132,6 +132,17 @@ int BVHNode::getSubtreeSize(BVH_STAT stat) const case BVH_STAT_UNALIGNED_LEAF_COUNT: cnt = (is_leaf() && is_unaligned) ? 1 : 0; break; + case BVH_STAT_DEPTH: + if(is_leaf()) { + cnt = 1; + } + else { + for(int i = 0; i < num_children(); i++) { + cnt = max(cnt, get_child(i)->getSubtreeSize(stat)); + } + cnt += 1; + } + return cnt; default: assert(0); /* unknown mode */ } diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h index 1c875f5a524..94cf5ab730c 100644 --- a/intern/cycles/bvh/bvh_node.h +++ b/intern/cycles/bvh/bvh_node.h @@ -38,6 +38,7 @@ enum BVH_STAT { BVH_STAT_UNALIGNED_INNER_QNODE_COUNT, BVH_STAT_ALIGNED_LEAF_COUNT, BVH_STAT_UNALIGNED_LEAF_COUNT, + BVH_STAT_DEPTH, }; class BVHParams; diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt index 74ec57ddf74..3c632160fbd 100644 --- a/intern/cycles/device/CMakeLists.txt +++ b/intern/cycles/device/CMakeLists.txt @@ -34,11 +34,13 @@ set(SRC set(SRC_OPENCL opencl/opencl.h + opencl/memory_manager.h opencl/opencl_base.cpp opencl/opencl_mega.cpp opencl/opencl_split.cpp opencl/opencl_util.cpp + opencl/memory_manager.cpp ) if(WITH_CYCLES_NETWORK) diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index a54bb77f9f3..f64436aec7b 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -379,11 +379,9 @@ DeviceInfo Device::get_multi_device(vector<DeviceInfo> subdevices) info.num = 0; info.has_bindless_textures = true; - info.pack_images = false; foreach(DeviceInfo &device, subdevices) { assert(device.type == info.multi_devices[0].type); - info.pack_images |= device.pack_images; info.has_bindless_textures &= device.has_bindless_textures; } diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index b3b693c630c..26d6d380a10 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -53,7 +53,6 @@ public: int num; bool display_device; bool advanced_shading; - bool pack_images; bool has_bindless_textures; /* flag for GPU and Multi device */ bool use_split_kernel; /* Denotes if the device is going to run cycles using split-kernel */ vector<DeviceInfo> multi_devices; @@ -65,7 +64,6 @@ public: num = 0; display_device = false; advanced_shading = true; - pack_images = false; has_bindless_textures = false; use_split_kernel = false; } diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index 18112437b45..6a1106328fb 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -48,6 +48,7 @@ #include "util/util_logging.h" #include "util/util_map.h" #include "util/util_opengl.h" +#include "util/util_optimization.h" #include "util/util_progress.h" #include "util/util_system.h" #include "util/util_thread.h" @@ -119,7 +120,7 @@ public: } #endif - if(strstr(architecture_name, logged_architecture) != 0) { + if(strcmp(architecture_name, logged_architecture) != 0) { VLOG(1) << "Will be using " << architecture_name << " kernels."; logged_architecture = architecture_name; } @@ -976,7 +977,6 @@ void device_cpu_info(vector<DeviceInfo>& devices) info.id = "CPU"; info.num = 0; info.advanced_shading = true; - info.pack_images = false; devices.insert(devices.begin(), info); } diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 3a29538aa13..29b5bd70789 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -111,6 +111,16 @@ public: virtual int2 split_kernel_global_size(device_memory& kg, device_memory& data, DeviceTask *task); }; +/* Utility to push/pop CUDA context. */ +class CUDAContextScope { +public: + CUDAContextScope(CUDADevice *device); + ~CUDAContextScope(); + +private: + CUDADevice *device; +}; + class CUDADevice : public Device { public: @@ -206,16 +216,6 @@ public: cuda_error_documentation(); } - void cuda_push_context() - { - cuda_assert(cuCtxSetCurrent(cuContext)); - } - - void cuda_pop_context() - { - cuda_assert(cuCtxSetCurrent(NULL)); - } - CUDADevice(DeviceInfo& info, Stats &stats, bool background_) : Device(info, stats, background_) { @@ -263,7 +263,8 @@ public: cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevId); cuDevArchitecture = major*100 + minor*10; - cuda_pop_context(); + /* Pop context set by cuCtxCreate. */ + cuCtxPopCurrent(NULL); } ~CUDADevice() @@ -519,7 +520,7 @@ public: return false; /* open module */ - cuda_push_context(); + CUDAContextScope scope(this); string cubin_data; CUresult result; @@ -540,8 +541,6 @@ public: if(cuda_error_(result, "cuModuleLoad")) cuda_error_message(string_printf("Failed loading CUDA kernel %s.", filter_cubin.c_str())); - cuda_pop_context(); - return (result == CUDA_SUCCESS); } @@ -556,36 +555,36 @@ public: void mem_alloc(const char *name, device_memory& mem, MemoryType /*type*/) { + CUDAContextScope scope(this); + if(name) { VLOG(1) << "Buffer allocate: " << name << ", " << string_human_readable_number(mem.memory_size()) << " bytes. (" << string_human_readable_size(mem.memory_size()) << ")"; } - cuda_push_context(); CUdeviceptr device_pointer; size_t size = mem.memory_size(); cuda_assert(cuMemAlloc(&device_pointer, size)); mem.device_pointer = (device_ptr)device_pointer; mem.device_size = size; stats.mem_alloc(size); - cuda_pop_context(); } void mem_copy_to(device_memory& mem) { - cuda_push_context(); + CUDAContextScope scope(this); + if(mem.device_pointer) cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size())); - cuda_pop_context(); } void mem_copy_from(device_memory& mem, int y, int w, int h, int elem) { + CUDAContextScope scope(this); size_t offset = elem*y*w; size_t size = elem*w*h; - cuda_push_context(); if(mem.device_pointer) { cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset, (CUdeviceptr)(mem.device_pointer + offset), size)); @@ -593,7 +592,6 @@ public: else { memset((char*)mem.data_pointer + offset, 0, size); } - cuda_pop_context(); } void mem_zero(device_memory& mem) @@ -602,18 +600,17 @@ public: memset((void*)mem.data_pointer, 0, mem.memory_size()); } - cuda_push_context(); - if(mem.device_pointer) + if(mem.device_pointer) { + CUDAContextScope scope(this); cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size())); - cuda_pop_context(); + } } void mem_free(device_memory& mem) { if(mem.device_pointer) { - cuda_push_context(); + CUDAContextScope scope(this); cuda_assert(cuMemFree(cuda_device_ptr(mem.device_pointer))); - cuda_pop_context(); mem.device_pointer = 0; @@ -629,14 +626,13 @@ public: void const_copy_to(const char *name, void *host, size_t size) { + CUDAContextScope scope(this); CUdeviceptr mem; size_t bytes; - cuda_push_context(); cuda_assert(cuModuleGetGlobal(&mem, &bytes, cuModule, name)); //assert(bytes == size); cuda_assert(cuMemcpyHtoD(mem, host, size)); - cuda_pop_context(); } void tex_alloc(const char *name, @@ -644,6 +640,8 @@ public: InterpolationType interpolation, ExtensionType extension) { + CUDAContextScope scope(this); + VLOG(1) << "Texture allocate: " << name << ", " << string_human_readable_number(mem.memory_size()) << " bytes. (" << string_human_readable_size(mem.memory_size()) << ")"; @@ -706,9 +704,7 @@ public: tokens[3].c_str()); } - cuda_push_context(); cuda_assert(cuModuleGetTexRef(&texref, cuModule, bind_name.c_str())); - cuda_pop_context(); if(!texref) { return; @@ -721,8 +717,6 @@ public: mem_alloc(NULL, mem, MEM_READ_ONLY); mem_copy_to(mem); - cuda_push_context(); - CUdeviceptr cumem; size_t cubytes; @@ -738,28 +732,20 @@ public: uint32_t ptr = (uint32_t)mem.device_pointer; cuda_assert(cuMemcpyHtoD(cumem, (void*)&ptr, cubytes)); } - - cuda_pop_context(); } else { mem_alloc(NULL, mem, MEM_READ_ONLY); mem_copy_to(mem); - cuda_push_context(); - cuda_assert(cuTexRefSetAddress(NULL, texref, cuda_device_ptr(mem.device_pointer), size)); cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_POINT)); cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_READ_AS_INTEGER)); - - cuda_pop_context(); } } /* Texture Storage */ else { CUarray handle = NULL; - cuda_push_context(); - if(mem.data_depth > 1) { CUDA_ARRAY3D_DESCRIPTOR desc; @@ -784,7 +770,6 @@ public: } if(!handle) { - cuda_pop_context(); return; } @@ -877,14 +862,10 @@ public: cuda_assert(cuTexRefSetFilterMode(texref, filter_mode)); cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_NORMALIZED_COORDINATES)); } - - cuda_pop_context(); } /* Fermi, Data and Image Textures */ if(!has_bindless_textures) { - cuda_push_context(); - cuda_assert(cuTexRefSetAddressMode(texref, 0, address_mode)); cuda_assert(cuTexRefSetAddressMode(texref, 1, address_mode)); if(mem.data_depth > 1) { @@ -892,8 +873,6 @@ public: } cuda_assert(cuTexRefSetFormat(texref, format, mem.data_elements)); - - cuda_pop_context(); } /* Fermi and Kepler */ @@ -904,9 +883,8 @@ public: { if(mem.device_pointer) { if(tex_interp_map[mem.device_pointer]) { - cuda_push_context(); + CUDAContextScope scope(this); cuArrayDestroy((CUarray)mem.device_pointer); - cuda_pop_context(); /* Free CUtexObject (Bindless Textures) */ if(info.has_bindless_textures && tex_bindless_map[mem.device_pointer]) { @@ -960,7 +938,7 @@ public: if(have_error()) return false; - cuda_push_context(); + CUDAContextScope scope(this); int4 rect = task->rect; int w = align_up(rect.z-rect.x, 4); @@ -1017,7 +995,6 @@ public: CUDA_LAUNCH_KERNEL(cuNLMNormalize, normalize_args); cuda_assert(cuCtxSynchronize()); - cuda_pop_context(); return !have_error(); } @@ -1026,7 +1003,7 @@ public: if(have_error()) return false; - cuda_push_context(); + CUDAContextScope scope(this); CUfunction cuFilterConstructTransform; cuda_assert(cuModuleGetFunction(&cuFilterConstructTransform, cuFilterModule, "kernel_cuda_filter_construct_transform")); @@ -1046,7 +1023,6 @@ public: CUDA_LAUNCH_KERNEL(cuFilterConstructTransform, args); cuda_assert(cuCtxSynchronize()); - cuda_pop_context(); return !have_error(); } @@ -1058,11 +1034,11 @@ public: if(have_error()) return false; + CUDAContextScope scope(this); + mem_zero(task->storage.XtWX); mem_zero(task->storage.XtWY); - cuda_push_context(); - CUfunction cuNLMCalcDifference, cuNLMBlur, cuNLMCalcWeight, cuNLMConstructGramian, cuFinalize; cuda_assert(cuModuleGetFunction(&cuNLMCalcDifference, cuFilterModule, "kernel_cuda_filter_nlm_calc_difference")); cuda_assert(cuModuleGetFunction(&cuNLMBlur, cuFilterModule, "kernel_cuda_filter_nlm_blur")); @@ -1150,7 +1126,6 @@ public: CUDA_LAUNCH_KERNEL(cuFinalize, finalize_args); cuda_assert(cuCtxSynchronize()); - cuda_pop_context(); return !have_error(); } @@ -1161,7 +1136,7 @@ public: if(have_error()) return false; - cuda_push_context(); + CUDAContextScope scope(this); CUfunction cuFilterCombineHalves; cuda_assert(cuModuleGetFunction(&cuFilterCombineHalves, cuFilterModule, "kernel_cuda_filter_combine_halves")); @@ -1179,7 +1154,6 @@ public: CUDA_LAUNCH_KERNEL(cuFilterCombineHalves, args); cuda_assert(cuCtxSynchronize()); - cuda_pop_context(); return !have_error(); } @@ -1190,7 +1164,7 @@ public: if(have_error()) return false; - cuda_push_context(); + CUDAContextScope scope(this); CUfunction cuFilterDivideShadow; cuda_assert(cuModuleGetFunction(&cuFilterDivideShadow, cuFilterModule, "kernel_cuda_filter_divide_shadow")); @@ -1214,7 +1188,6 @@ public: CUDA_LAUNCH_KERNEL(cuFilterDivideShadow, args); cuda_assert(cuCtxSynchronize()); - cuda_pop_context(); return !have_error(); } @@ -1227,7 +1200,7 @@ public: if(have_error()) return false; - cuda_push_context(); + CUDAContextScope scope(this); CUfunction cuFilterGetFeature; cuda_assert(cuModuleGetFunction(&cuFilterGetFeature, cuFilterModule, "kernel_cuda_filter_get_feature")); @@ -1250,7 +1223,6 @@ public: CUDA_LAUNCH_KERNEL(cuFilterGetFeature, args); cuda_assert(cuCtxSynchronize()); - cuda_pop_context(); return !have_error(); } @@ -1263,7 +1235,7 @@ public: if(have_error()) return false; - cuda_push_context(); + CUDAContextScope scope(this); CUfunction cuFilterDetectOutliers; cuda_assert(cuModuleGetFunction(&cuFilterDetectOutliers, cuFilterModule, "kernel_cuda_filter_detect_outliers")); @@ -1282,7 +1254,6 @@ public: CUDA_LAUNCH_KERNEL(cuFilterDetectOutliers, args); cuda_assert(cuCtxSynchronize()); - cuda_pop_context(); return !have_error(); } @@ -1319,7 +1290,7 @@ public: if(have_error()) return; - cuda_push_context(); + CUDAContextScope scope(this); CUfunction cuPathTrace; CUdeviceptr d_buffer = cuda_device_ptr(rtile.buffer); @@ -1333,8 +1304,9 @@ public: cuda_assert(cuModuleGetFunction(&cuPathTrace, cuModule, "kernel_cuda_path_trace")); } - if(have_error()) + if(have_error()) { return; + } /* pass in parameters */ void *args[] = {&d_buffer, @@ -1370,8 +1342,6 @@ public: 0, 0, args, 0)); cuda_assert(cuCtxSynchronize()); - - cuda_pop_context(); } void film_convert(DeviceTask& task, device_ptr buffer, device_ptr rgba_byte, device_ptr rgba_half) @@ -1379,7 +1349,7 @@ public: if(have_error()) return; - cuda_push_context(); + CUDAContextScope scope(this); CUfunction cuFilmConvert; CUdeviceptr d_rgba = map_pixels((rgba_byte)? rgba_byte: rgba_half); @@ -1424,8 +1394,6 @@ public: 0, 0, args, 0)); unmap_pixels((rgba_byte)? rgba_byte: rgba_half); - - cuda_pop_context(); } void shader(DeviceTask& task) @@ -1433,7 +1401,7 @@ public: if(have_error()) return; - cuda_push_context(); + CUDAContextScope scope(this); CUfunction cuShader; CUdeviceptr d_input = cuda_device_ptr(task.shader_input); @@ -1498,8 +1466,6 @@ public: task.update_progress(NULL); } - - cuda_pop_context(); } CUdeviceptr map_pixels(device_ptr mem) @@ -1535,7 +1501,7 @@ public: pmem.w = mem.data_width; pmem.h = mem.data_height; - cuda_push_context(); + CUDAContextScope scope(this); glGenBuffers(1, &pmem.cuPBO); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO); @@ -1559,8 +1525,6 @@ public: CUresult result = cuGraphicsGLRegisterBuffer(&pmem.cuPBOresource, pmem.cuPBO, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE); if(result == CUDA_SUCCESS) { - cuda_pop_context(); - mem.device_pointer = pmem.cuTexId; pixel_mem_map[mem.device_pointer] = pmem; @@ -1574,8 +1538,6 @@ public: glDeleteBuffers(1, &pmem.cuPBO); glDeleteTextures(1, &pmem.cuTexId); - cuda_pop_context(); - background = true; } } @@ -1588,7 +1550,7 @@ public: if(!background) { PixelMem pmem = pixel_mem_map[mem.device_pointer]; - cuda_push_context(); + CUDAContextScope scope(this); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO); uchar *pixels = (uchar*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_ONLY); @@ -1597,8 +1559,6 @@ public: glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - cuda_pop_context(); - return; } @@ -1611,14 +1571,12 @@ public: if(!background) { PixelMem pmem = pixel_mem_map[mem.device_pointer]; - cuda_push_context(); + CUDAContextScope scope(this); cuda_assert(cuGraphicsUnregisterResource(pmem.cuPBOresource)); glDeleteBuffers(1, &pmem.cuPBO); glDeleteTextures(1, &pmem.cuTexId); - cuda_pop_context(); - pixel_mem_map.erase(pixel_mem_map.find(mem.device_pointer)); mem.device_pointer = 0; @@ -1639,7 +1597,7 @@ public: PixelMem pmem = pixel_mem_map[mem.device_pointer]; float *vpointer; - cuda_push_context(); + CUDAContextScope scope(this); /* for multi devices, this assumes the inefficient method that we allocate * all pixels on the device even though we only render to a subset */ @@ -1728,8 +1686,6 @@ public: glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); - cuda_pop_context(); - return; } @@ -1738,6 +1694,8 @@ public: void thread_run(DeviceTask *task) { + CUDAContextScope scope(this); + if(task->type == DeviceTask::RENDER) { RenderTile tile; @@ -1805,9 +1763,7 @@ public: shader(*task); - cuda_push_context(); cuda_assert(cuCtxSynchronize()); - cuda_pop_context(); } } @@ -1828,12 +1784,11 @@ public: void task_add(DeviceTask& task) { if(task.type == DeviceTask::FILM_CONVERT) { + CUDAContextScope scope(this); + /* must be done in main thread due to opengl access */ film_convert(task, task.buffer, task.rgba_byte, task.rgba_half); - - cuda_push_context(); cuda_assert(cuCtxSynchronize()); - cuda_pop_context(); } else { task_pool.push(new CUDADeviceTask(this, task)); @@ -1852,6 +1807,7 @@ public: friend class CUDASplitKernelFunction; friend class CUDASplitKernel; + friend class CUDAContextScope; }; /* redefine the cuda_assert macro so it can be used outside of the CUDADevice class @@ -1872,6 +1828,20 @@ public: } \ } (void)0 + +/* CUDA context scope. */ + +CUDAContextScope::CUDAContextScope(CUDADevice *device) +: device(device) +{ + cuda_assert(cuCtxPushCurrent(device->cuContext)); +} + +CUDAContextScope::~CUDAContextScope() +{ + cuda_assert(cuCtxPopCurrent(NULL)); +} + /* split kernel */ class CUDASplitKernelFunction : public SplitKernelFunction{ @@ -1889,30 +1859,24 @@ public: /* enqueue the kernel, returns false if there is an error */ bool enqueue(const KernelDimensions &dim, void *args[]) { - device->cuda_push_context(); - if(device->have_error()) return false; + CUDAContextScope scope(device); + /* we ignore dim.local_size for now, as this is faster */ int threads_per_block; cuda_assert(cuFuncGetAttribute(&threads_per_block, CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, func)); - int xthreads = (int)sqrt(threads_per_block); - int ythreads = (int)sqrt(threads_per_block); - - int xblocks = (dim.global_size[0] + xthreads - 1)/xthreads; - int yblocks = (dim.global_size[1] + ythreads - 1)/ythreads; + int xblocks = (dim.global_size[0]*dim.global_size[1] + threads_per_block - 1)/threads_per_block; cuda_assert(cuFuncSetCacheConfig(func, CU_FUNC_CACHE_PREFER_L1)); cuda_assert(cuLaunchKernel(func, - xblocks , yblocks, 1, /* blocks */ - xthreads, ythreads, 1, /* threads */ + xblocks, 1, 1, /* blocks */ + threads_per_block, 1, 1, /* threads */ 0, 0, args, 0)); - device->cuda_pop_context(); - return !device->have_error(); } }; @@ -1923,12 +1887,12 @@ CUDASplitKernel::CUDASplitKernel(CUDADevice *device) : DeviceSplitKernel(device) uint64_t CUDASplitKernel::state_buffer_size(device_memory& /*kg*/, device_memory& /*data*/, size_t num_threads) { + CUDAContextScope scope(device); + device_vector<uint64_t> size_buffer; size_buffer.resize(1); device->mem_alloc(NULL, size_buffer, MEM_READ_WRITE); - device->cuda_push_context(); - uint threads = num_threads; CUdeviceptr d_size = device->cuda_device_ptr(size_buffer.device_pointer); @@ -1950,8 +1914,6 @@ uint64_t CUDASplitKernel::state_buffer_size(device_memory& /*kg*/, device_memory 1, 1, 1, 0, 0, (void**)&args, 0)); - device->cuda_pop_context(); - device->mem_copy_from(size_buffer, 0, 1, 1, sizeof(uint64_t)); device->mem_free(size_buffer); @@ -1969,7 +1931,7 @@ bool CUDASplitKernel::enqueue_split_kernel_data_init(const KernelDimensions& dim device_memory& use_queues_flag, device_memory& work_pool_wgs) { - device->cuda_push_context(); + CUDAContextScope scope(device); CUdeviceptr d_split_data = device->cuda_device_ptr(split_data.device_pointer); CUdeviceptr d_ray_state = device->cuda_device_ptr(ray_state.device_pointer); @@ -2033,26 +1995,21 @@ bool CUDASplitKernel::enqueue_split_kernel_data_init(const KernelDimensions& dim CUDASplitKernelFunction(device, data_init).enqueue(dim, (void**)&args); - device->cuda_pop_context(); - return !device->have_error(); } SplitKernelFunction* CUDASplitKernel::get_split_kernel_function(const string& kernel_name, const DeviceRequestedFeatures&) { + CUDAContextScope scope(device); CUfunction func; - device->cuda_push_context(); - cuda_assert(cuModuleGetFunction(&func, device->cuModule, (string("kernel_cuda_") + kernel_name).data())); if(device->have_error()) { device->cuda_error_message(string_printf("kernel \"kernel_cuda_%s\" not found in module", kernel_name.data())); return NULL; } - device->cuda_pop_context(); - return new CUDASplitKernelFunction(device, func); } @@ -2063,12 +2020,11 @@ int2 CUDASplitKernel::split_kernel_local_size() int2 CUDASplitKernel::split_kernel_global_size(device_memory& kg, device_memory& data, DeviceTask * /*task*/) { + CUDAContextScope scope(device); size_t free; size_t total; - device->cuda_push_context(); cuda_assert(cuMemGetInfo(&free, &total)); - device->cuda_pop_context(); VLOG(1) << "Maximum device allocation size: " << string_human_readable_number(free) << " bytes. (" @@ -2127,18 +2083,34 @@ Device *device_cuda_create(DeviceInfo& info, Stats &stats, bool background) return new CUDADevice(info, stats, background); } -void device_cuda_info(vector<DeviceInfo>& devices) +static CUresult device_cuda_safe_init() { - CUresult result; - int count = 0; +#ifdef _WIN32 + __try { + return cuInit(0); + } + __except(EXCEPTION_EXECUTE_HANDLER) { + /* Ignore crashes inside the CUDA driver and hope we can + * survive even with corrupted CUDA installs. */ + fprintf(stderr, "Cycles CUDA: driver crashed, continuing without CUDA.\n"); + } - result = cuInit(0); + return CUDA_ERROR_NO_DEVICE; +#else + return cuInit(0); +#endif +} + +void device_cuda_info(vector<DeviceInfo>& devices) +{ + CUresult result = device_cuda_safe_init(); if(result != CUDA_SUCCESS) { if(result != CUDA_ERROR_NO_DEVICE) fprintf(stderr, "CUDA cuInit: %s\n", cuewErrorString(result)); return; } + int count = 0; result = cuDeviceGetCount(&count); if(result != CUDA_SUCCESS) { fprintf(stderr, "CUDA cuDeviceGetCount: %s\n", cuewErrorString(result)); @@ -2168,7 +2140,6 @@ void device_cuda_info(vector<DeviceInfo>& devices) info.advanced_shading = (major >= 2); info.has_bindless_textures = (major >= 3); - info.pack_images = false; int pci_location[3] = {0, 0, 0}; cuDeviceGetAttribute(&pci_location[0], CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID, num); @@ -2196,7 +2167,7 @@ void device_cuda_info(vector<DeviceInfo>& devices) string device_cuda_capabilities(void) { - CUresult result = cuInit(0); + CUresult result = device_cuda_safe_init(); if(result != CUDA_SUCCESS) { if(result != CUDA_ERROR_NO_DEVICE) { return string("Error initializing CUDA: ") + cuewErrorString(result); diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp index 66758954f44..571ba9465ca 100644 --- a/intern/cycles/device/device_network.cpp +++ b/intern/cycles/device/device_network.cpp @@ -344,7 +344,6 @@ void device_network_info(vector<DeviceInfo>& devices) info.id = "NETWORK"; info.num = 0; info.advanced_shading = true; /* todo: get this info from device */ - info.pack_images = false; devices.push_back(info); } diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index 681b8214b03..9d89decaaaf 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -73,8 +73,34 @@ bool device_opencl_init(void) return result; } + +static cl_int device_opencl_get_num_platforms_safe(cl_uint *num_platforms) +{ +#ifdef _WIN32 + __try { + return clGetPlatformIDs(0, NULL, num_platforms); + } + __except(EXCEPTION_EXECUTE_HANDLER) { + /* Ignore crashes inside the OpenCL driver and hope we can + * survive even with corrupted OpenCL installs. */ + fprintf(stderr, "Cycles OpenCL: driver crashed, continuing without OpenCL.\n"); + } + + *num_platforms = 0; + return CL_DEVICE_NOT_FOUND; +#else + return clGetPlatformIDs(0, NULL, num_platforms); +#endif +} + void device_opencl_info(vector<DeviceInfo>& devices) { + cl_uint num_platforms = 0; + device_opencl_get_num_platforms_safe(&num_platforms); + if(num_platforms == 0) { + return; + } + vector<OpenCLPlatformDevice> usable_devices; OpenCLInfo::get_usable_devices(&usable_devices); /* Devices are numbered consecutively across platforms. */ @@ -95,7 +121,6 @@ void device_opencl_info(vector<DeviceInfo>& devices) /* We don't know if it's used for display, but assume it is. */ info.display_device = true; info.advanced_shading = OpenCLInfo::kernel_use_advanced_shading(platform_name); - info.pack_images = true; info.use_split_kernel = OpenCLInfo::kernel_use_split(platform_name, device_type); info.id = string("OPENCL_") + platform_name + "_" + device_name + "_" + hardware_id; @@ -114,7 +139,7 @@ string device_opencl_capabilities(void) * it could also be nicely reported to the console. */ cl_uint num_platforms = 0; - opencl_assert(clGetPlatformIDs(0, NULL, &num_platforms)); + opencl_assert(device_opencl_get_num_platforms_safe(&num_platforms)); if(num_platforms == 0) { return "No OpenCL platforms found\n"; } diff --git a/intern/cycles/device/opencl/memory_manager.cpp b/intern/cycles/device/opencl/memory_manager.cpp new file mode 100644 index 00000000000..b67dfef88aa --- /dev/null +++ b/intern/cycles/device/opencl/memory_manager.cpp @@ -0,0 +1,253 @@ +/* + * Copyright 2011-2017 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef WITH_OPENCL + +#include "util/util_foreach.h" + +#include "device/opencl/opencl.h" +#include "device/opencl/memory_manager.h" + +CCL_NAMESPACE_BEGIN + +void MemoryManager::DeviceBuffer::add_allocation(Allocation& allocation) +{ + allocations.push_back(&allocation); +} + +void MemoryManager::DeviceBuffer::update_device_memory(OpenCLDeviceBase *device) +{ + bool need_realloc = false; + + /* Calculate total size and remove any freed. */ + size_t total_size = 0; + + for(int i = allocations.size()-1; i >= 0; i--) { + Allocation* allocation = allocations[i]; + + /* Remove allocations that have been freed. */ + if(!allocation->mem || allocation->mem->memory_size() == 0) { + allocation->device_buffer = NULL; + allocation->size = 0; + + allocations.erase(allocations.begin()+i); + + need_realloc = true; + + continue; + } + + /* Get actual size for allocation. */ + size_t alloc_size = align_up(allocation->mem->memory_size(), 16); + + if(allocation->size != alloc_size) { + /* Allocation is either new or resized. */ + allocation->size = alloc_size; + allocation->needs_copy_to_device = true; + + need_realloc = true; + } + + total_size += alloc_size; + } + + if(need_realloc) { + cl_ulong max_buffer_size; + clGetDeviceInfo(device->cdDevice, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &max_buffer_size, NULL); + + if(total_size > max_buffer_size) { + device->set_error("Scene too complex to fit in available memory."); + return; + } + + device_memory *new_buffer = new device_memory; + + new_buffer->resize(total_size); + device->mem_alloc(string_printf("buffer_%p", this).data(), *new_buffer, MEM_READ_ONLY); + + size_t offset = 0; + + foreach(Allocation* allocation, allocations) { + if(allocation->needs_copy_to_device) { + /* Copy from host to device. */ + opencl_device_assert(device, clEnqueueWriteBuffer(device->cqCommandQueue, + CL_MEM_PTR(new_buffer->device_pointer), + CL_FALSE, + offset, + allocation->mem->memory_size(), + (void*)allocation->mem->data_pointer, + 0, NULL, NULL + )); + + allocation->needs_copy_to_device = false; + } + else { + /* Fast copy from memory already on device. */ + opencl_device_assert(device, clEnqueueCopyBuffer(device->cqCommandQueue, + CL_MEM_PTR(buffer->device_pointer), + CL_MEM_PTR(new_buffer->device_pointer), + allocation->desc.offset, + offset, + allocation->mem->memory_size(), + 0, NULL, NULL + )); + } + + allocation->desc.offset = offset; + offset += allocation->size; + } + + device->mem_free(*buffer); + delete buffer; + + buffer = new_buffer; + } + else { + assert(total_size == buffer->data_size); + + size_t offset = 0; + + foreach(Allocation* allocation, allocations) { + if(allocation->needs_copy_to_device) { + /* Copy from host to device. */ + opencl_device_assert(device, clEnqueueWriteBuffer(device->cqCommandQueue, + CL_MEM_PTR(buffer->device_pointer), + CL_FALSE, + offset, + allocation->mem->memory_size(), + (void*)allocation->mem->data_pointer, + 0, NULL, NULL + )); + + allocation->needs_copy_to_device = false; + } + + offset += allocation->size; + } + } + + /* Not really necessary, but seems to improve responsiveness for some reason. */ + clFinish(device->cqCommandQueue); +} + +void MemoryManager::DeviceBuffer::free(OpenCLDeviceBase *device) +{ + device->mem_free(*buffer); +} + +MemoryManager::DeviceBuffer* MemoryManager::smallest_device_buffer() +{ + DeviceBuffer* smallest = device_buffers; + + foreach(DeviceBuffer& device_buffer, device_buffers) { + if(device_buffer.size < smallest->size) { + smallest = &device_buffer; + } + } + + return smallest; +} + +MemoryManager::MemoryManager(OpenCLDeviceBase *device) : device(device), need_update(false) +{ +} + +void MemoryManager::free() +{ + foreach(DeviceBuffer& device_buffer, device_buffers) { + device_buffer.free(device); + } +} + +void MemoryManager::alloc(const char *name, device_memory& mem) +{ + Allocation& allocation = allocations[name]; + + allocation.mem = &mem; + allocation.needs_copy_to_device = true; + + if(!allocation.device_buffer) { + DeviceBuffer* device_buffer = smallest_device_buffer(); + allocation.device_buffer = device_buffer; + + allocation.desc.device_buffer = device_buffer - device_buffers; + + device_buffer->add_allocation(allocation); + + device_buffer->size += mem.memory_size(); + } + + need_update = true; +} + +bool MemoryManager::free(device_memory& mem) +{ + foreach(AllocationsMap::value_type& value, allocations) { + Allocation& allocation = value.second; + if(allocation.mem == &mem) { + + allocation.device_buffer->size -= mem.memory_size(); + + allocation.mem = NULL; + allocation.needs_copy_to_device = false; + + need_update = true; + return true; + } + } + + return false; +} + +MemoryManager::BufferDescriptor MemoryManager::get_descriptor(string name) +{ + update_device_memory(); + + Allocation& allocation = allocations[name]; + return allocation.desc; +} + +void MemoryManager::update_device_memory() +{ + if(!need_update) { + return; + } + + need_update = false; + + foreach(DeviceBuffer& device_buffer, device_buffers) { + device_buffer.update_device_memory(device); + } +} + +void MemoryManager::set_kernel_arg_buffers(cl_kernel kernel, cl_uint *narg) +{ + update_device_memory(); + + foreach(DeviceBuffer& device_buffer, device_buffers) { + if(device_buffer.buffer->device_pointer) { + device->kernel_set_args(kernel, (*narg)++, *device_buffer.buffer); + } + else { + device->kernel_set_args(kernel, (*narg)++, device->null_mem); + } + } +} + +CCL_NAMESPACE_END + +#endif /* WITH_OPENCL */ + diff --git a/intern/cycles/device/opencl/memory_manager.h b/intern/cycles/device/opencl/memory_manager.h new file mode 100644 index 00000000000..3714405d026 --- /dev/null +++ b/intern/cycles/device/opencl/memory_manager.h @@ -0,0 +1,105 @@ +/* + * Copyright 2011-2017 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "device/device.h" + +#include "util/util_map.h" +#include "util/util_vector.h" +#include "util/util_string.h" + +#include "clew.h" + +CCL_NAMESPACE_BEGIN + +class OpenCLDeviceBase; + +class MemoryManager { +public: + static const int NUM_DEVICE_BUFFERS = 8; + + struct BufferDescriptor { + uint device_buffer; + cl_ulong offset; + }; + +private: + struct DeviceBuffer; + + struct Allocation { + device_memory *mem; + + DeviceBuffer *device_buffer; + size_t size; /* Size of actual allocation, may be larger than requested. */ + + BufferDescriptor desc; + + bool needs_copy_to_device; + + Allocation() : mem(NULL), device_buffer(NULL), size(0), needs_copy_to_device(false) + { + } + }; + + struct DeviceBuffer { + device_memory *buffer; + vector<Allocation*> allocations; + size_t size; /* Size of all allocations. */ + + DeviceBuffer() : buffer(new device_memory), size(0) + { + } + + ~DeviceBuffer() { + delete buffer; + buffer = NULL; + } + + void add_allocation(Allocation& allocation); + + void update_device_memory(OpenCLDeviceBase *device); + + void free(OpenCLDeviceBase *device); + }; + + OpenCLDeviceBase *device; + + DeviceBuffer device_buffers[NUM_DEVICE_BUFFERS]; + + typedef unordered_map<string, Allocation> AllocationsMap; + AllocationsMap allocations; + + bool need_update; + + DeviceBuffer* smallest_device_buffer(); + +public: + MemoryManager(OpenCLDeviceBase *device); + + void free(); /* Free all memory. */ + + void alloc(const char *name, device_memory& mem); + bool free(device_memory& mem); + + BufferDescriptor get_descriptor(string name); + + void update_device_memory(); + void set_kernel_arg_buffers(cl_kernel kernel, cl_uint *narg); +}; + +CCL_NAMESPACE_END + diff --git a/intern/cycles/device/opencl/opencl.h b/intern/cycles/device/opencl/opencl.h index 78ca377d933..26bf4a9af5b 100644 --- a/intern/cycles/device/opencl/opencl.h +++ b/intern/cycles/device/opencl/opencl.h @@ -25,6 +25,8 @@ #include "clew.h" +#include "device/opencl/memory_manager.h" + CCL_NAMESPACE_BEGIN /* Disable workarounds, seems to be working fine on latest drivers. */ @@ -224,6 +226,18 @@ public: static string get_kernel_md5(); }; +#define opencl_device_assert(device, stmt) \ + { \ + cl_int err = stmt; \ + \ + if(err != CL_SUCCESS) { \ + string message = string_printf("OpenCL error: %s in %s (%s:%d)", clewErrorString(err), #stmt, __FILE__, __LINE__); \ + if((device)->error_message() == "") \ + (device)->set_error(message); \ + fprintf(stderr, "%s\n", message.c_str()); \ + } \ + } (void)0 + #define opencl_assert(stmt) \ { \ cl_int err = stmt; \ @@ -344,6 +358,7 @@ public: size_t global_size_round_up(int group_size, int global_size); void enqueue_kernel(cl_kernel kernel, size_t w, size_t h, size_t max_workgroup_size = -1); void set_kernel_arg_mem(cl_kernel kernel, cl_uint *narg, const char *name); + void set_kernel_arg_buffers(cl_kernel kernel, cl_uint *narg); void film_convert(DeviceTask& task, device_ptr buffer, device_ptr rgba_byte, device_ptr rgba_half); void shader(DeviceTask& task); @@ -525,6 +540,42 @@ protected: virtual string build_options_for_base_program( const DeviceRequestedFeatures& /*requested_features*/); + +private: + MemoryManager memory_manager; + friend class MemoryManager; + + struct tex_info_t { + uint buffer, padding; + cl_ulong offset; + uint width, height, depth, options; + }; + static_assert_align(tex_info_t, 16); + + vector<tex_info_t> texture_descriptors; + device_memory texture_descriptors_buffer; + + struct Texture { + Texture() {} + Texture(device_memory* mem, + InterpolationType interpolation, + ExtensionType extension) + : mem(mem), + interpolation(interpolation), + extension(extension) { + } + device_memory* mem; + InterpolationType interpolation; + ExtensionType extension; + }; + + typedef map<string, Texture> TexturesMap; + TexturesMap textures; + + bool textures_need_update; + +protected: + void flush_texture_buffers(); }; Device *opencl_create_mega_device(DeviceInfo& info, Stats& stats, bool background); diff --git a/intern/cycles/device/opencl/opencl_base.cpp b/intern/cycles/device/opencl/opencl_base.cpp index 509da7a0a84..7bdf81462b8 100644 --- a/intern/cycles/device/opencl/opencl_base.cpp +++ b/intern/cycles/device/opencl/opencl_base.cpp @@ -29,6 +29,15 @@ CCL_NAMESPACE_BEGIN +struct texture_slot_t { + texture_slot_t(const string& name, int slot) + : name(name), + slot(slot) { + } + string name; + int slot; +}; + bool OpenCLDeviceBase::opencl_error(cl_int err) { if(err != CL_SUCCESS) { @@ -63,7 +72,7 @@ void OpenCLDeviceBase::opencl_assert_err(cl_int err, const char* where) } OpenCLDeviceBase::OpenCLDeviceBase(DeviceInfo& info, Stats &stats, bool background_) -: Device(info, stats, background_) +: Device(info, stats, background_), memory_manager(this) { cpPlatform = NULL; cdDevice = NULL; @@ -71,6 +80,7 @@ OpenCLDeviceBase::OpenCLDeviceBase(DeviceInfo& info, Stats &stats, bool backgrou cqCommandQueue = NULL; null_mem = 0; device_initialized = false; + textures_need_update = true; vector<OpenCLPlatformDevice> usable_devices; OpenCLInfo::get_usable_devices(&usable_devices); @@ -126,6 +136,12 @@ OpenCLDeviceBase::OpenCLDeviceBase(DeviceInfo& info, Stats &stats, bool backgrou return; } + /* Allocate this right away so that texture_descriptors_buffer is placed at offset 0 in the device memory buffers */ + texture_descriptors.resize(1); + texture_descriptors_buffer.resize(1); + texture_descriptors_buffer.data_pointer = (device_ptr)&texture_descriptors[0]; + memory_manager.alloc("texture_descriptors", texture_descriptors_buffer); + fprintf(stderr, "Device init success\n"); device_initialized = true; } @@ -134,6 +150,8 @@ OpenCLDeviceBase::~OpenCLDeviceBase() { task_pool.stop(); + memory_manager.free(); + if(null_mem) clReleaseMemObject(CL_MEM_PTR(null_mem)); @@ -493,29 +511,35 @@ void OpenCLDeviceBase::const_copy_to(const char *name, void *host, size_t size) void OpenCLDeviceBase::tex_alloc(const char *name, device_memory& mem, - InterpolationType /*interpolation*/, - ExtensionType /*extension*/) + InterpolationType interpolation, + ExtensionType extension) { VLOG(1) << "Texture allocate: " << name << ", " << string_human_readable_number(mem.memory_size()) << " bytes. (" << string_human_readable_size(mem.memory_size()) << ")"; - mem_alloc(NULL, mem, MEM_READ_ONLY); - mem_copy_to(mem); - assert(mem_map.find(name) == mem_map.end()); - mem_map.insert(MemMap::value_type(name, mem.device_pointer)); + + memory_manager.alloc(name, mem); + /* Set the pointer to non-null to keep code that inspects its value from thinking its unallocated. */ + mem.device_pointer = 1; + textures[name] = Texture(&mem, interpolation, extension); + textures_need_update = true; } void OpenCLDeviceBase::tex_free(device_memory& mem) { if(mem.device_pointer) { - foreach(const MemMap::value_type& value, mem_map) { - if(value.second == mem.device_pointer) { - mem_map.erase(value.first); + mem.device_pointer = 0; + + if(memory_manager.free(mem)) { + textures_need_update = true; + } + + foreach(TexturesMap::value_type& value, textures) { + if(value.second.mem == &mem) { + textures.erase(value.first); break; } } - - mem_free(mem); } } @@ -581,6 +605,98 @@ void OpenCLDeviceBase::set_kernel_arg_mem(cl_kernel kernel, cl_uint *narg, const opencl_assert(clSetKernelArg(kernel, (*narg)++, sizeof(ptr), (void*)&ptr)); } +void OpenCLDeviceBase::set_kernel_arg_buffers(cl_kernel kernel, cl_uint *narg) +{ + flush_texture_buffers(); + + memory_manager.set_kernel_arg_buffers(kernel, narg); +} + +void OpenCLDeviceBase::flush_texture_buffers() +{ + if(!textures_need_update) { + return; + } + textures_need_update = false; + + /* Setup slots for textures. */ + int num_slots = 0; + + vector<texture_slot_t> texture_slots; + +#define KERNEL_TEX(type, ttype, name) \ + if(textures.find(#name) != textures.end()) { \ + texture_slots.push_back(texture_slot_t(#name, num_slots)); \ + } \ + num_slots++; +#include "kernel/kernel_textures.h" + + int num_data_slots = num_slots; + + foreach(TexturesMap::value_type& tex, textures) { + string name = tex.first; + + if(string_startswith(name, "__tex_image")) { + int pos = name.rfind("_"); + int id = atoi(name.data() + pos + 1); + texture_slots.push_back(texture_slot_t(name, + num_data_slots + id)); + num_slots = max(num_slots, num_data_slots + id + 1); + } + } + + /* Realloc texture descriptors buffer. */ + memory_manager.free(texture_descriptors_buffer); + + texture_descriptors.resize(num_slots); + texture_descriptors_buffer.resize(num_slots * sizeof(tex_info_t)); + texture_descriptors_buffer.data_pointer = (device_ptr)&texture_descriptors[0]; + + memory_manager.alloc("texture_descriptors", texture_descriptors_buffer); + + /* Fill in descriptors */ + foreach(texture_slot_t& slot, texture_slots) { + Texture& tex = textures[slot.name]; + + tex_info_t& info = texture_descriptors[slot.slot]; + + MemoryManager::BufferDescriptor desc = memory_manager.get_descriptor(slot.name); + + info.offset = desc.offset; + info.buffer = desc.device_buffer; + + if(string_startswith(slot.name, "__tex_image")) { + info.width = tex.mem->data_width; + info.height = tex.mem->data_height; + info.depth = tex.mem->data_depth; + + info.options = 0; + + if(tex.interpolation == INTERPOLATION_CLOSEST) { + info.options |= (1 << 0); + } + + switch(tex.extension) { + case EXTENSION_REPEAT: + info.options |= (1 << 1); + break; + case EXTENSION_EXTEND: + info.options |= (1 << 2); + break; + case EXTENSION_CLIP: + info.options |= (1 << 3); + break; + default: + break; + } + } + } + + /* Force write of descriptors. */ + memory_manager.free(texture_descriptors_buffer); + memory_manager.alloc("texture_descriptors", texture_descriptors_buffer); +} + void OpenCLDeviceBase::film_convert(DeviceTask& task, device_ptr buffer, device_ptr rgba_byte, device_ptr rgba_half) { /* cast arguments to cl types */ @@ -605,10 +721,7 @@ void OpenCLDeviceBase::film_convert(DeviceTask& task, device_ptr buffer, device_ d_rgba, d_buffer); -#define KERNEL_TEX(type, ttype, name) \ -set_kernel_arg_mem(ckFilmConvertKernel, &start_arg_index, #name); -#include "kernel/kernel_textures.h" -#undef KERNEL_TEX + set_kernel_arg_buffers(ckFilmConvertKernel, &start_arg_index); start_arg_index += kernel_set_args(ckFilmConvertKernel, start_arg_index, @@ -1030,10 +1143,7 @@ void OpenCLDeviceBase::shader(DeviceTask& task) d_output_luma); } -#define KERNEL_TEX(type, ttype, name) \ - set_kernel_arg_mem(kernel, &start_arg_index, #name); -#include "kernel/kernel_textures.h" -#undef KERNEL_TEX + set_kernel_arg_buffers(kernel, &start_arg_index); start_arg_index += kernel_set_args(kernel, start_arg_index, diff --git a/intern/cycles/device/opencl/opencl_mega.cpp b/intern/cycles/device/opencl/opencl_mega.cpp index 06c15bcf401..ec47fdafa3d 100644 --- a/intern/cycles/device/opencl/opencl_mega.cpp +++ b/intern/cycles/device/opencl/opencl_mega.cpp @@ -82,10 +82,7 @@ public: d_buffer, d_rng_state); -#define KERNEL_TEX(type, ttype, name) \ - set_kernel_arg_mem(ckPathTraceKernel, &start_arg_index, #name); -#include "kernel/kernel_textures.h" -#undef KERNEL_TEX + set_kernel_arg_buffers(ckPathTraceKernel, &start_arg_index); start_arg_index += kernel_set_args(ckPathTraceKernel, start_arg_index, diff --git a/intern/cycles/device/opencl/opencl_split.cpp b/intern/cycles/device/opencl/opencl_split.cpp index 76d9983e9a2..16a96213100 100644 --- a/intern/cycles/device/opencl/opencl_split.cpp +++ b/intern/cycles/device/opencl/opencl_split.cpp @@ -99,6 +99,8 @@ public: void thread_run(DeviceTask *task) { + flush_texture_buffers(); + if(task->type == DeviceTask::FILM_CONVERT) { film_convert(*task, task->buffer, task->rgba_byte, task->rgba_half); } @@ -113,10 +115,19 @@ public: */ typedef struct KernelGlobals { ccl_constant KernelData *data; + ccl_global char *buffers[8]; + + typedef struct _tex_info_t { + uint buffer, padding; + uint64_t offset; + uint width, height, depth, options; + } _tex_info_t; + #define KERNEL_TEX(type, ttype, name) \ - ccl_global type *name; + _tex_info_t name; #include "kernel/kernel_textures.h" #undef KERNEL_TEX + SplitData split_data; SplitParams split_param_data; } KernelGlobals; @@ -217,11 +228,7 @@ public: *cached_memory.ray_state, *cached_memory.rng_state); -/* TODO(sergey): Avoid map lookup here. */ -#define KERNEL_TEX(type, ttype, name) \ - device->set_kernel_arg_mem(program(), &start_arg_index, #name); -#include "kernel/kernel_textures.h" -#undef KERNEL_TEX + device->set_kernel_arg_buffers(program(), &start_arg_index); start_arg_index += device->kernel_set_args(program(), @@ -352,11 +359,7 @@ public: ray_state, rtile.rng_state); -/* TODO(sergey): Avoid map lookup here. */ -#define KERNEL_TEX(type, ttype, name) \ - device->set_kernel_arg_mem(device->program_data_init(), &start_arg_index, #name); -#include "kernel/kernel_textures.h" -#undef KERNEL_TEX + device->set_kernel_arg_buffers(device->program_data_init(), &start_arg_index); start_arg_index += device->kernel_set_args(device->program_data_init(), diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp index 0d34af3e040..7d5173a5f1d 100644 --- a/intern/cycles/device/opencl/opencl_util.cpp +++ b/intern/cycles/device/opencl/opencl_util.cpp @@ -635,7 +635,7 @@ bool OpenCLInfo::device_supported(const string& platform_name, "Tahiti", "Pitcairn", "Capeverde", "Oland", NULL }; - for (int i = 0; blacklist[i] != NULL; i++) { + for(int i = 0; blacklist[i] != NULL; i++) { if(device_name == blacklist[i]) { VLOG(1) << "AMD device " << device_name << " not supported"; return false; diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 23e9bd311c4..b4ca16bdb48 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -79,7 +79,6 @@ set(SRC_HEADERS kernel_compat_cpu.h kernel_compat_cuda.h kernel_compat_opencl.h - kernel_debug.h kernel_differential.h kernel_emission.h kernel_film.h @@ -202,6 +201,7 @@ set(SRC_GEOM_HEADERS geom/geom.h geom/geom_attribute.h geom/geom_curve.h + geom/geom_curve_intersect.h geom/geom_motion_curve.h geom/geom_motion_triangle.h geom/geom_motion_triangle_intersect.h @@ -233,6 +233,7 @@ set(SRC_FILTER_HEADERS set(SRC_UTIL_HEADERS ../util/util_atomic.h ../util/util_color.h + ../util/util_defines.h ../util/util_half.h ../util/util_hash.h ../util/util_math.h diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h index 85741016b25..cf0c8542d69 100644 --- a/intern/cycles/kernel/bvh/bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -233,7 +233,7 @@ ccl_device_intersect void scene_intersect_subsurface(KernelGlobals *kg, ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, const Ray *ray, Intersection *isect, - int skip_object, + uint visibility, uint max_hits, uint *num_hits) { @@ -244,7 +244,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, return bvh_intersect_shadow_all_hair_motion(kg, ray, isect, - skip_object, + visibility, max_hits, num_hits); } @@ -253,7 +253,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, return bvh_intersect_shadow_all_motion(kg, ray, isect, - skip_object, + visibility, max_hits, num_hits); } @@ -264,7 +264,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, return bvh_intersect_shadow_all_hair(kg, ray, isect, - skip_object, + visibility, max_hits, num_hits); } @@ -275,7 +275,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, return bvh_intersect_shadow_all_instancing(kg, ray, isect, - skip_object, + visibility, max_hits, num_hits); } @@ -284,7 +284,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, return bvh_intersect_shadow_all(kg, ray, isect, - skip_object, + visibility, max_hits, num_hits); } diff --git a/intern/cycles/kernel/bvh/bvh_nodes.h b/intern/cycles/kernel/bvh/bvh_nodes.h index 74a9ebf14e4..6c33dad5426 100644 --- a/intern/cycles/kernel/bvh/bvh_nodes.h +++ b/intern/cycles/kernel/bvh/bvh_nodes.h @@ -52,8 +52,8 @@ ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals *kg, float c0hiy = (node1.z - P.y) * idir.y; float c0loz = (node2.x - P.z) * idir.z; float c0hiz = (node2.z - P.z) * idir.z; - float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); - float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); + float c0min = max4(0.0f, min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz)); + float c0max = min4(t, max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz)); float c1lox = (node0.y - P.x) * idir.x; float c1hix = (node0.w - P.x) * idir.x; @@ -61,8 +61,8 @@ ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals *kg, float c1hiy = (node1.w - P.y) * idir.y; float c1loz = (node2.y - P.z) * idir.z; float c1hiz = (node2.w - P.z) * idir.z; - float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); - float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); + float c1min = max4(0.0f, min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz)); + float c1max = min4(t, max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz)); dist[0] = c0min; dist[1] = c1min; @@ -101,8 +101,8 @@ ccl_device_forceinline int bvh_aligned_node_intersect_robust(KernelGlobals *kg, float c0hiy = (node1.z - P.y) * idir.y; float c0loz = (node2.x - P.z) * idir.z; float c0hiz = (node2.z - P.z) * idir.z; - float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); - float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); + float c0min = max4(0.0f, min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz)); + float c0max = min4(t, max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz)); float c1lox = (node0.y - P.x) * idir.x; float c1hix = (node0.w - P.x) * idir.x; @@ -110,8 +110,8 @@ ccl_device_forceinline int bvh_aligned_node_intersect_robust(KernelGlobals *kg, float c1hiy = (node1.w - P.y) * idir.y; float c1loz = (node2.y - P.z) * idir.z; float c1hiz = (node2.w - P.z) * idir.z; - float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); - float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); + float c1min = max4(0.0f, min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz)); + float c1max = min4(t, max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz)); if(difl != 0.0f) { float hdiff = 1.0f + difl; @@ -483,8 +483,8 @@ ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals *kg, ssef tfar_y = max(lower_y, upper_y); ssef tfar_z = max(lower_z, upper_z); - const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near); - const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far); + const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z); + const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z); sseb vmask = tnear <= tfar; dist[0] = tnear.f[0]; dist[1] = tnear.f[1]; @@ -545,8 +545,8 @@ ccl_device_forceinline int bvh_unaligned_node_intersect_robust(KernelGlobals *kg ssef tfar_y = max(lower_y, upper_y); ssef tfar_z = max(lower_z, upper_z); - const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near); - const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far); + const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z); + const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z); sseb vmask; if(difl != 0.0f) { const float round_down = 1.0f - difl; @@ -615,7 +615,7 @@ ccl_device_forceinline int bvh_node_intersect_robust(KernelGlobals *kg, const float3& P, const float3& dir, const ssef& isect_near, - const ssef& isect_far, + const ssef& isect_far, const ssef& tsplat, const ssef Psplat[3], const ssef idirsplat[3], diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h index 267e098f912..a6a4353562c 100644 --- a/intern/cycles/kernel/bvh/bvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h @@ -45,7 +45,7 @@ ccl_device_inline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, const Ray *ray, Intersection *isect_array, - const int skip_object, + const uint visibility, const uint max_hits, uint *num_hits) { @@ -119,7 +119,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, idir, isect_t, node_addr, - PATH_RAY_SHADOW, + visibility, dist); #else // __KERNEL_SSE2__ traverse_mask = NODE_INTERSECT(kg, @@ -134,7 +134,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, idirsplat, shufflexyz, node_addr, - PATH_RAY_SHADOW, + visibility, dist); #endif // __KERNEL_SSE2__ @@ -186,17 +186,6 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, /* primitive intersection */ while(prim_addr < prim_addr2) { kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == p_type); - -#ifdef __SHADOW_TRICKS__ - uint tri_object = (object == OBJECT_NONE) - ? kernel_tex_fetch(__prim_object, prim_addr) - : object; - if(tri_object == skip_object) { - ++prim_addr; - continue; - } -#endif - bool hit; /* todo: specialized intersect functions which don't fill in @@ -209,7 +198,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, isect_array, P, dir, - PATH_RAY_SHADOW, + visibility, object, prim_addr); break; @@ -221,7 +210,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, P, dir, ray->time, - PATH_RAY_SHADOW, + visibility, object, prim_addr); break; @@ -232,30 +221,30 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, case PRIMITIVE_MOTION_CURVE: { const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr); if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { - hit = bvh_cardinal_curve_intersect(kg, - isect_array, - P, - dir, - PATH_RAY_SHADOW, - object, - prim_addr, - ray->time, - curve_type, - NULL, - 0, 0); + hit = cardinal_curve_intersect(kg, + isect_array, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + curve_type, + NULL, + 0, 0); } else { - hit = bvh_curve_intersect(kg, - isect_array, - P, - dir, - PATH_RAY_SHADOW, - object, - prim_addr, - ray->time, - curve_type, - NULL, - 0, 0); + hit = curve_intersect(kg, + isect_array, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + curve_type, + NULL, + 0, 0); } break; } @@ -402,7 +391,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, const Ray *ray, Intersection *isect_array, - const int skip_object, + const uint visibility, const uint max_hits, uint *num_hits) { @@ -411,7 +400,7 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, return BVH_FUNCTION_FULL_NAME(QBVH)(kg, ray, isect_array, - skip_object, + visibility, max_hits, num_hits); } @@ -422,7 +411,7 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect_array, - skip_object, + visibility, max_hits, num_hits); } diff --git a/intern/cycles/kernel/bvh/bvh_traversal.h b/intern/cycles/kernel/bvh/bvh_traversal.h index c58d3b0316c..ae8f54821f2 100644 --- a/intern/cycles/kernel/bvh/bvh_traversal.h +++ b/intern/cycles/kernel/bvh/bvh_traversal.h @@ -244,14 +244,14 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, { /* shadow ray early termination */ #if defined(__KERNEL_SSE2__) - if(visibility == PATH_RAY_SHADOW_OPAQUE) + if(visibility & PATH_RAY_SHADOW_OPAQUE) return true; tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); # if BVH_FEATURE(BVH_HAIR) tfar = ssef(isect->t); # endif #else - if(visibility == PATH_RAY_SHADOW_OPAQUE) + if(visibility & PATH_RAY_SHADOW_OPAQUE) return true; #endif } @@ -274,14 +274,14 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, { /* shadow ray early termination */ # if defined(__KERNEL_SSE2__) - if(visibility == PATH_RAY_SHADOW_OPAQUE) + if(visibility & PATH_RAY_SHADOW_OPAQUE) return true; tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); # if BVH_FEATURE(BVH_HAIR) tfar = ssef(isect->t); # endif # else - if(visibility == PATH_RAY_SHADOW_OPAQUE) + if(visibility & PATH_RAY_SHADOW_OPAQUE) return true; # endif } @@ -298,44 +298,44 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, kernel_assert((curve_type & PRIMITIVE_ALL) == (type & PRIMITIVE_ALL)); bool hit; if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { - hit = bvh_cardinal_curve_intersect(kg, - isect, - P, - dir, - visibility, - object, - prim_addr, - ray->time, - curve_type, - lcg_state, - difl, - extmax); + hit = cardinal_curve_intersect(kg, + isect, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + curve_type, + lcg_state, + difl, + extmax); } else { - hit = bvh_curve_intersect(kg, - isect, - P, - dir, - visibility, - object, - prim_addr, - ray->time, - curve_type, - lcg_state, - difl, - extmax); + hit = curve_intersect(kg, + isect, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + curve_type, + lcg_state, + difl, + extmax); } if(hit) { /* shadow ray early termination */ # if defined(__KERNEL_SSE2__) - if(visibility == PATH_RAY_SHADOW_OPAQUE) + if(visibility & PATH_RAY_SHADOW_OPAQUE) return true; tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); # if BVH_FEATURE(BVH_HAIR) tfar = ssef(isect->t); # endif # else - if(visibility == PATH_RAY_SHADOW_OPAQUE) + if(visibility & PATH_RAY_SHADOW_OPAQUE) return true; # endif } diff --git a/intern/cycles/kernel/bvh/qbvh_nodes.h b/intern/cycles/kernel/bvh/qbvh_nodes.h index 6d22f0b0d6a..3036efd4198 100644 --- a/intern/cycles/kernel/bvh/qbvh_nodes.h +++ b/intern/cycles/kernel/bvh/qbvh_nodes.h @@ -126,8 +126,8 @@ ccl_device_inline int qbvh_aligned_node_intersect(KernelGlobals *ccl_restrict kg const sseb vmask = cast(tnear) > cast(tfar); int mask = (int)movemask(vmask)^0xf; #else - const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near); - const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far); + const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z); + const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z); const sseb vmask = tnear <= tfar; int mask = (int)movemask(vmask); #endif @@ -174,8 +174,8 @@ ccl_device_inline int qbvh_aligned_node_intersect_robust( const float round_down = 1.0f - difl; const float round_up = 1.0f + difl; - const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near); - const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far); + const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z); + const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z); const sseb vmask = round_down*tnear <= round_up*tfar; *dist = tnear; return (int)movemask(vmask); diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h index ce474438f2c..522213f30ca 100644 --- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h @@ -33,7 +33,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, Intersection *isect_array, - const int skip_object, + const uint visibility, const uint max_hits, uint *num_hits) { @@ -107,7 +107,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(false #ifdef __VISIBILITY_FLAG__ - || ((__float_as_uint(inodes.x) & PATH_RAY_SHADOW) == 0) + || ((__float_as_uint(inodes.x) & visibility) == 0) #endif #if BVH_FEATURE(BVH_MOTION) || UNLIKELY(ray->time < inodes.y) @@ -244,7 +244,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(node_addr < 0) { float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); #ifdef __VISIBILITY_FLAG__ - if((__float_as_uint(leaf.z) & PATH_RAY_SHADOW) == 0) { + if((__float_as_uint(leaf.z) & visibility) == 0) { /* Pop. */ node_addr = traversal_stack[stack_ptr].addr; --stack_ptr; @@ -268,17 +268,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Primitive intersection. */ while(prim_addr < prim_addr2) { kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == p_type); - -#ifdef __SHADOW_TRICKS__ - uint tri_object = (object == OBJECT_NONE) - ? kernel_tex_fetch(__prim_object, prim_addr) - : object; - if(tri_object == skip_object) { - ++prim_addr; - continue; - } -#endif - bool hit; /* todo: specialized intersect functions which don't fill in @@ -291,7 +280,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, isect_array, P, dir, - PATH_RAY_SHADOW, + visibility, object, prim_addr); break; @@ -303,7 +292,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, P, dir, ray->time, - PATH_RAY_SHADOW, + visibility, object, prim_addr); break; @@ -314,30 +303,30 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, case PRIMITIVE_MOTION_CURVE: { const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr); if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { - hit = bvh_cardinal_curve_intersect(kg, - isect_array, - P, - dir, - PATH_RAY_SHADOW, - object, - prim_addr, - ray->time, - curve_type, - NULL, - 0, 0); + hit = cardinal_curve_intersect(kg, + isect_array, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + curve_type, + NULL, + 0, 0); } else { - hit = bvh_curve_intersect(kg, - isect_array, - P, - dir, - PATH_RAY_SHADOW, - object, - prim_addr, - ray->time, - curve_type, - NULL, - 0, 0); + hit = curve_intersect(kg, + isect_array, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + curve_type, + NULL, + 0, 0); } break; } diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h index fca75a1d416..335a4afd47a 100644 --- a/intern/cycles/kernel/bvh/qbvh_traversal.h +++ b/intern/cycles/kernel/bvh/qbvh_traversal.h @@ -340,7 +340,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, prim_addr)) { tfar = ssef(isect->t); /* Shadow ray early termination. */ - if(visibility == PATH_RAY_SHADOW_OPAQUE) { + if(visibility & PATH_RAY_SHADOW_OPAQUE) { return true; } } @@ -362,7 +362,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, prim_addr)) { tfar = ssef(isect->t); /* Shadow ray early termination. */ - if(visibility == PATH_RAY_SHADOW_OPAQUE) { + if(visibility & PATH_RAY_SHADOW_OPAQUE) { return true; } } @@ -379,37 +379,37 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, kernel_assert((curve_type & PRIMITIVE_ALL) == (type & PRIMITIVE_ALL)); bool hit; if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { - hit = bvh_cardinal_curve_intersect(kg, - isect, - P, - dir, - visibility, - object, - prim_addr, - ray->time, - curve_type, - lcg_state, - difl, - extmax); + hit = cardinal_curve_intersect(kg, + isect, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + curve_type, + lcg_state, + difl, + extmax); } else { - hit = bvh_curve_intersect(kg, - isect, - P, - dir, - visibility, - object, - prim_addr, - ray->time, - curve_type, - lcg_state, - difl, - extmax); + hit = curve_intersect(kg, + isect, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + curve_type, + lcg_state, + difl, + extmax); } if(hit) { tfar = ssef(isect->t); /* Shadow ray early termination. */ - if(visibility == PATH_RAY_SHADOW_OPAQUE) { + if(visibility & PATH_RAY_SHADOW_OPAQUE) { return true; } } diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h index 22d0092093a..2f2c35d5d1f 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h @@ -40,20 +40,20 @@ ccl_device_forceinline float D_ggx_aniso(const float3 wm, const float2 alpha) } /* Sample slope distribution (based on page 14 of the supplemental implementation). */ -ccl_device_forceinline float2 mf_sampleP22_11(const float cosI, const float2 randU) +ccl_device_forceinline float2 mf_sampleP22_11(const float cosI, const float randx, const float randy) { if(cosI > 0.9999f || fabsf(cosI) < 1e-6f) { - const float r = sqrtf(randU.x / max(1.0f - randU.x, 1e-7f)); - const float phi = M_2PI_F * randU.y; + const float r = sqrtf(randx / max(1.0f - randx, 1e-7f)); + const float phi = M_2PI_F * randy; return make_float2(r*cosf(phi), r*sinf(phi)); } - const float sinI = sqrtf(1.0f - cosI*cosI); + const float sinI = safe_sqrtf(1.0f - cosI*cosI); const float tanI = sinI/cosI; const float projA = 0.5f * (cosI + 1.0f); if(projA < 0.0001f) return make_float2(0.0f, 0.0f); - const float A = 2.0f*randU.x*projA / cosI - 1.0f; + const float A = 2.0f*randx*projA / cosI - 1.0f; float tmp = A*A-1.0f; if(fabsf(tmp) < 1e-7f) return make_float2(0.0f, 0.0f); @@ -64,24 +64,24 @@ ccl_device_forceinline float2 mf_sampleP22_11(const float cosI, const float2 ran const float slopeX = (A < 0.0f || slopeX2 > 1.0f/tanI)? (tanI*tmp - D) : slopeX2; float U2; - if(randU.y >= 0.5f) - U2 = 2.0f*(randU.y - 0.5f); + if(randy >= 0.5f) + U2 = 2.0f*(randy - 0.5f); else - U2 = 2.0f*(0.5f - randU.y); + U2 = 2.0f*(0.5f - randy); const float z = (U2*(U2*(U2*0.27385f-0.73369f)+0.46341f)) / (U2*(U2*(U2*0.093073f+0.309420f)-1.0f)+0.597999f); const float slopeY = z * sqrtf(1.0f + slopeX*slopeX); - if(randU.y >= 0.5f) + if(randy >= 0.5f) return make_float2(slopeX, slopeY); else return make_float2(slopeX, -slopeY); } /* Visible normal sampling for the GGX distribution (based on page 7 of the supplemental implementation). */ -ccl_device_forceinline float3 mf_sample_vndf(const float3 wi, const float2 alpha, const float2 randU) +ccl_device_forceinline float3 mf_sample_vndf(const float3 wi, const float2 alpha, const float randx, const float randy) { const float3 wi_11 = normalize(make_float3(alpha.x*wi.x, alpha.y*wi.y, wi.z)); - const float2 slope_11 = mf_sampleP22_11(wi_11.z, randU); + const float2 slope_11 = mf_sampleP22_11(wi_11.z, randx, randy); const float3 cossin_phi = safe_normalize(make_float3(wi_11.x, wi_11.y, 0.0f)); const float slope_x = alpha.x*(cossin_phi.x * slope_11.x - cossin_phi.y * slope_11.y); @@ -474,6 +474,7 @@ ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderC *eval *= *pdf; *omega_in = X*localO.x + Y*localO.y + Z*localO.z; + #ifdef __RAY_DIFFERENTIALS__ *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h index 2eb2457c9e5..e73915dbda7 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h @@ -100,11 +100,14 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)( bool outside = true; for(int order = 0; order < 10; order++) { - /* Sample microfacet height and normal */ - if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float_addrspace(lcg_state))) + /* Sample microfacet height. */ + float height_rand = lcg_step_float_addrspace(lcg_state); + if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand)) break; - float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float_addrspace(lcg_state), - lcg_step_float_addrspace(lcg_state))); + /* Sample microfacet normal. */ + float vndf_rand_y = lcg_step_float_addrspace(lcg_state); + float vndf_rand_x = lcg_step_float_addrspace(lcg_state); + float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y); #ifdef MF_MULTI_GLASS if(order == 0 && use_fresnel) { @@ -136,7 +139,8 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)( #ifdef MF_MULTI_GLASS bool next_outside; float3 wi_prev = -wr; - wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside); + float phase_rand = lcg_step_float_addrspace(lcg_state); + wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, phase_rand, &next_outside); if(!next_outside) { outside = !outside; wr = -wr; @@ -204,14 +208,16 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)( int order; for(order = 0; order < 10; order++) { /* Sample microfacet height. */ - if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float_addrspace(lcg_state))) { + float height_rand = lcg_step_float_addrspace(lcg_state); + if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand)) { /* The random walk has left the surface. */ *wo = outside? wr: -wr; return throughput; } /* Sample microfacet normal. */ - float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float_addrspace(lcg_state), - lcg_step_float_addrspace(lcg_state))); + float vndf_rand_y = lcg_step_float_addrspace(lcg_state); + float vndf_rand_x = lcg_step_float_addrspace(lcg_state); + float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y); /* First-bounce color is already accounted for in mix weight. */ if(!use_fresnel && order > 0) @@ -221,7 +227,8 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)( #ifdef MF_MULTI_GLASS bool next_outside; float3 wi_prev = -wr; - wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside); + float phase_rand = lcg_step_float_addrspace(lcg_state); + wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, phase_rand, &next_outside); if(!next_outside) { hr = -hr; wr = -wr; diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h index f733ea4c517..267aeea6e86 100644 --- a/intern/cycles/kernel/closure/bssrdf.h +++ b/intern/cycles/kernel/closure/bssrdf.h @@ -348,8 +348,9 @@ ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight) { Bssrdf *bssrdf = (Bssrdf*)closure_alloc(sd, sizeof(Bssrdf), CLOSURE_NONE_ID, weight); - if(!bssrdf) + if(bssrdf == NULL) { return NULL; + } float sample_weight = fabsf(average(weight)); bssrdf->sample_weight = sample_weight; @@ -399,7 +400,7 @@ ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type) bssrdf_burley_setup(bssrdf); } - return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF; + return SD_BSSRDF; } } diff --git a/intern/cycles/kernel/filter/filter_features_sse.h b/intern/cycles/kernel/filter/filter_features_sse.h index 3185330994c..3ddd8712266 100644 --- a/intern/cycles/kernel/filter/filter_features_sse.h +++ b/intern/cycles/kernel/filter/filter_features_sse.h @@ -16,7 +16,7 @@ CCL_NAMESPACE_BEGIN -#define ccl_get_feature_sse(pass) _mm_loadu_ps(buffer + (pass)*pass_stride) +#define ccl_get_feature_sse(pass) load_float4(buffer + (pass)*pass_stride) /* Loop over the pixels in the range [low.x, high.x) x [low.y, high.y), 4 at a time. * pixel_buffer always points to the first of the 4 current pixel in the first pass. @@ -24,25 +24,25 @@ CCL_NAMESPACE_BEGIN #define FOR_PIXEL_WINDOW_SSE pixel_buffer = buffer + (low.y - rect.y)*buffer_w + (low.x - rect.x); \ for(pixel.y = low.y; pixel.y < high.y; pixel.y++) { \ - __m128 y4 = _mm_set1_ps(pixel.y); \ + float4 y4 = make_float4(pixel.y); \ for(pixel.x = low.x; pixel.x < high.x; pixel.x += 4, pixel_buffer += 4) { \ - __m128 x4 = _mm_add_ps(_mm_set1_ps(pixel.x), _mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f)); \ - __m128 active_pixels = _mm_cmplt_ps(x4, _mm_set1_ps(high.x)); + float4 x4 = make_float4(pixel.x) + make_float4(0.0f, 1.0f, 2.0f, 3.0f); \ + int4 active_pixels = x4 < make_float4(high.x); #define END_FOR_PIXEL_WINDOW_SSE } \ pixel_buffer += buffer_w - (pixel.x - low.x); \ } -ccl_device_inline void filter_get_features_sse(__m128 x, __m128 y, - __m128 active_pixels, +ccl_device_inline void filter_get_features_sse(float4 x, float4 y, + int4 active_pixels, const float *ccl_restrict buffer, - __m128 *features, - const __m128 *ccl_restrict mean, + float4 *features, + const float4 *ccl_restrict mean, int pass_stride) { features[0] = x; features[1] = y; - features[2] = _mm_fabs_ps(ccl_get_feature_sse(0)); + features[2] = fabs(ccl_get_feature_sse(0)); features[3] = ccl_get_feature_sse(1); features[4] = ccl_get_feature_sse(2); features[5] = ccl_get_feature_sse(3); @@ -52,53 +52,41 @@ ccl_device_inline void filter_get_features_sse(__m128 x, __m128 y, features[9] = ccl_get_feature_sse(7); if(mean) { for(int i = 0; i < DENOISE_FEATURES; i++) - features[i] = _mm_sub_ps(features[i], mean[i]); + features[i] = features[i] - mean[i]; } for(int i = 0; i < DENOISE_FEATURES; i++) - features[i] = _mm_mask_ps(features[i], active_pixels); + features[i] = mask(active_pixels, features[i]); } -ccl_device_inline void filter_get_feature_scales_sse(__m128 x, __m128 y, - __m128 active_pixels, +ccl_device_inline void filter_get_feature_scales_sse(float4 x, float4 y, + int4 active_pixels, const float *ccl_restrict buffer, - __m128 *scales, - const __m128 *ccl_restrict mean, + float4 *scales, + const float4 *ccl_restrict mean, int pass_stride) { - scales[0] = _mm_mask_ps(_mm_fabs_ps(_mm_sub_ps(x, mean[0])), active_pixels); - scales[1] = _mm_mask_ps(_mm_fabs_ps(_mm_sub_ps(y, mean[1])), active_pixels); - - scales[2] = _mm_mask_ps(_mm_fabs_ps(_mm_sub_ps(_mm_fabs_ps(ccl_get_feature_sse(0)), mean[2])), active_pixels); - - __m128 diff, scale; - diff = _mm_sub_ps(ccl_get_feature_sse(1), mean[3]); - scale = _mm_mul_ps(diff, diff); - diff = _mm_sub_ps(ccl_get_feature_sse(2), mean[4]); - scale = _mm_add_ps(scale, _mm_mul_ps(diff, diff)); - diff = _mm_sub_ps(ccl_get_feature_sse(3), mean[5]); - scale = _mm_add_ps(scale, _mm_mul_ps(diff, diff)); - scales[3] = _mm_mask_ps(scale, active_pixels); - - scales[4] = _mm_mask_ps(_mm_fabs_ps(_mm_sub_ps(ccl_get_feature_sse(4), mean[6])), active_pixels); - - diff = _mm_sub_ps(ccl_get_feature_sse(5), mean[7]); - scale = _mm_mul_ps(diff, diff); - diff = _mm_sub_ps(ccl_get_feature_sse(6), mean[8]); - scale = _mm_add_ps(scale, _mm_mul_ps(diff, diff)); - diff = _mm_sub_ps(ccl_get_feature_sse(7), mean[9]); - scale = _mm_add_ps(scale, _mm_mul_ps(diff, diff)); - scales[5] = _mm_mask_ps(scale, active_pixels); + scales[0] = fabs(x - mean[0]); + scales[1] = fabs(y - mean[1]); + scales[2] = fabs(fabs(ccl_get_feature_sse(0)) - mean[2]); + scales[3] = sqr(ccl_get_feature_sse(1) - mean[3]) + + sqr(ccl_get_feature_sse(2) - mean[4]) + + sqr(ccl_get_feature_sse(3) - mean[5]); + scales[4] = fabs(ccl_get_feature_sse(4) - mean[6]); + scales[5] = sqr(ccl_get_feature_sse(5) - mean[7]) + + sqr(ccl_get_feature_sse(6) - mean[8]) + + sqr(ccl_get_feature_sse(7) - mean[9]); + for(int i = 0; i < 6; i++) + scales[i] = mask(active_pixels, scales[i]); } -ccl_device_inline void filter_calculate_scale_sse(__m128 *scale) +ccl_device_inline void filter_calculate_scale_sse(float4 *scale) { - scale[0] = _mm_rcp_ps(_mm_max_ps(_mm_hmax_ps(scale[0]), _mm_set1_ps(0.01f))); - scale[1] = _mm_rcp_ps(_mm_max_ps(_mm_hmax_ps(scale[1]), _mm_set1_ps(0.01f))); - scale[2] = _mm_rcp_ps(_mm_max_ps(_mm_hmax_ps(scale[2]), _mm_set1_ps(0.01f))); - scale[6] = _mm_rcp_ps(_mm_max_ps(_mm_hmax_ps(scale[4]), _mm_set1_ps(0.01f))); - - scale[7] = scale[8] = scale[9] = _mm_rcp_ps(_mm_max_ps(_mm_hmax_ps(_mm_sqrt_ps(scale[5])), _mm_set1_ps(0.01f))); - scale[3] = scale[4] = scale[5] = _mm_rcp_ps(_mm_max_ps(_mm_hmax_ps(_mm_sqrt_ps(scale[3])), _mm_set1_ps(0.01f))); + scale[0] = rcp(max(reduce_max(scale[0]), make_float4(0.01f))); + scale[1] = rcp(max(reduce_max(scale[1]), make_float4(0.01f))); + scale[2] = rcp(max(reduce_max(scale[2]), make_float4(0.01f))); + scale[6] = rcp(max(reduce_max(scale[4]), make_float4(0.01f))); + scale[7] = scale[8] = scale[9] = rcp(max(reduce_max(sqrt(scale[5])), make_float4(0.01f))); + scale[3] = scale[4] = scale[5] = rcp(max(reduce_max(sqrt(scale[3])), make_float4(0.01f))); } diff --git a/intern/cycles/kernel/filter/filter_nlm_cpu.h b/intern/cycles/kernel/filter/filter_nlm_cpu.h index 3e752bce68f..5e989331bc2 100644 --- a/intern/cycles/kernel/filter/filter_nlm_cpu.h +++ b/intern/cycles/kernel/filter/filter_nlm_cpu.h @@ -50,10 +50,8 @@ ccl_device_inline void kernel_filter_nlm_blur(const float *ccl_restrict differen int w, int f) { -#ifdef __KERNEL_SSE3__ - int aligned_lowx = (rect.x & ~(3)); - int aligned_highx = ((rect.z + 3) & ~(3)); -#endif + int aligned_lowx = rect.x / 4; + int aligned_highx = (rect.z + 3) / 4; for(int y = rect.y; y < rect.w; y++) { const int low = max(rect.y, y-f); const int high = min(rect.w, y+f+1); @@ -61,15 +59,11 @@ ccl_device_inline void kernel_filter_nlm_blur(const float *ccl_restrict differen out_image[y*w+x] = 0.0f; } for(int y1 = low; y1 < high; y1++) { -#ifdef __KERNEL_SSE3__ - for(int x = aligned_lowx; x < aligned_highx; x+=4) { - _mm_store_ps(out_image + y*w+x, _mm_add_ps(_mm_load_ps(out_image + y*w+x), _mm_load_ps(difference_image + y1*w+x))); + float4* out_image4 = (float4*)(out_image + y*w); + float4* difference_image4 = (float4*)(difference_image + y1*w); + for(int x = aligned_lowx; x < aligned_highx; x++) { + out_image4[x] += difference_image4[x]; } -#else - for(int x = rect.x; x < rect.z; x++) { - out_image[y*w+x] += difference_image[y1*w+x]; - } -#endif } for(int x = rect.x; x < rect.z; x++) { out_image[y*w+x] *= 1.0f/(high - low); diff --git a/intern/cycles/kernel/filter/filter_prefilter.h b/intern/cycles/kernel/filter/filter_prefilter.h index d5ae1b73927..2aeb54a62be 100644 --- a/intern/cycles/kernel/filter/filter_prefilter.h +++ b/intern/cycles/kernel/filter/filter_prefilter.h @@ -61,8 +61,8 @@ ccl_device void kernel_filter_divide_shadow(int sample, varA = max(0.0f, varA - unfilteredA[idx]*unfilteredA[idx]*odd_sample); varB = max(0.0f, varB - unfilteredB[idx]*unfilteredB[idx]*even_sample); } - varA /= (odd_sample - 1); - varB /= (even_sample - 1); + varA /= max(odd_sample - 1, 1); + varB /= max(even_sample - 1, 1); sampleVariance[idx] = 0.5f*(varA + varB) / sample; sampleVarianceV[idx] = 0.5f * (varA - varB) * (varA - varB) / (sample*sample); @@ -96,11 +96,17 @@ ccl_device void kernel_filter_get_feature(int sample, int idx = (y-rect.y)*buffer_w + (x - rect.x); mean[idx] = center_buffer[m_offset] / sample; - if(use_split_variance) { - variance[idx] = max(0.0f, (center_buffer[v_offset] - mean[idx]*mean[idx]*sample) / (sample * (sample-1))); + if(sample > 1) { + if(use_split_variance) { + variance[idx] = max(0.0f, (center_buffer[v_offset] - mean[idx]*mean[idx]*sample) / (sample * (sample-1))); + } + else { + variance[idx] = center_buffer[v_offset] / (sample * (sample-1)); + } } else { - variance[idx] = center_buffer[v_offset] / (sample * (sample-1)); + /* Can't compute variance with single sample, just set it very high. */ + variance[idx] = 1e10f; } } @@ -114,49 +120,56 @@ ccl_device void kernel_filter_detect_outliers(int x, int y, { int buffer_w = align_up(rect.z - rect.x, 4); - int n = 0; - float values[25]; - for(int y1 = max(y-2, rect.y); y1 < min(y+3, rect.w); y1++) { - for(int x1 = max(x-2, rect.x); x1 < min(x+3, rect.z); x1++) { - int idx = (y1-rect.y)*buffer_w + (x1-rect.x); - float L = average(make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride])); - - /* Find the position of L. */ - int i; - for(i = 0; i < n; i++) { - if(values[i] > L) break; - } - /* Make space for L by shifting all following values to the right. */ - for(int j = n; j > i; j--) { - values[j] = values[j-1]; - } - /* Insert L. */ - values[i] = L; - n++; - } - } - int idx = (y-rect.y)*buffer_w + (x-rect.x); - float L = average(make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride])); + float3 color = make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]); - float ref = 2.0f*values[(int)(n*0.75f)]; float fac = 1.0f; - if(L > ref) { - /* The pixel appears to be an outlier. - * However, it may just be a legitimate highlight. Therefore, it is checked how likely it is that the pixel - * should actually be at the reference value: - * If the reference is within the 3-sigma interval, the pixel is assumed to be a statistical outlier. - * Otherwise, it is very unlikely that the pixel should be darker, which indicates a legitimate highlight. - */ - float stddev = sqrtf(average(make_float3(variance[idx], variance[idx+pass_stride], variance[idx+2*pass_stride]))); - if(L - 3*stddev < ref) { - /* The pixel is an outlier, so negate the depth value to mark it as one. - * Also, scale its brightness down to the outlier threshold to avoid trouble with the NLM weights. */ - depth[idx] = -depth[idx]; - fac = ref/L; - variance[idx ] *= fac*fac; - variance[idx + pass_stride] *= fac*fac; - variance[idx+2*pass_stride] *= fac*fac; + if(color.x < 0.0f || color.y < 0.0f || color.z < 0.0f) { + depth[idx] = -depth[idx]; + fac = 0.0f; + } + else { + float L = average(color); + int n = 0; + float values[25]; + for(int y1 = max(y-2, rect.y); y1 < min(y+3, rect.w); y1++) { + for(int x1 = max(x-2, rect.x); x1 < min(x+3, rect.z); x1++) { + int idx = (y1-rect.y)*buffer_w + (x1-rect.x); + float L = average(make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride])); + + /* Find the position of L. */ + int i; + for(i = 0; i < n; i++) { + if(values[i] > L) break; + } + /* Make space for L by shifting all following values to the right. */ + for(int j = n; j > i; j--) { + values[j] = values[j-1]; + } + /* Insert L. */ + values[i] = L; + n++; + } + } + + float ref = 2.0f*values[(int)(n*0.75f)]; + if(L > ref) { + /* The pixel appears to be an outlier. + * However, it may just be a legitimate highlight. Therefore, it is checked how likely it is that the pixel + * should actually be at the reference value: + * If the reference is within the 3-sigma interval, the pixel is assumed to be a statistical outlier. + * Otherwise, it is very unlikely that the pixel should be darker, which indicates a legitimate highlight. + */ + float stddev = sqrtf(average(make_float3(variance[idx], variance[idx+pass_stride], variance[idx+2*pass_stride]))); + if(L - 3*stddev < ref) { + /* The pixel is an outlier, so negate the depth value to mark it as one. + * Also, scale its brightness down to the outlier threshold to avoid trouble with the NLM weights. */ + depth[idx] = -depth[idx]; + fac = ref/L; + variance[idx ] *= fac*fac; + variance[idx + pass_stride] *= fac*fac; + variance[idx+2*pass_stride] *= fac*fac; + } } } out[idx ] = fac*image[idx]; diff --git a/intern/cycles/kernel/filter/filter_transform_sse.h b/intern/cycles/kernel/filter/filter_transform_sse.h index 30dc2969b11..9e65f61664b 100644 --- a/intern/cycles/kernel/filter/filter_transform_sse.h +++ b/intern/cycles/kernel/filter/filter_transform_sse.h @@ -24,7 +24,7 @@ ccl_device void kernel_filter_construct_transform(const float *ccl_restrict buff { int buffer_w = align_up(rect.z - rect.x, 4); - __m128 features[DENOISE_FEATURES]; + float4 features[DENOISE_FEATURES]; const float *ccl_restrict pixel_buffer; int2 pixel; @@ -34,19 +34,19 @@ ccl_device void kernel_filter_construct_transform(const float *ccl_restrict buff min(rect.w, y + radius + 1)); int num_pixels = (high.y - low.y) * (high.x - low.x); - __m128 feature_means[DENOISE_FEATURES]; + float4 feature_means[DENOISE_FEATURES]; math_vector_zero_sse(feature_means, DENOISE_FEATURES); FOR_PIXEL_WINDOW_SSE { filter_get_features_sse(x4, y4, active_pixels, pixel_buffer, features, NULL, pass_stride); math_vector_add_sse(feature_means, DENOISE_FEATURES, features); } END_FOR_PIXEL_WINDOW_SSE - __m128 pixel_scale = _mm_set1_ps(1.0f / num_pixels); + float4 pixel_scale = make_float4(1.0f / num_pixels); for(int i = 0; i < DENOISE_FEATURES; i++) { - feature_means[i] = _mm_mul_ps(_mm_hsum_ps(feature_means[i]), pixel_scale); + feature_means[i] = reduce_add(feature_means[i]) * pixel_scale; } - __m128 feature_scale[DENOISE_FEATURES]; + float4 feature_scale[DENOISE_FEATURES]; math_vector_zero_sse(feature_scale, DENOISE_FEATURES); FOR_PIXEL_WINDOW_SSE { filter_get_feature_scales_sse(x4, y4, active_pixels, pixel_buffer, features, feature_means, pass_stride); @@ -55,12 +55,12 @@ ccl_device void kernel_filter_construct_transform(const float *ccl_restrict buff filter_calculate_scale_sse(feature_scale); - __m128 feature_matrix_sse[DENOISE_FEATURES*DENOISE_FEATURES]; + float4 feature_matrix_sse[DENOISE_FEATURES*DENOISE_FEATURES]; math_matrix_zero_sse(feature_matrix_sse, DENOISE_FEATURES); FOR_PIXEL_WINDOW_SSE { filter_get_features_sse(x4, y4, active_pixels, pixel_buffer, features, feature_means, pass_stride); math_vector_mul_sse(features, DENOISE_FEATURES, feature_scale); - math_matrix_add_gramian_sse(feature_matrix_sse, DENOISE_FEATURES, features, _mm_set1_ps(1.0f)); + math_matrix_add_gramian_sse(feature_matrix_sse, DENOISE_FEATURES, features, make_float4(1.0f)); } END_FOR_PIXEL_WINDOW_SSE float feature_matrix[DENOISE_FEATURES*DENOISE_FEATURES]; @@ -98,7 +98,7 @@ ccl_device void kernel_filter_construct_transform(const float *ccl_restrict buff /* Bake the feature scaling into the transformation matrix. */ for(int i = 0; i < DENOISE_FEATURES; i++) { - math_vector_scale(transform + i*DENOISE_FEATURES, _mm_cvtss_f32(feature_scale[i]), *rank); + math_vector_scale(transform + i*DENOISE_FEATURES, feature_scale[i][0], *rank); } } diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h index c623e3490fd..f34b77ebc07 100644 --- a/intern/cycles/kernel/geom/geom.h +++ b/intern/cycles/kernel/geom/geom.h @@ -27,6 +27,7 @@ #include "kernel/geom/geom_motion_triangle_shader.h" #include "kernel/geom/geom_motion_curve.h" #include "kernel/geom/geom_curve.h" +#include "kernel/geom/geom_curve_intersect.h" #include "kernel/geom/geom_volume.h" #include "kernel/geom/geom_primitive.h" diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h index 5c3b0ee3c15..e35267f02bf 100644 --- a/intern/cycles/kernel/geom/geom_curve.h +++ b/intern/cycles/kernel/geom/geom_curve.h @@ -16,18 +16,13 @@ CCL_NAMESPACE_BEGIN /* Curve Primitive * - * Curve primitive for rendering hair and fur. These can be render as flat ribbons - * or curves with actual thickness. The curve can also be rendered as line segments - * rather than curves for better performance */ + * Curve primitive for rendering hair and fur. These can be render as flat + * ribbons or curves with actual thickness. The curve can also be rendered as + * line segments rather than curves for better performance. + */ #ifdef __HAIR__ -#if defined(__KERNEL_CUDA__) && (__CUDA_ARCH__ < 300) -# define ccl_device_curveintersect ccl_device -#else -# define ccl_device_curveintersect ccl_device_forceinline -#endif - /* Reading attributes on various curve elements */ ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy) @@ -151,7 +146,7 @@ ccl_device float3 curve_motion_center_location(KernelGlobals *kg, ShaderData *sd /* Curve tangent normal */ ccl_device float3 curve_tangent_normal(KernelGlobals *kg, ShaderData *sd) -{ +{ float3 tgN = make_float3(0.0f,0.0f,0.0f); if(sd->type & PRIMITIVE_ALL_CURVE) { @@ -219,893 +214,6 @@ ccl_device_inline void curvebounds(float *lower, float *upper, float *extremta, } } -#ifdef __KERNEL_SSE2__ -ccl_device_inline ssef transform_point_T3(const ssef t[3], const ssef &a) -{ - return madd(shuffle<0>(a), t[0], madd(shuffle<1>(a), t[1], shuffle<2>(a) * t[2])); -} -#endif - -#ifdef __KERNEL_SSE2__ -/* Pass P and dir by reference to aligned vector */ -ccl_device_curveintersect bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersection *isect, - const float3 &P, const float3 &dir, uint visibility, int object, int curveAddr, float time, int type, uint *lcg_state, float difl, float extmax) -#else -ccl_device_curveintersect bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersection *isect, - float3 P, float3 dir, uint visibility, int object, int curveAddr, float time,int type, uint *lcg_state, float difl, float extmax) -#endif -{ - const bool is_curve_primitive = (type & PRIMITIVE_CURVE); - - if(!is_curve_primitive && kernel_data.bvh.use_bvh_steps) { - const float2 prim_time = kernel_tex_fetch(__prim_time, curveAddr); - if(time < prim_time.x || time > prim_time.y) { - return false; - } - } - - int segment = PRIMITIVE_UNPACK_SEGMENT(type); - float epsilon = 0.0f; - float r_st, r_en; - - int depth = kernel_data.curve.subdivisions; - int flags = kernel_data.curve.curveflags; - int prim = kernel_tex_fetch(__prim_index, curveAddr); - -#ifdef __KERNEL_SSE2__ - ssef vdir = load4f(dir); - ssef vcurve_coef[4]; - const float3 *curve_coef = (float3 *)vcurve_coef; - - { - ssef dtmp = vdir * vdir; - ssef d_ss = mm_sqrt(dtmp + shuffle<2>(dtmp)); - ssef rd_ss = load1f_first(1.0f) / d_ss; - - ssei v00vec = load4i((ssei *)&kg->__curves.data[prim]); - int2 &v00 = (int2 &)v00vec; - - int k0 = v00.x + segment; - int k1 = k0 + 1; - int ka = max(k0 - 1, v00.x); - int kb = min(k1 + 1, v00.x + v00.y - 1); - -#if defined(__KERNEL_AVX2__) && defined(__KERNEL_SSE__) && (!defined(_MSC_VER) || _MSC_VER > 1800) - avxf P_curve_0_1, P_curve_2_3; - if(is_curve_primitive) { - P_curve_0_1 = _mm256_loadu2_m128(&kg->__curve_keys.data[k0].x, &kg->__curve_keys.data[ka].x); - P_curve_2_3 = _mm256_loadu2_m128(&kg->__curve_keys.data[kb].x, &kg->__curve_keys.data[k1].x); - } - else { - int fobject = (object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, curveAddr) : object; - motion_cardinal_curve_keys_avx(kg, fobject, prim, time, ka, k0, k1, kb, &P_curve_0_1,&P_curve_2_3); - } -#else /* __KERNEL_AVX2__ */ - ssef P_curve[4]; - - if(is_curve_primitive) { - P_curve[0] = load4f(&kg->__curve_keys.data[ka].x); - P_curve[1] = load4f(&kg->__curve_keys.data[k0].x); - P_curve[2] = load4f(&kg->__curve_keys.data[k1].x); - P_curve[3] = load4f(&kg->__curve_keys.data[kb].x); - } - else { - int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, curveAddr): object; - motion_cardinal_curve_keys(kg, fobject, prim, time, ka, k0, k1, kb, (float4*)&P_curve); - } -#endif /* __KERNEL_AVX2__ */ - - ssef rd_sgn = set_sign_bit<0, 1, 1, 1>(shuffle<0>(rd_ss)); - ssef mul_zxxy = shuffle<2, 0, 0, 1>(vdir) * rd_sgn; - ssef mul_yz = shuffle<1, 2, 1, 2>(vdir) * mul_zxxy; - ssef mul_shuf = shuffle<0, 1, 2, 3>(mul_zxxy, mul_yz); - ssef vdir0 = vdir & cast(ssei(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0)); - - ssef htfm0 = shuffle<0, 2, 0, 3>(mul_shuf, vdir0); - ssef htfm1 = shuffle<1, 0, 1, 3>(load1f_first(extract<0>(d_ss)), vdir0); - ssef htfm2 = shuffle<1, 3, 2, 3>(mul_shuf, vdir0); - -#if defined(__KERNEL_AVX2__) && defined(__KERNEL_SSE__) && (!defined(_MSC_VER) || _MSC_VER > 1800) - const avxf vPP = _mm256_broadcast_ps(&P.m128); - const avxf htfm00 = avxf(htfm0.m128, htfm0.m128); - const avxf htfm11 = avxf(htfm1.m128, htfm1.m128); - const avxf htfm22 = avxf(htfm2.m128, htfm2.m128); - - const avxf p01 = madd(shuffle<0>(P_curve_0_1 - vPP), - htfm00, - madd(shuffle<1>(P_curve_0_1 - vPP), - htfm11, - shuffle<2>(P_curve_0_1 - vPP) * htfm22)); - const avxf p23 = madd(shuffle<0>(P_curve_2_3 - vPP), - htfm00, - madd(shuffle<1>(P_curve_2_3 - vPP), - htfm11, - shuffle<2>(P_curve_2_3 - vPP)*htfm22)); - - const ssef p0 = _mm256_castps256_ps128(p01); - const ssef p1 = _mm256_extractf128_ps(p01, 1); - const ssef p2 = _mm256_castps256_ps128(p23); - const ssef p3 = _mm256_extractf128_ps(p23, 1); - - const ssef P_curve_1 = _mm256_extractf128_ps(P_curve_0_1, 1); - r_st = ((float4 &)P_curve_1).w; - const ssef P_curve_2 = _mm256_castps256_ps128(P_curve_2_3); - r_en = ((float4 &)P_curve_2).w; -#else /* __KERNEL_AVX2__ */ - ssef htfm[] = { htfm0, htfm1, htfm2 }; - ssef vP = load4f(P); - ssef p0 = transform_point_T3(htfm, P_curve[0] - vP); - ssef p1 = transform_point_T3(htfm, P_curve[1] - vP); - ssef p2 = transform_point_T3(htfm, P_curve[2] - vP); - ssef p3 = transform_point_T3(htfm, P_curve[3] - vP); - - r_st = ((float4 &)P_curve[1]).w; - r_en = ((float4 &)P_curve[2]).w; -#endif /* __KERNEL_AVX2__ */ - - float fc = 0.71f; - ssef vfc = ssef(fc); - ssef vfcxp3 = vfc * p3; - - vcurve_coef[0] = p1; - vcurve_coef[1] = vfc * (p2 - p0); - vcurve_coef[2] = madd(ssef(fc * 2.0f), p0, madd(ssef(fc - 3.0f), p1, msub(ssef(3.0f - 2.0f * fc), p2, vfcxp3))); - vcurve_coef[3] = msub(ssef(fc - 2.0f), p2 - p1, msub(vfc, p0, vfcxp3)); - - } -#else - float3 curve_coef[4]; - - /* curve Intersection check */ - /* obtain curve parameters */ - { - /* ray transform created - this should be created at beginning of intersection loop */ - Transform htfm; - float d = sqrtf(dir.x * dir.x + dir.z * dir.z); - htfm = make_transform( - dir.z / d, 0, -dir.x /d, 0, - -dir.x * dir.y /d, d, -dir.y * dir.z /d, 0, - dir.x, dir.y, dir.z, 0, - 0, 0, 0, 1); - - float4 v00 = kernel_tex_fetch(__curves, prim); - - int k0 = __float_as_int(v00.x) + segment; - int k1 = k0 + 1; - - int ka = max(k0 - 1,__float_as_int(v00.x)); - int kb = min(k1 + 1,__float_as_int(v00.x) + __float_as_int(v00.y) - 1); - - float4 P_curve[4]; - - if(is_curve_primitive) { - P_curve[0] = kernel_tex_fetch(__curve_keys, ka); - P_curve[1] = kernel_tex_fetch(__curve_keys, k0); - P_curve[2] = kernel_tex_fetch(__curve_keys, k1); - P_curve[3] = kernel_tex_fetch(__curve_keys, kb); - } - else { - int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, curveAddr): object; - motion_cardinal_curve_keys(kg, fobject, prim, time, ka, k0, k1, kb, P_curve); - } - - float3 p0 = transform_point(&htfm, float4_to_float3(P_curve[0]) - P); - float3 p1 = transform_point(&htfm, float4_to_float3(P_curve[1]) - P); - float3 p2 = transform_point(&htfm, float4_to_float3(P_curve[2]) - P); - float3 p3 = transform_point(&htfm, float4_to_float3(P_curve[3]) - P); - - float fc = 0.71f; - curve_coef[0] = p1; - curve_coef[1] = -fc*p0 + fc*p2; - curve_coef[2] = 2.0f * fc * p0 + (fc - 3.0f) * p1 + (3.0f - 2.0f * fc) * p2 - fc * p3; - curve_coef[3] = -fc * p0 + (2.0f - fc) * p1 + (fc - 2.0f) * p2 + fc * p3; - r_st = P_curve[1].w; - r_en = P_curve[2].w; - } -#endif - - float r_curr = max(r_st, r_en); - - if((flags & CURVE_KN_RIBBONS) || !(flags & CURVE_KN_BACKFACING)) - epsilon = 2 * r_curr; - - /* find bounds - this is slow for cubic curves */ - float upper, lower; - - float zextrem[4]; - curvebounds(&lower, &upper, &zextrem[0], &zextrem[1], &zextrem[2], &zextrem[3], curve_coef[0].z, curve_coef[1].z, curve_coef[2].z, curve_coef[3].z); - if(lower - r_curr > isect->t || upper + r_curr < epsilon) - return false; - - /* minimum width extension */ - float mw_extension = min(difl * fabsf(upper), extmax); - float r_ext = mw_extension + r_curr; - - float xextrem[4]; - curvebounds(&lower, &upper, &xextrem[0], &xextrem[1], &xextrem[2], &xextrem[3], curve_coef[0].x, curve_coef[1].x, curve_coef[2].x, curve_coef[3].x); - if(lower > r_ext || upper < -r_ext) - return false; - - float yextrem[4]; - curvebounds(&lower, &upper, &yextrem[0], &yextrem[1], &yextrem[2], &yextrem[3], curve_coef[0].y, curve_coef[1].y, curve_coef[2].y, curve_coef[3].y); - if(lower > r_ext || upper < -r_ext) - return false; - - /* setup recurrent loop */ - int level = 1 << depth; - int tree = 0; - float resol = 1.0f / (float)level; - bool hit = false; - - /* begin loop */ - while(!(tree >> (depth))) { - const float i_st = tree * resol; - const float i_en = i_st + (level * resol); - -#ifdef __KERNEL_SSE2__ - ssef vi_st = ssef(i_st), vi_en = ssef(i_en); - ssef vp_st = madd(madd(madd(vcurve_coef[3], vi_st, vcurve_coef[2]), vi_st, vcurve_coef[1]), vi_st, vcurve_coef[0]); - ssef vp_en = madd(madd(madd(vcurve_coef[3], vi_en, vcurve_coef[2]), vi_en, vcurve_coef[1]), vi_en, vcurve_coef[0]); - - ssef vbmin = min(vp_st, vp_en); - ssef vbmax = max(vp_st, vp_en); - - float3 &bmin = (float3 &)vbmin, &bmax = (float3 &)vbmax; - float &bminx = bmin.x, &bminy = bmin.y, &bminz = bmin.z; - float &bmaxx = bmax.x, &bmaxy = bmax.y, &bmaxz = bmax.z; - float3 &p_st = (float3 &)vp_st, &p_en = (float3 &)vp_en; -#else - float3 p_st = ((curve_coef[3] * i_st + curve_coef[2]) * i_st + curve_coef[1]) * i_st + curve_coef[0]; - float3 p_en = ((curve_coef[3] * i_en + curve_coef[2]) * i_en + curve_coef[1]) * i_en + curve_coef[0]; - - float bminx = min(p_st.x, p_en.x); - float bmaxx = max(p_st.x, p_en.x); - float bminy = min(p_st.y, p_en.y); - float bmaxy = max(p_st.y, p_en.y); - float bminz = min(p_st.z, p_en.z); - float bmaxz = max(p_st.z, p_en.z); -#endif - - if(xextrem[0] >= i_st && xextrem[0] <= i_en) { - bminx = min(bminx,xextrem[1]); - bmaxx = max(bmaxx,xextrem[1]); - } - if(xextrem[2] >= i_st && xextrem[2] <= i_en) { - bminx = min(bminx,xextrem[3]); - bmaxx = max(bmaxx,xextrem[3]); - } - if(yextrem[0] >= i_st && yextrem[0] <= i_en) { - bminy = min(bminy,yextrem[1]); - bmaxy = max(bmaxy,yextrem[1]); - } - if(yextrem[2] >= i_st && yextrem[2] <= i_en) { - bminy = min(bminy,yextrem[3]); - bmaxy = max(bmaxy,yextrem[3]); - } - if(zextrem[0] >= i_st && zextrem[0] <= i_en) { - bminz = min(bminz,zextrem[1]); - bmaxz = max(bmaxz,zextrem[1]); - } - if(zextrem[2] >= i_st && zextrem[2] <= i_en) { - bminz = min(bminz,zextrem[3]); - bmaxz = max(bmaxz,zextrem[3]); - } - - float r1 = r_st + (r_en - r_st) * i_st; - float r2 = r_st + (r_en - r_st) * i_en; - r_curr = max(r1, r2); - - mw_extension = min(difl * fabsf(bmaxz), extmax); - float r_ext = mw_extension + r_curr; - float coverage = 1.0f; - - if(bminz - r_curr > isect->t || bmaxz + r_curr < epsilon || bminx > r_ext|| bmaxx < -r_ext|| bminy > r_ext|| bmaxy < -r_ext) { - /* the bounding box does not overlap the square centered at O */ - tree += level; - level = tree & -tree; - } - else if(level == 1) { - - /* the maximum recursion depth is reached. - * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0. - * dP* is reversed if necessary.*/ - float t = isect->t; - float u = 0.0f; - float gd = 0.0f; - - if(flags & CURVE_KN_RIBBONS) { - float3 tg = (p_en - p_st); -#ifdef __KERNEL_SSE__ - const float3 tg_sq = tg * tg; - float w = tg_sq.x + tg_sq.y; -#else - float w = tg.x * tg.x + tg.y * tg.y; -#endif - if(w == 0) { - tree++; - level = tree & -tree; - continue; - } -#ifdef __KERNEL_SSE__ - const float3 p_sttg = p_st * tg; - w = -(p_sttg.x + p_sttg.y) / w; -#else - w = -(p_st.x * tg.x + p_st.y * tg.y) / w; -#endif - w = saturate(w); - - /* compute u on the curve segment */ - u = i_st * (1 - w) + i_en * w; - r_curr = r_st + (r_en - r_st) * u; - /* compare x-y distances */ - float3 p_curr = ((curve_coef[3] * u + curve_coef[2]) * u + curve_coef[1]) * u + curve_coef[0]; - - float3 dp_st = (3 * curve_coef[3] * i_st + 2 * curve_coef[2]) * i_st + curve_coef[1]; - if(dot(tg, dp_st)< 0) - dp_st *= -1; - if(dot(dp_st, -p_st) + p_curr.z * dp_st.z < 0) { - tree++; - level = tree & -tree; - continue; - } - float3 dp_en = (3 * curve_coef[3] * i_en + 2 * curve_coef[2]) * i_en + curve_coef[1]; - if(dot(tg, dp_en) < 0) - dp_en *= -1; - if(dot(dp_en, p_en) - p_curr.z * dp_en.z < 0) { - tree++; - level = tree & -tree; - continue; - } - - /* compute coverage */ - float r_ext = r_curr; - coverage = 1.0f; - if(difl != 0.0f) { - mw_extension = min(difl * fabsf(bmaxz), extmax); - r_ext = mw_extension + r_curr; -#ifdef __KERNEL_SSE__ - const float3 p_curr_sq = p_curr * p_curr; - const float3 dxxx(_mm_sqrt_ss(_mm_hadd_ps(p_curr_sq.m128, p_curr_sq.m128))); - float d = dxxx.x; -#else - float d = sqrtf(p_curr.x * p_curr.x + p_curr.y * p_curr.y); -#endif - float d0 = d - r_curr; - float d1 = d + r_curr; - float inv_mw_extension = 1.0f/mw_extension; - if(d0 >= 0) - coverage = (min(d1 * inv_mw_extension, 1.0f) - min(d0 * inv_mw_extension, 1.0f)) * 0.5f; - else // inside - coverage = (min(d1 * inv_mw_extension, 1.0f) + min(-d0 * inv_mw_extension, 1.0f)) * 0.5f; - } - - if(p_curr.x * p_curr.x + p_curr.y * p_curr.y >= r_ext * r_ext || p_curr.z <= epsilon || isect->t < p_curr.z) { - tree++; - level = tree & -tree; - continue; - } - - t = p_curr.z; - - /* stochastic fade from minimum width */ - if(difl != 0.0f && lcg_state) { - if(coverage != 1.0f && (lcg_step_float(lcg_state) > coverage)) - return hit; - } - } - else { - float l = len(p_en - p_st); - /* minimum width extension */ - float or1 = r1; - float or2 = r2; - - if(difl != 0.0f) { - mw_extension = min(len(p_st - P) * difl, extmax); - or1 = r1 < mw_extension ? mw_extension : r1; - mw_extension = min(len(p_en - P) * difl, extmax); - or2 = r2 < mw_extension ? mw_extension : r2; - } - /* --- */ - float invl = 1.0f/l; - float3 tg = (p_en - p_st) * invl; - gd = (or2 - or1) * invl; - float difz = -dot(p_st,tg); - float cyla = 1.0f - (tg.z * tg.z * (1 + gd*gd)); - float invcyla = 1.0f/cyla; - float halfb = (-p_st.z - tg.z*(difz + gd*(difz*gd + or1))); - float tcentre = -halfb*invcyla; - float zcentre = difz + (tg.z * tcentre); - float3 tdif = - p_st; - tdif.z += tcentre; - float tdifz = dot(tdif,tg); - float tb = 2*(tdif.z - tg.z*(tdifz + gd*(tdifz*gd + or1))); - float tc = dot(tdif,tdif) - tdifz * tdifz * (1 + gd*gd) - or1*or1 - 2*or1*tdifz*gd; - float td = tb*tb - 4*cyla*tc; - if(td < 0.0f) { - tree++; - level = tree & -tree; - continue; - } - - float rootd = sqrtf(td); - float correction = (-tb - rootd) * 0.5f * invcyla; - t = tcentre + correction; - - float3 dp_st = (3 * curve_coef[3] * i_st + 2 * curve_coef[2]) * i_st + curve_coef[1]; - if(dot(tg, dp_st)< 0) - dp_st *= -1; - float3 dp_en = (3 * curve_coef[3] * i_en + 2 * curve_coef[2]) * i_en + curve_coef[1]; - if(dot(tg, dp_en) < 0) - dp_en *= -1; - - if(flags & CURVE_KN_BACKFACING && (dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 || isect->t < t || t <= 0.0f)) { - correction = (-tb + rootd) * 0.5f * invcyla; - t = tcentre + correction; - } - - if(dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 || isect->t < t || t <= 0.0f) { - tree++; - level = tree & -tree; - continue; - } - - float w = (zcentre + (tg.z * correction)) * invl; - w = saturate(w); - /* compute u on the curve segment */ - u = i_st * (1 - w) + i_en * w; - - /* stochastic fade from minimum width */ - if(difl != 0.0f && lcg_state) { - r_curr = r1 + (r2 - r1) * w; - r_ext = or1 + (or2 - or1) * w; - coverage = r_curr/r_ext; - - if(coverage != 1.0f && (lcg_step_float(lcg_state) > coverage)) - return hit; - } - } - /* we found a new intersection */ - -#ifdef __VISIBILITY_FLAG__ - /* visibility flag test. we do it here under the assumption - * that most triangles are culled by node flags */ - if(kernel_tex_fetch(__prim_visibility, curveAddr) & visibility) -#endif - { - /* record intersection */ - isect->t = t; - isect->u = u; - isect->v = gd; - isect->prim = curveAddr; - isect->object = object; - isect->type = type; - hit = true; - } - - tree++; - level = tree & -tree; - } - else { - /* split the curve into two curves and process */ - level = level >> 1; - } - } - - return hit; -} - -ccl_device_curveintersect bool bvh_curve_intersect(KernelGlobals *kg, Intersection *isect, - float3 P, float3 direction, uint visibility, int object, int curveAddr, float time, int type, uint *lcg_state, float difl, float extmax) -{ - /* define few macros to minimize code duplication for SSE */ -#ifndef __KERNEL_SSE2__ -# define len3_squared(x) len_squared(x) -# define len3(x) len(x) -# define dot3(x, y) dot(x, y) -#endif - - const bool is_curve_primitive = (type & PRIMITIVE_CURVE); - - if(!is_curve_primitive && kernel_data.bvh.use_bvh_steps) { - const float2 prim_time = kernel_tex_fetch(__prim_time, curveAddr); - if(time < prim_time.x || time > prim_time.y) { - return false; - } - } - - int segment = PRIMITIVE_UNPACK_SEGMENT(type); - /* curve Intersection check */ - int flags = kernel_data.curve.curveflags; - - int prim = kernel_tex_fetch(__prim_index, curveAddr); - float4 v00 = kernel_tex_fetch(__curves, prim); - - int cnum = __float_as_int(v00.x); - int k0 = cnum + segment; - int k1 = k0 + 1; - -#ifndef __KERNEL_SSE2__ - float4 P_curve[2]; - - if(is_curve_primitive) { - P_curve[0] = kernel_tex_fetch(__curve_keys, k0); - P_curve[1] = kernel_tex_fetch(__curve_keys, k1); - } - else { - int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, curveAddr): object; - motion_curve_keys(kg, fobject, prim, time, k0, k1, P_curve); - } - - float or1 = P_curve[0].w; - float or2 = P_curve[1].w; - float3 p1 = float4_to_float3(P_curve[0]); - float3 p2 = float4_to_float3(P_curve[1]); - - /* minimum width extension */ - float r1 = or1; - float r2 = or2; - float3 dif = P - p1; - float3 dif_second = P - p2; - if(difl != 0.0f) { - float pixelsize = min(len3(dif) * difl, extmax); - r1 = or1 < pixelsize ? pixelsize : or1; - pixelsize = min(len3(dif_second) * difl, extmax); - r2 = or2 < pixelsize ? pixelsize : or2; - } - /* --- */ - - float3 p21_diff = p2 - p1; - float3 sphere_dif1 = (dif + dif_second) * 0.5f; - float3 dir = direction; - float sphere_b_tmp = dot3(dir, sphere_dif1); - float3 sphere_dif2 = sphere_dif1 - sphere_b_tmp * dir; -#else - ssef P_curve[2]; - - if(is_curve_primitive) { - P_curve[0] = load4f(&kg->__curve_keys.data[k0].x); - P_curve[1] = load4f(&kg->__curve_keys.data[k1].x); - } - else { - int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, curveAddr): object; - motion_curve_keys(kg, fobject, prim, time, k0, k1, (float4*)&P_curve); - } - - const ssef or12 = shuffle<3, 3, 3, 3>(P_curve[0], P_curve[1]); - - ssef r12 = or12; - const ssef vP = load4f(P); - const ssef dif = vP - P_curve[0]; - const ssef dif_second = vP - P_curve[1]; - if(difl != 0.0f) { - const ssef len1_sq = len3_squared_splat(dif); - const ssef len2_sq = len3_squared_splat(dif_second); - const ssef len12 = mm_sqrt(shuffle<0, 0, 0, 0>(len1_sq, len2_sq)); - const ssef pixelsize12 = min(len12 * difl, ssef(extmax)); - r12 = max(or12, pixelsize12); - } - float or1 = extract<0>(or12), or2 = extract<0>(shuffle<2>(or12)); - float r1 = extract<0>(r12), r2 = extract<0>(shuffle<2>(r12)); - - const ssef p21_diff = P_curve[1] - P_curve[0]; - const ssef sphere_dif1 = (dif + dif_second) * 0.5f; - const ssef dir = load4f(direction); - const ssef sphere_b_tmp = dot3_splat(dir, sphere_dif1); - const ssef sphere_dif2 = nmadd(sphere_b_tmp, dir, sphere_dif1); -#endif - - float mr = max(r1, r2); - float l = len3(p21_diff); - float invl = 1.0f / l; - float sp_r = mr + 0.5f * l; - - float sphere_b = dot3(dir, sphere_dif2); - float sdisc = sphere_b * sphere_b - len3_squared(sphere_dif2) + sp_r * sp_r; - - if(sdisc < 0.0f) - return false; - - /* obtain parameters and test midpoint distance for suitable modes */ -#ifndef __KERNEL_SSE2__ - float3 tg = p21_diff * invl; -#else - const ssef tg = p21_diff * invl; -#endif - float gd = (r2 - r1) * invl; - - float dirz = dot3(dir, tg); - float difz = dot3(dif, tg); - - float a = 1.0f - (dirz*dirz*(1 + gd*gd)); - - float halfb = dot3(dir, dif) - dirz*(difz + gd*(difz*gd + r1)); - - float tcentre = -halfb/a; - float zcentre = difz + (dirz * tcentre); - - if((tcentre > isect->t) && !(flags & CURVE_KN_ACCURATE)) - return false; - if((zcentre < 0 || zcentre > l) && !(flags & CURVE_KN_ACCURATE) && !(flags & CURVE_KN_INTERSECTCORRECTION)) - return false; - - /* test minimum separation */ -#ifndef __KERNEL_SSE2__ - float3 cprod = cross(tg, dir); - float cprod2sq = len3_squared(cross(tg, dif)); -#else - const ssef cprod = cross(tg, dir); - float cprod2sq = len3_squared(cross_zxy(tg, dif)); -#endif - float cprodsq = len3_squared(cprod); - float distscaled = dot3(cprod, dif); - - if(cprodsq == 0) - distscaled = cprod2sq; - else - distscaled = (distscaled*distscaled)/cprodsq; - - if(distscaled > mr*mr) - return false; - - /* calculate true intersection */ -#ifndef __KERNEL_SSE2__ - float3 tdif = dif + tcentre * dir; -#else - const ssef tdif = madd(ssef(tcentre), dir, dif); -#endif - float tdifz = dot3(tdif, tg); - float tdifma = tdifz*gd + r1; - float tb = 2*(dot3(dir, tdif) - dirz*(tdifz + gd*tdifma)); - float tc = dot3(tdif, tdif) - tdifz*tdifz - tdifma*tdifma; - float td = tb*tb - 4*a*tc; - - if(td < 0.0f) - return false; - - float rootd = 0.0f; - float correction = 0.0f; - if(flags & CURVE_KN_ACCURATE) { - rootd = sqrtf(td); - correction = ((-tb - rootd)/(2*a)); - } - - float t = tcentre + correction; - - if(t < isect->t) { - - if(flags & CURVE_KN_INTERSECTCORRECTION) { - rootd = sqrtf(td); - correction = ((-tb - rootd)/(2*a)); - t = tcentre + correction; - } - - float z = zcentre + (dirz * correction); - // bool backface = false; - - if(flags & CURVE_KN_BACKFACING && (t < 0.0f || z < 0 || z > l)) { - // backface = true; - correction = ((-tb + rootd)/(2*a)); - t = tcentre + correction; - z = zcentre + (dirz * correction); - } - - /* stochastic fade from minimum width */ - float adjradius = or1 + z * (or2 - or1) * invl; - adjradius = adjradius / (r1 + z * gd); - if(lcg_state && adjradius != 1.0f) { - if(lcg_step_float(lcg_state) > adjradius) - return false; - } - /* --- */ - - if(t > 0.0f && t < isect->t && z >= 0 && z <= l) { - - if(flags & CURVE_KN_ENCLOSEFILTER) { - float enc_ratio = 1.01f; - if((difz > -r1 * enc_ratio) && (dot3(dif_second, tg) < r2 * enc_ratio)) { - float a2 = 1.0f - (dirz*dirz*(1 + gd*gd*enc_ratio*enc_ratio)); - float c2 = dot3(dif, dif) - difz * difz * (1 + gd*gd*enc_ratio*enc_ratio) - r1*r1*enc_ratio*enc_ratio - 2*r1*difz*gd*enc_ratio; - if(a2*c2 < 0.0f) - return false; - } - } - -#ifdef __VISIBILITY_FLAG__ - /* visibility flag test. we do it here under the assumption - * that most triangles are culled by node flags */ - if(kernel_tex_fetch(__prim_visibility, curveAddr) & visibility) -#endif - { - /* record intersection */ - isect->t = t; - isect->u = z*invl; - isect->v = gd; - isect->prim = curveAddr; - isect->object = object; - isect->type = type; - - return true; - } - } - } - - return false; - -#ifndef __KERNEL_SSE2__ -# undef len3_squared -# undef len3 -# undef dot3 -#endif -} - -ccl_device_inline float3 curvetangent(float t, float3 p0, float3 p1, float3 p2, float3 p3) -{ - float fc = 0.71f; - float data[4]; - float t2 = t * t; - data[0] = -3.0f * fc * t2 + 4.0f * fc * t - fc; - data[1] = 3.0f * (2.0f - fc) * t2 + 2.0f * (fc - 3.0f) * t; - data[2] = 3.0f * (fc - 2.0f) * t2 + 2.0f * (3.0f - 2.0f * fc) * t + fc; - data[3] = 3.0f * fc * t2 - 2.0f * fc * t; - return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3; -} - -ccl_device_inline float3 curvepoint(float t, float3 p0, float3 p1, float3 p2, float3 p3) -{ - float data[4]; - float fc = 0.71f; - float t2 = t * t; - float t3 = t2 * t; - data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t; - data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f; - data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t; - data[3] = fc * t3 - fc * t2; - return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3; -} - -ccl_device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray) -{ - int flag = kernel_data.curve.curveflags; - float t = isect->t; - float3 P = ray->P; - float3 D = ray->D; - - if(isect->object != OBJECT_NONE) { -#ifdef __OBJECT_MOTION__ - Transform tfm = sd->ob_itfm; -#else - Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM); -#endif - - P = transform_point(&tfm, P); - D = transform_direction(&tfm, D*t); - D = normalize_len(D, &t); - } - - int prim = kernel_tex_fetch(__prim_index, isect->prim); - float4 v00 = kernel_tex_fetch(__curves, prim); - - int k0 = __float_as_int(v00.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type); - int k1 = k0 + 1; - - float3 tg; - - if(flag & CURVE_KN_INTERPOLATE) { - int ka = max(k0 - 1,__float_as_int(v00.x)); - int kb = min(k1 + 1,__float_as_int(v00.x) + __float_as_int(v00.y) - 1); - - float4 P_curve[4]; - - if(sd->type & PRIMITIVE_CURVE) { - P_curve[0] = kernel_tex_fetch(__curve_keys, ka); - P_curve[1] = kernel_tex_fetch(__curve_keys, k0); - P_curve[2] = kernel_tex_fetch(__curve_keys, k1); - P_curve[3] = kernel_tex_fetch(__curve_keys, kb); - } - else { - motion_cardinal_curve_keys(kg, sd->object, sd->prim, sd->time, ka, k0, k1, kb, P_curve); - } - - float3 p[4]; - p[0] = float4_to_float3(P_curve[0]); - p[1] = float4_to_float3(P_curve[1]); - p[2] = float4_to_float3(P_curve[2]); - p[3] = float4_to_float3(P_curve[3]); - - P = P + D*t; - -#ifdef __UV__ - sd->u = isect->u; - sd->v = 0.0f; -#endif - - tg = normalize(curvetangent(isect->u, p[0], p[1], p[2], p[3])); - - if(kernel_data.curve.curveflags & CURVE_KN_RIBBONS) { - sd->Ng = normalize(-(D - tg * (dot(tg, D)))); - } - else { - /* direction from inside to surface of curve */ - float3 p_curr = curvepoint(isect->u, p[0], p[1], p[2], p[3]); - sd->Ng = normalize(P - p_curr); - - /* adjustment for changing radius */ - float gd = isect->v; - - if(gd != 0.0f) { - sd->Ng = sd->Ng - gd * tg; - sd->Ng = normalize(sd->Ng); - } - } - - /* todo: sometimes the normal is still so that this is detected as - * backfacing even if cull backfaces is enabled */ - - sd->N = sd->Ng; - } - else { - float4 P_curve[2]; - - if(sd->type & PRIMITIVE_CURVE) { - P_curve[0]= kernel_tex_fetch(__curve_keys, k0); - P_curve[1]= kernel_tex_fetch(__curve_keys, k1); - } - else { - motion_curve_keys(kg, sd->object, sd->prim, sd->time, k0, k1, P_curve); - } - - float l = 1.0f; - tg = normalize_len(float4_to_float3(P_curve[1] - P_curve[0]), &l); - - P = P + D*t; - - float3 dif = P - float4_to_float3(P_curve[0]); - -#ifdef __UV__ - sd->u = dot(dif,tg)/l; - sd->v = 0.0f; -#endif - - if(flag & CURVE_KN_TRUETANGENTGNORMAL) { - sd->Ng = -(D - tg * dot(tg, D)); - sd->Ng = normalize(sd->Ng); - } - else { - float gd = isect->v; - - /* direction from inside to surface of curve */ - sd->Ng = (dif - tg * sd->u * l) / (P_curve[0].w + sd->u * l * gd); - - /* adjustment for changing radius */ - if(gd != 0.0f) { - sd->Ng = sd->Ng - gd * tg; - sd->Ng = normalize(sd->Ng); - } - } - - sd->N = sd->Ng; - } - -#ifdef __DPDU__ - /* dPdu/dPdv */ - sd->dPdu = tg; - sd->dPdv = cross(tg, sd->Ng); -#endif - - if(isect->object != OBJECT_NONE) { -#ifdef __OBJECT_MOTION__ - Transform tfm = sd->ob_tfm; -#else - Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM); -#endif - - P = transform_point(&tfm, P); - } - - return P; -} - -#endif +#endif /* __HAIR__ */ CCL_NAMESPACE_END - diff --git a/intern/cycles/kernel/geom/geom_curve_intersect.h b/intern/cycles/kernel/geom/geom_curve_intersect.h new file mode 100644 index 00000000000..e9a149ea1ab --- /dev/null +++ b/intern/cycles/kernel/geom/geom_curve_intersect.h @@ -0,0 +1,934 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +/* Curve primitive intersection functions. */ + +#ifdef __HAIR__ + +#if defined(__KERNEL_CUDA__) && (__CUDA_ARCH__ < 300) +# define ccl_device_curveintersect ccl_device +#else +# define ccl_device_curveintersect ccl_device_forceinline +#endif + +#ifdef __KERNEL_SSE2__ +ccl_device_inline ssef transform_point_T3(const ssef t[3], const ssef &a) +{ + return madd(shuffle<0>(a), t[0], madd(shuffle<1>(a), t[1], shuffle<2>(a) * t[2])); +} +#endif + +/* On CPU pass P and dir by reference to aligned vector. */ +ccl_device_curveintersect bool cardinal_curve_intersect( + KernelGlobals *kg, + Intersection *isect, + const float3 ccl_ref P, + const float3 ccl_ref dir, + uint visibility, + int object, + int curveAddr, + float time, + int type, + uint *lcg_state, + float difl, + float extmax) +{ + const bool is_curve_primitive = (type & PRIMITIVE_CURVE); + + if(!is_curve_primitive && kernel_data.bvh.use_bvh_steps) { + const float2 prim_time = kernel_tex_fetch(__prim_time, curveAddr); + if(time < prim_time.x || time > prim_time.y) { + return false; + } + } + + int segment = PRIMITIVE_UNPACK_SEGMENT(type); + float epsilon = 0.0f; + float r_st, r_en; + + int depth = kernel_data.curve.subdivisions; + int flags = kernel_data.curve.curveflags; + int prim = kernel_tex_fetch(__prim_index, curveAddr); + +#ifdef __KERNEL_SSE2__ + ssef vdir = load4f(dir); + ssef vcurve_coef[4]; + const float3 *curve_coef = (float3 *)vcurve_coef; + + { + ssef dtmp = vdir * vdir; + ssef d_ss = mm_sqrt(dtmp + shuffle<2>(dtmp)); + ssef rd_ss = load1f_first(1.0f) / d_ss; + + ssei v00vec = load4i((ssei *)&kg->__curves.data[prim]); + int2 &v00 = (int2 &)v00vec; + + int k0 = v00.x + segment; + int k1 = k0 + 1; + int ka = max(k0 - 1, v00.x); + int kb = min(k1 + 1, v00.x + v00.y - 1); + +#if defined(__KERNEL_AVX2__) && defined(__KERNEL_SSE__) && (!defined(_MSC_VER) || _MSC_VER > 1800) + avxf P_curve_0_1, P_curve_2_3; + if(is_curve_primitive) { + P_curve_0_1 = _mm256_loadu2_m128(&kg->__curve_keys.data[k0].x, &kg->__curve_keys.data[ka].x); + P_curve_2_3 = _mm256_loadu2_m128(&kg->__curve_keys.data[kb].x, &kg->__curve_keys.data[k1].x); + } + else { + int fobject = (object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, curveAddr) : object; + motion_cardinal_curve_keys_avx(kg, fobject, prim, time, ka, k0, k1, kb, &P_curve_0_1,&P_curve_2_3); + } +#else /* __KERNEL_AVX2__ */ + ssef P_curve[4]; + + if(is_curve_primitive) { + P_curve[0] = load4f(&kg->__curve_keys.data[ka].x); + P_curve[1] = load4f(&kg->__curve_keys.data[k0].x); + P_curve[2] = load4f(&kg->__curve_keys.data[k1].x); + P_curve[3] = load4f(&kg->__curve_keys.data[kb].x); + } + else { + int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, curveAddr): object; + motion_cardinal_curve_keys(kg, fobject, prim, time, ka, k0, k1, kb, (float4*)&P_curve); + } +#endif /* __KERNEL_AVX2__ */ + + ssef rd_sgn = set_sign_bit<0, 1, 1, 1>(shuffle<0>(rd_ss)); + ssef mul_zxxy = shuffle<2, 0, 0, 1>(vdir) * rd_sgn; + ssef mul_yz = shuffle<1, 2, 1, 2>(vdir) * mul_zxxy; + ssef mul_shuf = shuffle<0, 1, 2, 3>(mul_zxxy, mul_yz); + ssef vdir0 = vdir & cast(ssei(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0)); + + ssef htfm0 = shuffle<0, 2, 0, 3>(mul_shuf, vdir0); + ssef htfm1 = shuffle<1, 0, 1, 3>(load1f_first(extract<0>(d_ss)), vdir0); + ssef htfm2 = shuffle<1, 3, 2, 3>(mul_shuf, vdir0); + +#if defined(__KERNEL_AVX2__) && defined(__KERNEL_SSE__) && (!defined(_MSC_VER) || _MSC_VER > 1800) + const avxf vPP = _mm256_broadcast_ps(&P.m128); + const avxf htfm00 = avxf(htfm0.m128, htfm0.m128); + const avxf htfm11 = avxf(htfm1.m128, htfm1.m128); + const avxf htfm22 = avxf(htfm2.m128, htfm2.m128); + + const avxf p01 = madd(shuffle<0>(P_curve_0_1 - vPP), + htfm00, + madd(shuffle<1>(P_curve_0_1 - vPP), + htfm11, + shuffle<2>(P_curve_0_1 - vPP) * htfm22)); + const avxf p23 = madd(shuffle<0>(P_curve_2_3 - vPP), + htfm00, + madd(shuffle<1>(P_curve_2_3 - vPP), + htfm11, + shuffle<2>(P_curve_2_3 - vPP)*htfm22)); + + const ssef p0 = _mm256_castps256_ps128(p01); + const ssef p1 = _mm256_extractf128_ps(p01, 1); + const ssef p2 = _mm256_castps256_ps128(p23); + const ssef p3 = _mm256_extractf128_ps(p23, 1); + + const ssef P_curve_1 = _mm256_extractf128_ps(P_curve_0_1, 1); + r_st = ((float4 &)P_curve_1).w; + const ssef P_curve_2 = _mm256_castps256_ps128(P_curve_2_3); + r_en = ((float4 &)P_curve_2).w; +#else /* __KERNEL_AVX2__ */ + ssef htfm[] = { htfm0, htfm1, htfm2 }; + ssef vP = load4f(P); + ssef p0 = transform_point_T3(htfm, P_curve[0] - vP); + ssef p1 = transform_point_T3(htfm, P_curve[1] - vP); + ssef p2 = transform_point_T3(htfm, P_curve[2] - vP); + ssef p3 = transform_point_T3(htfm, P_curve[3] - vP); + + r_st = ((float4 &)P_curve[1]).w; + r_en = ((float4 &)P_curve[2]).w; +#endif /* __KERNEL_AVX2__ */ + + float fc = 0.71f; + ssef vfc = ssef(fc); + ssef vfcxp3 = vfc * p3; + + vcurve_coef[0] = p1; + vcurve_coef[1] = vfc * (p2 - p0); + vcurve_coef[2] = madd(ssef(fc * 2.0f), p0, madd(ssef(fc - 3.0f), p1, msub(ssef(3.0f - 2.0f * fc), p2, vfcxp3))); + vcurve_coef[3] = msub(ssef(fc - 2.0f), p2 - p1, msub(vfc, p0, vfcxp3)); + + } +#else + float3 curve_coef[4]; + + /* curve Intersection check */ + /* obtain curve parameters */ + { + /* ray transform created - this should be created at beginning of intersection loop */ + Transform htfm; + float d = sqrtf(dir.x * dir.x + dir.z * dir.z); + htfm = make_transform( + dir.z / d, 0, -dir.x /d, 0, + -dir.x * dir.y /d, d, -dir.y * dir.z /d, 0, + dir.x, dir.y, dir.z, 0, + 0, 0, 0, 1); + + float4 v00 = kernel_tex_fetch(__curves, prim); + + int k0 = __float_as_int(v00.x) + segment; + int k1 = k0 + 1; + + int ka = max(k0 - 1,__float_as_int(v00.x)); + int kb = min(k1 + 1,__float_as_int(v00.x) + __float_as_int(v00.y) - 1); + + float4 P_curve[4]; + + if(is_curve_primitive) { + P_curve[0] = kernel_tex_fetch(__curve_keys, ka); + P_curve[1] = kernel_tex_fetch(__curve_keys, k0); + P_curve[2] = kernel_tex_fetch(__curve_keys, k1); + P_curve[3] = kernel_tex_fetch(__curve_keys, kb); + } + else { + int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, curveAddr): object; + motion_cardinal_curve_keys(kg, fobject, prim, time, ka, k0, k1, kb, P_curve); + } + + float3 p0 = transform_point(&htfm, float4_to_float3(P_curve[0]) - P); + float3 p1 = transform_point(&htfm, float4_to_float3(P_curve[1]) - P); + float3 p2 = transform_point(&htfm, float4_to_float3(P_curve[2]) - P); + float3 p3 = transform_point(&htfm, float4_to_float3(P_curve[3]) - P); + + float fc = 0.71f; + curve_coef[0] = p1; + curve_coef[1] = -fc*p0 + fc*p2; + curve_coef[2] = 2.0f * fc * p0 + (fc - 3.0f) * p1 + (3.0f - 2.0f * fc) * p2 - fc * p3; + curve_coef[3] = -fc * p0 + (2.0f - fc) * p1 + (fc - 2.0f) * p2 + fc * p3; + r_st = P_curve[1].w; + r_en = P_curve[2].w; + } +#endif + + float r_curr = max(r_st, r_en); + + if((flags & CURVE_KN_RIBBONS) || !(flags & CURVE_KN_BACKFACING)) + epsilon = 2 * r_curr; + + /* find bounds - this is slow for cubic curves */ + float upper, lower; + + float zextrem[4]; + curvebounds(&lower, &upper, &zextrem[0], &zextrem[1], &zextrem[2], &zextrem[3], curve_coef[0].z, curve_coef[1].z, curve_coef[2].z, curve_coef[3].z); + if(lower - r_curr > isect->t || upper + r_curr < epsilon) + return false; + + /* minimum width extension */ + float mw_extension = min(difl * fabsf(upper), extmax); + float r_ext = mw_extension + r_curr; + + float xextrem[4]; + curvebounds(&lower, &upper, &xextrem[0], &xextrem[1], &xextrem[2], &xextrem[3], curve_coef[0].x, curve_coef[1].x, curve_coef[2].x, curve_coef[3].x); + if(lower > r_ext || upper < -r_ext) + return false; + + float yextrem[4]; + curvebounds(&lower, &upper, &yextrem[0], &yextrem[1], &yextrem[2], &yextrem[3], curve_coef[0].y, curve_coef[1].y, curve_coef[2].y, curve_coef[3].y); + if(lower > r_ext || upper < -r_ext) + return false; + + /* setup recurrent loop */ + int level = 1 << depth; + int tree = 0; + float resol = 1.0f / (float)level; + bool hit = false; + + /* begin loop */ + while(!(tree >> (depth))) { + const float i_st = tree * resol; + const float i_en = i_st + (level * resol); + +#ifdef __KERNEL_SSE2__ + ssef vi_st = ssef(i_st), vi_en = ssef(i_en); + ssef vp_st = madd(madd(madd(vcurve_coef[3], vi_st, vcurve_coef[2]), vi_st, vcurve_coef[1]), vi_st, vcurve_coef[0]); + ssef vp_en = madd(madd(madd(vcurve_coef[3], vi_en, vcurve_coef[2]), vi_en, vcurve_coef[1]), vi_en, vcurve_coef[0]); + + ssef vbmin = min(vp_st, vp_en); + ssef vbmax = max(vp_st, vp_en); + + float3 &bmin = (float3 &)vbmin, &bmax = (float3 &)vbmax; + float &bminx = bmin.x, &bminy = bmin.y, &bminz = bmin.z; + float &bmaxx = bmax.x, &bmaxy = bmax.y, &bmaxz = bmax.z; + float3 &p_st = (float3 &)vp_st, &p_en = (float3 &)vp_en; +#else + float3 p_st = ((curve_coef[3] * i_st + curve_coef[2]) * i_st + curve_coef[1]) * i_st + curve_coef[0]; + float3 p_en = ((curve_coef[3] * i_en + curve_coef[2]) * i_en + curve_coef[1]) * i_en + curve_coef[0]; + + float bminx = min(p_st.x, p_en.x); + float bmaxx = max(p_st.x, p_en.x); + float bminy = min(p_st.y, p_en.y); + float bmaxy = max(p_st.y, p_en.y); + float bminz = min(p_st.z, p_en.z); + float bmaxz = max(p_st.z, p_en.z); +#endif + + if(xextrem[0] >= i_st && xextrem[0] <= i_en) { + bminx = min(bminx,xextrem[1]); + bmaxx = max(bmaxx,xextrem[1]); + } + if(xextrem[2] >= i_st && xextrem[2] <= i_en) { + bminx = min(bminx,xextrem[3]); + bmaxx = max(bmaxx,xextrem[3]); + } + if(yextrem[0] >= i_st && yextrem[0] <= i_en) { + bminy = min(bminy,yextrem[1]); + bmaxy = max(bmaxy,yextrem[1]); + } + if(yextrem[2] >= i_st && yextrem[2] <= i_en) { + bminy = min(bminy,yextrem[3]); + bmaxy = max(bmaxy,yextrem[3]); + } + if(zextrem[0] >= i_st && zextrem[0] <= i_en) { + bminz = min(bminz,zextrem[1]); + bmaxz = max(bmaxz,zextrem[1]); + } + if(zextrem[2] >= i_st && zextrem[2] <= i_en) { + bminz = min(bminz,zextrem[3]); + bmaxz = max(bmaxz,zextrem[3]); + } + + float r1 = r_st + (r_en - r_st) * i_st; + float r2 = r_st + (r_en - r_st) * i_en; + r_curr = max(r1, r2); + + mw_extension = min(difl * fabsf(bmaxz), extmax); + float r_ext = mw_extension + r_curr; + float coverage = 1.0f; + + if(bminz - r_curr > isect->t || bmaxz + r_curr < epsilon || bminx > r_ext|| bmaxx < -r_ext|| bminy > r_ext|| bmaxy < -r_ext) { + /* the bounding box does not overlap the square centered at O */ + tree += level; + level = tree & -tree; + } + else if(level == 1) { + + /* the maximum recursion depth is reached. + * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0. + * dP* is reversed if necessary.*/ + float t = isect->t; + float u = 0.0f; + float gd = 0.0f; + + if(flags & CURVE_KN_RIBBONS) { + float3 tg = (p_en - p_st); +#ifdef __KERNEL_SSE__ + const float3 tg_sq = tg * tg; + float w = tg_sq.x + tg_sq.y; +#else + float w = tg.x * tg.x + tg.y * tg.y; +#endif + if(w == 0) { + tree++; + level = tree & -tree; + continue; + } +#ifdef __KERNEL_SSE__ + const float3 p_sttg = p_st * tg; + w = -(p_sttg.x + p_sttg.y) / w; +#else + w = -(p_st.x * tg.x + p_st.y * tg.y) / w; +#endif + w = saturate(w); + + /* compute u on the curve segment */ + u = i_st * (1 - w) + i_en * w; + r_curr = r_st + (r_en - r_st) * u; + /* compare x-y distances */ + float3 p_curr = ((curve_coef[3] * u + curve_coef[2]) * u + curve_coef[1]) * u + curve_coef[0]; + + float3 dp_st = (3 * curve_coef[3] * i_st + 2 * curve_coef[2]) * i_st + curve_coef[1]; + if(dot(tg, dp_st)< 0) + dp_st *= -1; + if(dot(dp_st, -p_st) + p_curr.z * dp_st.z < 0) { + tree++; + level = tree & -tree; + continue; + } + float3 dp_en = (3 * curve_coef[3] * i_en + 2 * curve_coef[2]) * i_en + curve_coef[1]; + if(dot(tg, dp_en) < 0) + dp_en *= -1; + if(dot(dp_en, p_en) - p_curr.z * dp_en.z < 0) { + tree++; + level = tree & -tree; + continue; + } + + /* compute coverage */ + float r_ext = r_curr; + coverage = 1.0f; + if(difl != 0.0f) { + mw_extension = min(difl * fabsf(bmaxz), extmax); + r_ext = mw_extension + r_curr; +#ifdef __KERNEL_SSE__ + const float3 p_curr_sq = p_curr * p_curr; + const float3 dxxx(_mm_sqrt_ss(_mm_hadd_ps(p_curr_sq.m128, p_curr_sq.m128))); + float d = dxxx.x; +#else + float d = sqrtf(p_curr.x * p_curr.x + p_curr.y * p_curr.y); +#endif + float d0 = d - r_curr; + float d1 = d + r_curr; + float inv_mw_extension = 1.0f/mw_extension; + if(d0 >= 0) + coverage = (min(d1 * inv_mw_extension, 1.0f) - min(d0 * inv_mw_extension, 1.0f)) * 0.5f; + else // inside + coverage = (min(d1 * inv_mw_extension, 1.0f) + min(-d0 * inv_mw_extension, 1.0f)) * 0.5f; + } + + if(p_curr.x * p_curr.x + p_curr.y * p_curr.y >= r_ext * r_ext || p_curr.z <= epsilon || isect->t < p_curr.z) { + tree++; + level = tree & -tree; + continue; + } + + t = p_curr.z; + + /* stochastic fade from minimum width */ + if(difl != 0.0f && lcg_state) { + if(coverage != 1.0f && (lcg_step_float(lcg_state) > coverage)) + return hit; + } + } + else { + float l = len(p_en - p_st); + /* minimum width extension */ + float or1 = r1; + float or2 = r2; + + if(difl != 0.0f) { + mw_extension = min(len(p_st - P) * difl, extmax); + or1 = r1 < mw_extension ? mw_extension : r1; + mw_extension = min(len(p_en - P) * difl, extmax); + or2 = r2 < mw_extension ? mw_extension : r2; + } + /* --- */ + float invl = 1.0f/l; + float3 tg = (p_en - p_st) * invl; + gd = (or2 - or1) * invl; + float difz = -dot(p_st,tg); + float cyla = 1.0f - (tg.z * tg.z * (1 + gd*gd)); + float invcyla = 1.0f/cyla; + float halfb = (-p_st.z - tg.z*(difz + gd*(difz*gd + or1))); + float tcentre = -halfb*invcyla; + float zcentre = difz + (tg.z * tcentre); + float3 tdif = - p_st; + tdif.z += tcentre; + float tdifz = dot(tdif,tg); + float tb = 2*(tdif.z - tg.z*(tdifz + gd*(tdifz*gd + or1))); + float tc = dot(tdif,tdif) - tdifz * tdifz * (1 + gd*gd) - or1*or1 - 2*or1*tdifz*gd; + float td = tb*tb - 4*cyla*tc; + if(td < 0.0f) { + tree++; + level = tree & -tree; + continue; + } + + float rootd = sqrtf(td); + float correction = (-tb - rootd) * 0.5f * invcyla; + t = tcentre + correction; + + float3 dp_st = (3 * curve_coef[3] * i_st + 2 * curve_coef[2]) * i_st + curve_coef[1]; + if(dot(tg, dp_st)< 0) + dp_st *= -1; + float3 dp_en = (3 * curve_coef[3] * i_en + 2 * curve_coef[2]) * i_en + curve_coef[1]; + if(dot(tg, dp_en) < 0) + dp_en *= -1; + + if(flags & CURVE_KN_BACKFACING && (dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 || isect->t < t || t <= 0.0f)) { + correction = (-tb + rootd) * 0.5f * invcyla; + t = tcentre + correction; + } + + if(dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 || isect->t < t || t <= 0.0f) { + tree++; + level = tree & -tree; + continue; + } + + float w = (zcentre + (tg.z * correction)) * invl; + w = saturate(w); + /* compute u on the curve segment */ + u = i_st * (1 - w) + i_en * w; + + /* stochastic fade from minimum width */ + if(difl != 0.0f && lcg_state) { + r_curr = r1 + (r2 - r1) * w; + r_ext = or1 + (or2 - or1) * w; + coverage = r_curr/r_ext; + + if(coverage != 1.0f && (lcg_step_float(lcg_state) > coverage)) + return hit; + } + } + /* we found a new intersection */ + +#ifdef __VISIBILITY_FLAG__ + /* visibility flag test. we do it here under the assumption + * that most triangles are culled by node flags */ + if(kernel_tex_fetch(__prim_visibility, curveAddr) & visibility) +#endif + { + /* record intersection */ + isect->t = t; + isect->u = u; + isect->v = gd; + isect->prim = curveAddr; + isect->object = object; + isect->type = type; + hit = true; + } + + tree++; + level = tree & -tree; + } + else { + /* split the curve into two curves and process */ + level = level >> 1; + } + } + + return hit; +} + +ccl_device_curveintersect bool curve_intersect(KernelGlobals *kg, + Intersection *isect, + float3 P, + float3 direction, + uint visibility, + int object, + int curveAddr, + float time, + int type, + uint *lcg_state, + float difl, + float extmax) +{ + /* define few macros to minimize code duplication for SSE */ +#ifndef __KERNEL_SSE2__ +# define len3_squared(x) len_squared(x) +# define len3(x) len(x) +# define dot3(x, y) dot(x, y) +#endif + + const bool is_curve_primitive = (type & PRIMITIVE_CURVE); + + if(!is_curve_primitive && kernel_data.bvh.use_bvh_steps) { + const float2 prim_time = kernel_tex_fetch(__prim_time, curveAddr); + if(time < prim_time.x || time > prim_time.y) { + return false; + } + } + + int segment = PRIMITIVE_UNPACK_SEGMENT(type); + /* curve Intersection check */ + int flags = kernel_data.curve.curveflags; + + int prim = kernel_tex_fetch(__prim_index, curveAddr); + float4 v00 = kernel_tex_fetch(__curves, prim); + + int cnum = __float_as_int(v00.x); + int k0 = cnum + segment; + int k1 = k0 + 1; + +#ifndef __KERNEL_SSE2__ + float4 P_curve[2]; + + if(is_curve_primitive) { + P_curve[0] = kernel_tex_fetch(__curve_keys, k0); + P_curve[1] = kernel_tex_fetch(__curve_keys, k1); + } + else { + int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, curveAddr): object; + motion_curve_keys(kg, fobject, prim, time, k0, k1, P_curve); + } + + float or1 = P_curve[0].w; + float or2 = P_curve[1].w; + float3 p1 = float4_to_float3(P_curve[0]); + float3 p2 = float4_to_float3(P_curve[1]); + + /* minimum width extension */ + float r1 = or1; + float r2 = or2; + float3 dif = P - p1; + float3 dif_second = P - p2; + if(difl != 0.0f) { + float pixelsize = min(len3(dif) * difl, extmax); + r1 = or1 < pixelsize ? pixelsize : or1; + pixelsize = min(len3(dif_second) * difl, extmax); + r2 = or2 < pixelsize ? pixelsize : or2; + } + /* --- */ + + float3 p21_diff = p2 - p1; + float3 sphere_dif1 = (dif + dif_second) * 0.5f; + float3 dir = direction; + float sphere_b_tmp = dot3(dir, sphere_dif1); + float3 sphere_dif2 = sphere_dif1 - sphere_b_tmp * dir; +#else + ssef P_curve[2]; + + if(is_curve_primitive) { + P_curve[0] = load4f(&kg->__curve_keys.data[k0].x); + P_curve[1] = load4f(&kg->__curve_keys.data[k1].x); + } + else { + int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, curveAddr): object; + motion_curve_keys(kg, fobject, prim, time, k0, k1, (float4*)&P_curve); + } + + const ssef or12 = shuffle<3, 3, 3, 3>(P_curve[0], P_curve[1]); + + ssef r12 = or12; + const ssef vP = load4f(P); + const ssef dif = vP - P_curve[0]; + const ssef dif_second = vP - P_curve[1]; + if(difl != 0.0f) { + const ssef len1_sq = len3_squared_splat(dif); + const ssef len2_sq = len3_squared_splat(dif_second); + const ssef len12 = mm_sqrt(shuffle<0, 0, 0, 0>(len1_sq, len2_sq)); + const ssef pixelsize12 = min(len12 * difl, ssef(extmax)); + r12 = max(or12, pixelsize12); + } + float or1 = extract<0>(or12), or2 = extract<0>(shuffle<2>(or12)); + float r1 = extract<0>(r12), r2 = extract<0>(shuffle<2>(r12)); + + const ssef p21_diff = P_curve[1] - P_curve[0]; + const ssef sphere_dif1 = (dif + dif_second) * 0.5f; + const ssef dir = load4f(direction); + const ssef sphere_b_tmp = dot3_splat(dir, sphere_dif1); + const ssef sphere_dif2 = nmadd(sphere_b_tmp, dir, sphere_dif1); +#endif + + float mr = max(r1, r2); + float l = len3(p21_diff); + float invl = 1.0f / l; + float sp_r = mr + 0.5f * l; + + float sphere_b = dot3(dir, sphere_dif2); + float sdisc = sphere_b * sphere_b - len3_squared(sphere_dif2) + sp_r * sp_r; + + if(sdisc < 0.0f) + return false; + + /* obtain parameters and test midpoint distance for suitable modes */ +#ifndef __KERNEL_SSE2__ + float3 tg = p21_diff * invl; +#else + const ssef tg = p21_diff * invl; +#endif + float gd = (r2 - r1) * invl; + + float dirz = dot3(dir, tg); + float difz = dot3(dif, tg); + + float a = 1.0f - (dirz*dirz*(1 + gd*gd)); + + float halfb = dot3(dir, dif) - dirz*(difz + gd*(difz*gd + r1)); + + float tcentre = -halfb/a; + float zcentre = difz + (dirz * tcentre); + + if((tcentre > isect->t) && !(flags & CURVE_KN_ACCURATE)) + return false; + if((zcentre < 0 || zcentre > l) && !(flags & CURVE_KN_ACCURATE) && !(flags & CURVE_KN_INTERSECTCORRECTION)) + return false; + + /* test minimum separation */ +#ifndef __KERNEL_SSE2__ + float3 cprod = cross(tg, dir); + float cprod2sq = len3_squared(cross(tg, dif)); +#else + const ssef cprod = cross(tg, dir); + float cprod2sq = len3_squared(cross_zxy(tg, dif)); +#endif + float cprodsq = len3_squared(cprod); + float distscaled = dot3(cprod, dif); + + if(cprodsq == 0) + distscaled = cprod2sq; + else + distscaled = (distscaled*distscaled)/cprodsq; + + if(distscaled > mr*mr) + return false; + + /* calculate true intersection */ +#ifndef __KERNEL_SSE2__ + float3 tdif = dif + tcentre * dir; +#else + const ssef tdif = madd(ssef(tcentre), dir, dif); +#endif + float tdifz = dot3(tdif, tg); + float tdifma = tdifz*gd + r1; + float tb = 2*(dot3(dir, tdif) - dirz*(tdifz + gd*tdifma)); + float tc = dot3(tdif, tdif) - tdifz*tdifz - tdifma*tdifma; + float td = tb*tb - 4*a*tc; + + if(td < 0.0f) + return false; + + float rootd = 0.0f; + float correction = 0.0f; + if(flags & CURVE_KN_ACCURATE) { + rootd = sqrtf(td); + correction = ((-tb - rootd)/(2*a)); + } + + float t = tcentre + correction; + + if(t < isect->t) { + + if(flags & CURVE_KN_INTERSECTCORRECTION) { + rootd = sqrtf(td); + correction = ((-tb - rootd)/(2*a)); + t = tcentre + correction; + } + + float z = zcentre + (dirz * correction); + // bool backface = false; + + if(flags & CURVE_KN_BACKFACING && (t < 0.0f || z < 0 || z > l)) { + // backface = true; + correction = ((-tb + rootd)/(2*a)); + t = tcentre + correction; + z = zcentre + (dirz * correction); + } + + /* stochastic fade from minimum width */ + float adjradius = or1 + z * (or2 - or1) * invl; + adjradius = adjradius / (r1 + z * gd); + if(lcg_state && adjradius != 1.0f) { + if(lcg_step_float(lcg_state) > adjradius) + return false; + } + /* --- */ + + if(t > 0.0f && t < isect->t && z >= 0 && z <= l) { + + if(flags & CURVE_KN_ENCLOSEFILTER) { + float enc_ratio = 1.01f; + if((difz > -r1 * enc_ratio) && (dot3(dif_second, tg) < r2 * enc_ratio)) { + float a2 = 1.0f - (dirz*dirz*(1 + gd*gd*enc_ratio*enc_ratio)); + float c2 = dot3(dif, dif) - difz * difz * (1 + gd*gd*enc_ratio*enc_ratio) - r1*r1*enc_ratio*enc_ratio - 2*r1*difz*gd*enc_ratio; + if(a2*c2 < 0.0f) + return false; + } + } + +#ifdef __VISIBILITY_FLAG__ + /* visibility flag test. we do it here under the assumption + * that most triangles are culled by node flags */ + if(kernel_tex_fetch(__prim_visibility, curveAddr) & visibility) +#endif + { + /* record intersection */ + isect->t = t; + isect->u = z*invl; + isect->v = gd; + isect->prim = curveAddr; + isect->object = object; + isect->type = type; + + return true; + } + } + } + + return false; + +#ifndef __KERNEL_SSE2__ +# undef len3_squared +# undef len3 +# undef dot3 +#endif +} + +ccl_device_inline float3 curvetangent(float t, float3 p0, float3 p1, float3 p2, float3 p3) +{ + float fc = 0.71f; + float data[4]; + float t2 = t * t; + data[0] = -3.0f * fc * t2 + 4.0f * fc * t - fc; + data[1] = 3.0f * (2.0f - fc) * t2 + 2.0f * (fc - 3.0f) * t; + data[2] = 3.0f * (fc - 2.0f) * t2 + 2.0f * (3.0f - 2.0f * fc) * t + fc; + data[3] = 3.0f * fc * t2 - 2.0f * fc * t; + return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3; +} + +ccl_device_inline float3 curvepoint(float t, float3 p0, float3 p1, float3 p2, float3 p3) +{ + float data[4]; + float fc = 0.71f; + float t2 = t * t; + float t3 = t2 * t; + data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t; + data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f; + data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t; + data[3] = fc * t3 - fc * t2; + return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3; +} + +ccl_device_inline float3 curve_refine(KernelGlobals *kg, + ShaderData *sd, + const Intersection *isect, + const Ray *ray) +{ + int flag = kernel_data.curve.curveflags; + float t = isect->t; + float3 P = ray->P; + float3 D = ray->D; + + if(isect->object != OBJECT_NONE) { +#ifdef __OBJECT_MOTION__ + Transform tfm = sd->ob_itfm; +#else + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM); +#endif + + P = transform_point(&tfm, P); + D = transform_direction(&tfm, D*t); + D = normalize_len(D, &t); + } + + int prim = kernel_tex_fetch(__prim_index, isect->prim); + float4 v00 = kernel_tex_fetch(__curves, prim); + + int k0 = __float_as_int(v00.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type); + int k1 = k0 + 1; + + float3 tg; + + if(flag & CURVE_KN_INTERPOLATE) { + int ka = max(k0 - 1,__float_as_int(v00.x)); + int kb = min(k1 + 1,__float_as_int(v00.x) + __float_as_int(v00.y) - 1); + + float4 P_curve[4]; + + if(sd->type & PRIMITIVE_CURVE) { + P_curve[0] = kernel_tex_fetch(__curve_keys, ka); + P_curve[1] = kernel_tex_fetch(__curve_keys, k0); + P_curve[2] = kernel_tex_fetch(__curve_keys, k1); + P_curve[3] = kernel_tex_fetch(__curve_keys, kb); + } + else { + motion_cardinal_curve_keys(kg, sd->object, sd->prim, sd->time, ka, k0, k1, kb, P_curve); + } + + float3 p[4]; + p[0] = float4_to_float3(P_curve[0]); + p[1] = float4_to_float3(P_curve[1]); + p[2] = float4_to_float3(P_curve[2]); + p[3] = float4_to_float3(P_curve[3]); + + P = P + D*t; + +#ifdef __UV__ + sd->u = isect->u; + sd->v = 0.0f; +#endif + + tg = normalize(curvetangent(isect->u, p[0], p[1], p[2], p[3])); + + if(kernel_data.curve.curveflags & CURVE_KN_RIBBONS) { + sd->Ng = normalize(-(D - tg * (dot(tg, D)))); + } + else { + /* direction from inside to surface of curve */ + float3 p_curr = curvepoint(isect->u, p[0], p[1], p[2], p[3]); + sd->Ng = normalize(P - p_curr); + + /* adjustment for changing radius */ + float gd = isect->v; + + if(gd != 0.0f) { + sd->Ng = sd->Ng - gd * tg; + sd->Ng = normalize(sd->Ng); + } + } + + /* todo: sometimes the normal is still so that this is detected as + * backfacing even if cull backfaces is enabled */ + + sd->N = sd->Ng; + } + else { + float4 P_curve[2]; + + if(sd->type & PRIMITIVE_CURVE) { + P_curve[0]= kernel_tex_fetch(__curve_keys, k0); + P_curve[1]= kernel_tex_fetch(__curve_keys, k1); + } + else { + motion_curve_keys(kg, sd->object, sd->prim, sd->time, k0, k1, P_curve); + } + + float l = 1.0f; + tg = normalize_len(float4_to_float3(P_curve[1] - P_curve[0]), &l); + + P = P + D*t; + + float3 dif = P - float4_to_float3(P_curve[0]); + +#ifdef __UV__ + sd->u = dot(dif,tg)/l; + sd->v = 0.0f; +#endif + + if(flag & CURVE_KN_TRUETANGENTGNORMAL) { + sd->Ng = -(D - tg * dot(tg, D)); + sd->Ng = normalize(sd->Ng); + } + else { + float gd = isect->v; + + /* direction from inside to surface of curve */ + sd->Ng = (dif - tg * sd->u * l) / (P_curve[0].w + sd->u * l * gd); + + /* adjustment for changing radius */ + if(gd != 0.0f) { + sd->Ng = sd->Ng - gd * tg; + sd->Ng = normalize(sd->Ng); + } + } + + sd->N = sd->Ng; + } + +#ifdef __DPDU__ + /* dPdu/dPdv */ + sd->dPdu = tg; + sd->dPdv = cross(tg, sd->Ng); +#endif + + if(isect->object != OBJECT_NONE) { +#ifdef __OBJECT_MOTION__ + Transform tfm = sd->ob_tfm; +#else + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM); +#endif + + P = transform_point(&tfm, P); + } + + return P; +} + +#endif + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h index 6ecdfe0173a..1ffc143be34 100644 --- a/intern/cycles/kernel/geom/geom_object.h +++ b/intern/cycles/kernel/geom/geom_object.h @@ -415,12 +415,7 @@ ccl_device_inline float3 bvh_clamp_direction(float3 dir) ccl_device_inline float3 bvh_inverse_direction(float3 dir) { - /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */ -#if defined(__KERNEL_SSE__) && 0 return rcp(dir); -#else - return 1.0f / dir; -#endif } /* Transform ray into object space to enter static object in BVH */ diff --git a/intern/cycles/kernel/geom/geom_volume.h b/intern/cycles/kernel/geom/geom_volume.h index 1e0ef5201c9..698cd6b03fd 100644 --- a/intern/cycles/kernel/geom/geom_volume.h +++ b/intern/cycles/kernel/geom/geom_volume.h @@ -35,10 +35,10 @@ ccl_device float4 volume_image_texture_3d(int id, float x, float y, float z) float4 r; switch(id) { case 0: r = kernel_tex_image_interp_3d(__tex_image_float4_3d_000, x, y, z); break; - case 1: r = kernel_tex_image_interp_3d(__tex_image_float4_3d_001, x, y, z); break; - case 2: r = kernel_tex_image_interp_3d(__tex_image_float4_3d_002, x, y, z); break; - case 3: r = kernel_tex_image_interp_3d(__tex_image_float4_3d_003, x, y, z); break; - case 4: r = kernel_tex_image_interp_3d(__tex_image_float4_3d_004, x, y, z); break; + case 8: r = kernel_tex_image_interp_3d(__tex_image_float4_3d_008, x, y, z); break; + case 16: r = kernel_tex_image_interp_3d(__tex_image_float4_3d_016, x, y, z); break; + case 24: r = kernel_tex_image_interp_3d(__tex_image_float4_3d_024, x, y, z); break; + case 32: r = kernel_tex_image_interp_3d(__tex_image_float4_3d_032, x, y, z); break; } return r; } diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h index 175bd6b9737..ae5f6e5e070 100644 --- a/intern/cycles/kernel/kernel_accumulate.h +++ b/intern/cycles/kernel/kernel_accumulate.h @@ -21,6 +21,9 @@ CCL_NAMESPACE_BEGIN * BSDF evaluation result, split per BSDF type. This is used to accumulate * render passes separately. */ +ccl_device float3 shader_bsdf_transparency(KernelGlobals *kg, + const ShaderData *sd); + ccl_device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 value, int use_light_pass) { #ifdef __PASSES__ @@ -178,7 +181,6 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass) if(use_light_pass) { L->indirect = make_float3(0.0f, 0.0f, 0.0f); - L->direct_throughput = make_float3(0.0f, 0.0f, 0.0f); L->direct_emission = make_float3(0.0f, 0.0f, 0.0f); L->color_diffuse = make_float3(0.0f, 0.0f, 0.0f); @@ -199,57 +201,78 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass) L->indirect_subsurface = make_float3(0.0f, 0.0f, 0.0f); L->indirect_scatter = make_float3(0.0f, 0.0f, 0.0f); - L->path_diffuse = make_float3(0.0f, 0.0f, 0.0f); - L->path_glossy = make_float3(0.0f, 0.0f, 0.0f); - L->path_transmission = make_float3(0.0f, 0.0f, 0.0f); - L->path_subsurface = make_float3(0.0f, 0.0f, 0.0f); - L->path_scatter = make_float3(0.0f, 0.0f, 0.0f); - + L->transparent = 0.0f; L->emission = make_float3(0.0f, 0.0f, 0.0f); L->background = make_float3(0.0f, 0.0f, 0.0f); L->ao = make_float3(0.0f, 0.0f, 0.0f); L->shadow = make_float4(0.0f, 0.0f, 0.0f, 0.0f); L->mist = 0.0f; + + L->state.diffuse = make_float3(0.0f, 0.0f, 0.0f); + L->state.glossy = make_float3(0.0f, 0.0f, 0.0f); + L->state.transmission = make_float3(0.0f, 0.0f, 0.0f); + L->state.subsurface = make_float3(0.0f, 0.0f, 0.0f); + L->state.scatter = make_float3(0.0f, 0.0f, 0.0f); + L->state.direct = make_float3(0.0f, 0.0f, 0.0f); } else #endif { + L->transparent = 0.0f; L->emission = make_float3(0.0f, 0.0f, 0.0f); } #ifdef __SHADOW_TRICKS__ L->path_total = make_float3(0.0f, 0.0f, 0.0f); L->path_total_shaded = make_float3(0.0f, 0.0f, 0.0f); - L->shadow_color = make_float3(0.0f, 0.0f, 0.0f); + L->shadow_background_color = make_float3(0.0f, 0.0f, 0.0f); + L->shadow_throughput = 0.0f; + L->shadow_transparency = 1.0f; + L->has_shadow_catcher = 0; #endif #ifdef __DENOISING_FEATURES__ L->denoising_normal = make_float3(0.0f, 0.0f, 0.0f); L->denoising_albedo = make_float3(0.0f, 0.0f, 0.0f); L->denoising_depth = 0.0f; -#endif /* __DENOISING_FEATURES__ */ +#endif + +#ifdef __KERNEL_DEBUG__ + L->debug_data.num_bvh_traversed_nodes = 0; + L->debug_data.num_bvh_traversed_instances = 0; + L->debug_data.num_bvh_intersections = 0; + L->debug_data.num_ray_bounces = 0; +#endif } -ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space float3 *throughput, - BsdfEval *bsdf_eval, float bsdf_pdf, int bounce, int bsdf_label) +ccl_device_inline void path_radiance_bsdf_bounce( + KernelGlobals *kg, + PathRadianceState *L_state, + ccl_addr_space float3 *throughput, + BsdfEval *bsdf_eval, + float bsdf_pdf, int bounce, int bsdf_label) { float inverse_pdf = 1.0f/bsdf_pdf; #ifdef __PASSES__ - if(L->use_light_pass) { + if(kernel_data.film.use_light_pass) { if(bounce == 0 && !(bsdf_label & LABEL_TRANSPARENT)) { /* first on directly visible surface */ float3 value = *throughput*inverse_pdf; - L->path_diffuse = bsdf_eval->diffuse*value; - L->path_glossy = bsdf_eval->glossy*value; - L->path_transmission = bsdf_eval->transmission*value; - L->path_subsurface = bsdf_eval->subsurface*value; - L->path_scatter = bsdf_eval->scatter*value; - - *throughput = L->path_diffuse + L->path_glossy + L->path_transmission + L->path_subsurface + L->path_scatter; + L_state->diffuse = bsdf_eval->diffuse*value; + L_state->glossy = bsdf_eval->glossy*value; + L_state->transmission = bsdf_eval->transmission*value; + L_state->subsurface = bsdf_eval->subsurface*value; + L_state->scatter = bsdf_eval->scatter*value; + + *throughput = L_state->diffuse + + L_state->glossy + + L_state->transmission + + L_state->subsurface + + L_state->scatter; - L->direct_throughput = *throughput; + L_state->direct = *throughput; } else { /* transparent bounce before first hit, or indirectly visible through BSDF */ @@ -264,13 +287,22 @@ ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space } } -ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, float3 throughput, float3 value, int bounce) +ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, + ccl_addr_space PathState *state, + float3 throughput, + float3 value) { +#ifdef __SHADOW_TRICKS__ + if(state->flag & PATH_RAY_SHADOW_CATCHER) { + return; + } +#endif + #ifdef __PASSES__ if(L->use_light_pass) { - if(bounce == 0) + if(state->bounce == 0) L->emission += throughput*value; - else if(bounce == 1) + else if(state->bounce == 1) L->direct_emission += throughput*value; else L->indirect += throughput*value; @@ -289,6 +321,18 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 bsdf, float3 ao) { +#ifdef __SHADOW_TRICKS__ + if(state->flag & PATH_RAY_STORE_SHADOW_INFO) { + float3 light = throughput * bsdf; + L->path_total += light; + L->path_total_shaded += ao * light; + + if(state->flag & PATH_RAY_SHADOW_CATCHER) { + return; + } + } +#endif + #ifdef __PASSES__ if(L->use_light_pass) { if(state->bounce == 0) { @@ -306,14 +350,6 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, { L->emission += throughput*bsdf*ao; } - -#ifdef __SHADOW_TRICKS__ - if(state->flag & PATH_RAY_STORE_SHADOW_INFO) { - float3 light = throughput * bsdf; - L->path_total += light; - L->path_total_shaded += ao * light; - } -#endif } ccl_device_inline void path_radiance_accum_total_ao( @@ -342,6 +378,18 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float shadow_fac, bool is_lamp) { +#ifdef __SHADOW_TRICKS__ + if(state->flag & PATH_RAY_STORE_SHADOW_INFO) { + float3 light = throughput * bsdf_eval->sum_no_mis; + L->path_total += light; + L->path_total_shaded += shadow * light; + + if(state->flag & PATH_RAY_SHADOW_CATCHER) { + return; + } + } +#endif + #ifdef __PASSES__ if(L->use_light_pass) { if(state->bounce == 0) { @@ -368,14 +416,6 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L, { L->emission += throughput*bsdf_eval->diffuse*shadow; } - -#ifdef __SHADOW_TRICKS__ - if(state->flag & PATH_RAY_STORE_SHADOW_INFO) { - float3 light = throughput * bsdf_eval->sum_no_mis; - L->path_total += light; - L->path_total_shaded += shadow * light; - } -#endif } ccl_device_inline void path_radiance_accum_total_light( @@ -396,11 +436,24 @@ ccl_device_inline void path_radiance_accum_total_light( #endif } -ccl_device_inline void path_radiance_accum_background(PathRadiance *L, - ccl_addr_space PathState *state, - float3 throughput, - float3 value) +ccl_device_inline void path_radiance_accum_background( + PathRadiance *L, + ccl_addr_space PathState *state, + float3 throughput, + float3 value) { + +#ifdef __SHADOW_TRICKS__ + if(state->flag & PATH_RAY_STORE_SHADOW_INFO) { + L->path_total += throughput * value; + L->path_total_shaded += throughput * value * L->shadow_transparency; + + if(state->flag & PATH_RAY_SHADOW_CATCHER) { + return; + } + } +#endif + #ifdef __PASSES__ if(L->use_light_pass) { if(state->bounce == 0) @@ -416,20 +469,31 @@ ccl_device_inline void path_radiance_accum_background(PathRadiance *L, L->emission += throughput*value; } -#ifdef __SHADOW_TRICKS__ - if(state->flag & PATH_RAY_STORE_SHADOW_INFO) { - L->path_total += throughput * value; - if(state->flag & PATH_RAY_SHADOW_CATCHER_ONLY) { - L->path_total_shaded += throughput * value; - } - } -#endif - #ifdef __DENOISING_FEATURES__ L->denoising_albedo += state->denoising_feature_weight * value; #endif /* __DENOISING_FEATURES__ */ } +ccl_device_inline void path_radiance_accum_transparent( + PathRadiance *L, + ccl_addr_space PathState *state, + float3 throughput) +{ + L->transparent += average(throughput); +} + +#ifdef __SHADOW_TRICKS__ +ccl_device_inline void path_radiance_accum_shadowcatcher( + PathRadiance *L, + float3 throughput, + float3 background) +{ + L->shadow_throughput += average(throughput); + L->shadow_background_color += throughput * background; + L->has_shadow_catcher = 1; +} +#endif + ccl_device_inline void path_radiance_sum_indirect(PathRadiance *L) { #ifdef __PASSES__ @@ -437,19 +501,19 @@ ccl_device_inline void path_radiance_sum_indirect(PathRadiance *L) * only a single throughput further along the path, here we recover just * the indirect path that is not influenced by any particular BSDF type */ if(L->use_light_pass) { - L->direct_emission = safe_divide_color(L->direct_emission, L->direct_throughput); - L->direct_diffuse += L->path_diffuse*L->direct_emission; - L->direct_glossy += L->path_glossy*L->direct_emission; - L->direct_transmission += L->path_transmission*L->direct_emission; - L->direct_subsurface += L->path_subsurface*L->direct_emission; - L->direct_scatter += L->path_scatter*L->direct_emission; - - L->indirect = safe_divide_color(L->indirect, L->direct_throughput); - L->indirect_diffuse += L->path_diffuse*L->indirect; - L->indirect_glossy += L->path_glossy*L->indirect; - L->indirect_transmission += L->path_transmission*L->indirect; - L->indirect_subsurface += L->path_subsurface*L->indirect; - L->indirect_scatter += L->path_scatter*L->indirect; + L->direct_emission = safe_divide_color(L->direct_emission, L->state.direct); + L->direct_diffuse += L->state.diffuse*L->direct_emission; + L->direct_glossy += L->state.glossy*L->direct_emission; + L->direct_transmission += L->state.transmission*L->direct_emission; + L->direct_subsurface += L->state.subsurface*L->direct_emission; + L->direct_scatter += L->state.scatter*L->direct_emission; + + L->indirect = safe_divide_color(L->indirect, L->state.direct); + L->indirect_diffuse += L->state.diffuse*L->indirect; + L->indirect_glossy += L->state.glossy*L->indirect; + L->indirect_transmission += L->state.transmission*L->indirect; + L->indirect_subsurface += L->state.subsurface*L->indirect; + L->indirect_scatter += L->state.scatter*L->indirect; } #endif } @@ -458,11 +522,11 @@ ccl_device_inline void path_radiance_reset_indirect(PathRadiance *L) { #ifdef __PASSES__ if(L->use_light_pass) { - L->path_diffuse = make_float3(0.0f, 0.0f, 0.0f); - L->path_glossy = make_float3(0.0f, 0.0f, 0.0f); - L->path_transmission = make_float3(0.0f, 0.0f, 0.0f); - L->path_subsurface = make_float3(0.0f, 0.0f, 0.0f); - L->path_scatter = make_float3(0.0f, 0.0f, 0.0f); + L->state.diffuse = make_float3(0.0f, 0.0f, 0.0f); + L->state.glossy = make_float3(0.0f, 0.0f, 0.0f); + L->state.transmission = make_float3(0.0f, 0.0f, 0.0f); + L->state.subsurface = make_float3(0.0f, 0.0f, 0.0f); + L->state.scatter = make_float3(0.0f, 0.0f, 0.0f); L->direct_emission = make_float3(0.0f, 0.0f, 0.0f); L->indirect = make_float3(0.0f, 0.0f, 0.0f); @@ -475,11 +539,7 @@ ccl_device_inline void path_radiance_copy_indirect(PathRadiance *L, { #ifdef __PASSES__ if(L->use_light_pass) { - L->path_diffuse = L_src->path_diffuse; - L->path_glossy = L_src->path_glossy; - L->path_transmission = L_src->path_transmission; - L->path_subsurface = L_src->path_subsurface; - L->path_scatter = L_src->path_scatter; + L->state = L_src->state; L->direct_emission = L_src->direct_emission; L->indirect = L_src->indirect; @@ -487,7 +547,36 @@ ccl_device_inline void path_radiance_copy_indirect(PathRadiance *L, #endif } -ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadiance *L) +#ifdef __SHADOW_TRICKS__ +ccl_device_inline void path_radiance_sum_shadowcatcher(KernelGlobals *kg, + PathRadiance *L, + float3 *L_sum, + float *alpha) +{ + /* Calculate current shadow of the path. */ + float path_total = average(L->path_total); + float shadow; + + if(path_total == 0.0f) { + shadow = L->shadow_transparency; + } + else { + float path_total_shaded = average(L->path_total_shaded); + shadow = path_total_shaded / path_total; + } + + /* Calculate final light sum and transparency for shadow catcher object. */ + if(kernel_data.background.transparent) { + *alpha -= L->shadow_throughput * shadow; + } + else { + L->shadow_background_color *= shadow; + *L_sum += L->shadow_background_color; + } +} +#endif + +ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadiance *L, float *alpha) { float3 L_sum; /* Light Passes are used */ @@ -564,8 +653,6 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi L_sum = L_direct + L_indirect; } #endif - - return L_sum; } /* No Light Passes */ @@ -573,14 +660,24 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi #endif { L_sum = L->emission; + + /* Reject invalid value */ + float sum = fabsf((L_sum).x) + fabsf((L_sum).y) + fabsf((L_sum).z); + if(!isfinite_safe(sum)) { + kernel_assert(!"Non-finite final sum in path_radiance_clamp_and_sum!"); + L_sum = make_float3(0.0f, 0.0f, 0.0f); + } } - /* Reject invalid value */ - float sum = fabsf((L_sum).x) + fabsf((L_sum).y) + fabsf((L_sum).z); - if(!isfinite_safe(sum)) { - kernel_assert(!"Non-finite final sum in path_radiance_clamp_and_sum!"); - L_sum = make_float3(0.0f, 0.0f, 0.0f); + /* Compute alpha. */ + *alpha = 1.0f - L->transparent; + + /* Add shadow catcher contributions. */ +#ifdef __SHADOW_TRICKS__ + if(L->has_shadow_catcher) { + path_radiance_sum_shadowcatcher(kg, L, &L_sum, alpha); } +#endif /* __SHADOW_TRICKS__ */ return L_sum; } @@ -613,14 +710,18 @@ ccl_device_inline void path_radiance_split_denoising(KernelGlobals *kg, PathRadi *clean = make_float3(0.0f, 0.0f, 0.0f); #endif +#ifdef __SHADOW_TRICKS__ + if(L->has_shadow_catcher) { + *noisy += L->shadow_background_color; + } +#endif + *noisy = ensure_finite3(*noisy); *clean = ensure_finite3(*clean); } -ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance *L_sample, int num_samples) +ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance *L_sample) { - float fac = 1.0f/num_samples; - #ifdef __SPLIT_KERNEL__ # define safe_float3_add(f, v) \ do { \ @@ -629,65 +730,35 @@ ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance atomic_add_and_fetch_float(p+1, (v).y); \ atomic_add_and_fetch_float(p+2, (v).z); \ } while(0) +# define safe_float_add(f, v) \ + atomic_add_and_fetch_float(&(f), (v)) #else # define safe_float3_add(f, v) (f) += (v) +# define safe_float_add(f, v) (f) += (v) #endif /* __SPLIT_KERNEL__ */ #ifdef __PASSES__ - safe_float3_add(L->direct_diffuse, L_sample->direct_diffuse*fac); - safe_float3_add(L->direct_glossy, L_sample->direct_glossy*fac); - safe_float3_add(L->direct_transmission, L_sample->direct_transmission*fac); - safe_float3_add(L->direct_subsurface, L_sample->direct_subsurface*fac); - safe_float3_add(L->direct_scatter, L_sample->direct_scatter*fac); - - safe_float3_add(L->indirect_diffuse, L_sample->indirect_diffuse*fac); - safe_float3_add(L->indirect_glossy, L_sample->indirect_glossy*fac); - safe_float3_add(L->indirect_transmission, L_sample->indirect_transmission*fac); - safe_float3_add(L->indirect_subsurface, L_sample->indirect_subsurface*fac); - safe_float3_add(L->indirect_scatter, L_sample->indirect_scatter*fac); - - safe_float3_add(L->background, L_sample->background*fac); - safe_float3_add(L->ao, L_sample->ao*fac); - safe_float3_add(L->shadow, L_sample->shadow*fac); -# ifdef __SPLIT_KERNEL__ - atomic_add_and_fetch_float(&L->mist, L_sample->mist*fac); -# else - L->mist += L_sample->mist*fac; -# endif /* __SPLIT_KERNEL__ */ + safe_float3_add(L->direct_diffuse, L_sample->direct_diffuse); + safe_float3_add(L->direct_glossy, L_sample->direct_glossy); + safe_float3_add(L->direct_transmission, L_sample->direct_transmission); + safe_float3_add(L->direct_subsurface, L_sample->direct_subsurface); + safe_float3_add(L->direct_scatter, L_sample->direct_scatter); + + safe_float3_add(L->indirect_diffuse, L_sample->indirect_diffuse); + safe_float3_add(L->indirect_glossy, L_sample->indirect_glossy); + safe_float3_add(L->indirect_transmission, L_sample->indirect_transmission); + safe_float3_add(L->indirect_subsurface, L_sample->indirect_subsurface); + safe_float3_add(L->indirect_scatter, L_sample->indirect_scatter); + + safe_float3_add(L->background, L_sample->background); + safe_float3_add(L->ao, L_sample->ao); + safe_float3_add(L->shadow, L_sample->shadow); + safe_float_add(L->mist, L_sample->mist); #endif /* __PASSES__ */ - safe_float3_add(L->emission, L_sample->emission*fac); + safe_float3_add(L->emission, L_sample->emission); +#undef safe_float_add #undef safe_float3_add } -#ifdef __SHADOW_TRICKS__ -/* Calculate current shadow of the path. */ -ccl_device_inline float path_radiance_sum_shadow(const PathRadiance *L) -{ - float path_total = average(L->path_total); - float path_total_shaded = average(L->path_total_shaded); - if(path_total != 0.0f) { - return path_total_shaded / path_total; - } - return 1.0f; -} - -/* Calculate final light sum and transparency for shadow catcher object. */ -ccl_device_inline float3 path_radiance_sum_shadowcatcher(KernelGlobals *kg, - const PathRadiance *L, - float* alpha) -{ - const float shadow = path_radiance_sum_shadow(L); - float3 L_sum; - if(kernel_data.background.transparent) { - *alpha = 1.0f-shadow; - L_sum = make_float3(0.0f, 0.0f, 0.0f); - } - else { - L_sum = L->shadow_color * shadow; - } - return L_sum; -} -#endif - CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h index f18d145f7cf..4d89839c46c 100644 --- a/intern/cycles/kernel/kernel_bake.h +++ b/intern/cycles/kernel/kernel_bake.h @@ -21,7 +21,7 @@ CCL_NAMESPACE_BEGIN ccl_device_inline void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, - RNG rng, + uint rng_hash, int pass_filter, int sample) { @@ -48,11 +48,10 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg, path_radiance_init(&L_sample, kernel_data.film.use_light_pass); /* init path state */ - path_state_init(kg, &emission_sd, &state, &rng, sample, NULL); + path_state_init(kg, &emission_sd, &state, rng_hash, sample, NULL); /* evaluate surface shader */ - float rbsdf = path_state_rng_1D(kg, &rng, &state, PRNG_BSDF); - shader_eval_surface(kg, sd, &rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, &state, state.flag); /* TODO, disable more closures we don't need besides transparent */ shader_bsdf_disable_transparency(kg, sd); @@ -64,13 +63,13 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg, /* sample ambient occlusion */ if(pass_filter & BAKE_FILTER_AO) { - kernel_path_ao(kg, sd, &emission_sd, &L_sample, &state, &rng, throughput, shader_bsdf_alpha(kg, sd)); + kernel_path_ao(kg, sd, &emission_sd, &L_sample, &state, throughput, shader_bsdf_alpha(kg, sd)); } /* sample emission */ if((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) { float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf); - path_radiance_accum_emission(&L_sample, throughput, emission, state.bounce); + path_radiance_accum_emission(&L_sample, &state, throughput, emission); } bool is_sss_sample = false; @@ -86,7 +85,6 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg, &emission_sd, &L_sample, &state, - &rng, &ray, &throughput, &ss_indirect)) @@ -101,13 +99,10 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg, kernel_path_indirect(kg, &indirect_sd, &emission_sd, - &rng, &ray, throughput, - state.num_samples, &state, &L_sample); - kernel_path_subsurface_accum_indirect(&ss_indirect, &L_sample); } is_sss_sample = true; } @@ -116,14 +111,14 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg, /* sample light and BSDF */ if(!is_sss_sample && (pass_filter & (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT))) { - kernel_path_surface_connect_light(kg, &rng, sd, &emission_sd, throughput, &state, &L_sample); + kernel_path_surface_connect_light(kg, sd, &emission_sd, throughput, &state, &L_sample); - if(kernel_path_surface_bounce(kg, &rng, sd, &throughput, &state, &L_sample, &ray)) { + if(kernel_path_surface_bounce(kg, sd, &throughput, &state, &L_sample.state, &ray)) { #ifdef __LAMP_MIS__ state.ray_t = 0.0f; #endif /* compute indirect light */ - kernel_path_indirect(kg, &indirect_sd, &emission_sd, &rng, &ray, throughput, 1, &state, &L_sample); + kernel_path_indirect(kg, &indirect_sd, &emission_sd, &ray, throughput, &state, &L_sample); /* sum and reset indirect light pass variables for the next samples */ path_radiance_sum_indirect(&L_sample); @@ -137,13 +132,13 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg, /* sample ambient occlusion */ if(pass_filter & BAKE_FILTER_AO) { - kernel_branched_path_ao(kg, sd, &emission_sd, &L_sample, &state, &rng, throughput); + kernel_branched_path_ao(kg, sd, &emission_sd, &L_sample, &state, throughput); } /* sample emission */ if((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) { float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf); - path_radiance_accum_emission(&L_sample, throughput, emission, state.bounce); + path_radiance_accum_emission(&L_sample, &state, throughput, emission); } #ifdef __SUBSURFACE__ @@ -151,7 +146,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg, if((pass_filter & BAKE_FILTER_SUBSURFACE) && (sd->flag & SD_BSSRDF)) { /* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */ kernel_branched_path_subsurface_scatter(kg, sd, &indirect_sd, - &emission_sd, &L_sample, &state, &rng, &ray, throughput); + &emission_sd, &L_sample, &state, &ray, throughput); } #endif @@ -161,20 +156,20 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg, /* direct light */ if(kernel_data.integrator.use_direct_light) { int all = kernel_data.integrator.sample_all_lights_direct; - kernel_branched_path_surface_connect_light(kg, &rng, + kernel_branched_path_surface_connect_light(kg, sd, &emission_sd, &state, throughput, 1.0f, &L_sample, all); } #endif /* indirect light */ - kernel_branched_path_surface_indirect_light(kg, &rng, + kernel_branched_path_surface_indirect_light(kg, sd, &indirect_sd, &emission_sd, throughput, 1.0f, &state, &L_sample); } } #endif /* accumulate into master L */ - path_radiance_accum_sample(L, &L_sample, 1); + path_radiance_accum_sample(L, &L_sample); } ccl_device bool is_aa_pass(ShaderEvalType type) @@ -225,7 +220,6 @@ ccl_device_inline float3 kernel_bake_shader_bsdf(KernelGlobals *kg, ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg, ShaderData *sd, - RNG *rng, PathState *state, float3 direct, float3 indirect, @@ -245,12 +239,12 @@ ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg, } else { /* surface color of the pass only */ - shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, state, 0); return kernel_bake_shader_bsdf(kg, sd, type); } } else { - shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, state, 0); color = kernel_bake_shader_bsdf(kg, sd, type); } @@ -292,14 +286,14 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, int num_samples = kernel_data.integrator.aa_samples; /* random number generator */ - RNG rng = cmj_hash(offset + i, kernel_data.integrator.seed); + uint rng_hash = cmj_hash(offset + i, kernel_data.integrator.seed); float filter_x, filter_y; if(sample == 0) { filter_x = filter_y = 0.5f; } else { - path_rng_2D(kg, &rng, sample, num_samples, PRNG_FILTER_U, &filter_x, &filter_y); + path_rng_2D(kg, rng_hash, sample, num_samples, PRNG_FILTER_U, &filter_x, &filter_y); } /* subpixel u/v offset */ @@ -335,18 +329,18 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, /* light passes if we need more than color */ if(pass_filter & ~BAKE_FILTER_COLOR) - compute_light_pass(kg, &sd, &L, rng, pass_filter, sample); + compute_light_pass(kg, &sd, &L, rng_hash, pass_filter, sample); switch(type) { /* data passes */ case SHADER_EVAL_NORMAL: { if((sd.flag & SD_HAS_BUMP)) { - shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, &state, 0); } - /* compression: normal = (2 * color) - 1 */ - out = sd.N * 0.5f + make_float3(0.5f, 0.5f, 0.5f); + /* encoding: normal = (2 * color) - 1 */ + out = shader_bsdf_average_normal(kg, &sd) * 0.5f + make_float3(0.5f, 0.5f, 0.5f); break; } case SHADER_EVAL_UV: @@ -356,7 +350,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, } case SHADER_EVAL_EMISSION: { - shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_EMISSION); + shader_eval_surface(kg, &sd, &state, 0); out = shader_emissive_eval(kg, &sd); break; } @@ -371,7 +365,8 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, case SHADER_EVAL_COMBINED: { if((pass_filter & BAKE_FILTER_COMBINED) == BAKE_FILTER_COMBINED) { - out = path_radiance_clamp_and_sum(kg, &L); + float alpha; + out = path_radiance_clamp_and_sum(kg, &L, &alpha); break; } @@ -409,7 +404,6 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, - &rng, &state, L.direct_diffuse, L.indirect_diffuse, @@ -421,7 +415,6 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, - &rng, &state, L.direct_glossy, L.indirect_glossy, @@ -433,7 +426,6 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, - &rng, &state, L.direct_transmission, L.indirect_transmission, @@ -446,7 +438,6 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, #ifdef __SUBSURFACE__ out = kernel_bake_evaluate_direct_indirect(kg, &sd, - &rng, &state, L.direct_subsurface, L.indirect_subsurface, @@ -480,7 +471,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, /* evaluate */ int flag = 0; /* we can't know which type of BSDF this is for */ - out = shader_eval_background(kg, &sd, &state, flag, SHADER_CONTEXT_MAIN); + out = shader_eval_background(kg, &sd, &state, flag); break; } default: @@ -524,7 +515,7 @@ ccl_device void kernel_shader_evaluate(KernelGlobals *kg, /* evaluate */ float3 P = sd.P; - shader_eval_displacement(kg, &sd, &state, SHADER_CONTEXT_MAIN); + shader_eval_displacement(kg, &sd, &state); out = sd.P - P; object_inverse_dir_transform(kg, &sd, &out); @@ -552,7 +543,7 @@ ccl_device void kernel_shader_evaluate(KernelGlobals *kg, /* evaluate */ int flag = 0; /* we can't know which type of BSDF this is for */ - out = shader_eval_background(kg, &sd, &state, flag, SHADER_CONTEXT_MAIN); + out = shader_eval_background(kg, &sd, &state, flag); } /* write output */ diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h index 38708f7ff0b..1e2af9de8b3 100644 --- a/intern/cycles/kernel/kernel_compat_cuda.h +++ b/intern/cycles/kernel/kernel_compat_cuda.h @@ -38,11 +38,15 @@ /* Qualifier wrappers for different names on different devices */ #define ccl_device __device__ __inline__ +#if __CUDA_ARCH__ < 300 +# define ccl_device_inline __device__ __inline__ # define ccl_device_forceinline __device__ __forceinline__ -#if __CUDA_ARCH__ < 500 +#elif __CUDA_ARCH__ < 500 # define ccl_device_inline __device__ __forceinline__ +# define ccl_device_forceinline __device__ __forceinline__ #else # define ccl_device_inline __device__ __inline__ +# define ccl_device_forceinline __device__ __forceinline__ #endif #define ccl_device_noinline __device__ __noinline__ #define ccl_global @@ -53,6 +57,10 @@ #define ccl_may_alias #define ccl_addr_space #define ccl_restrict __restrict__ +/* TODO(sergey): In theory we might use references with CUDA, however + * performance impact yet to be investigated. + */ +#define ccl_ref #define ccl_align(n) __align__(n) #define ATTR_FALLTHROUGH diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h index 4836c290312..36d6031d042 100644 --- a/intern/cycles/kernel/kernel_compat_opencl.h +++ b/intern/cycles/kernel/kernel_compat_opencl.h @@ -42,6 +42,7 @@ #define ccl_local_param __local #define ccl_private __private #define ccl_restrict restrict +#define ccl_ref #define ccl_align(n) __attribute__((aligned(n))) #ifdef __SPLIT_KERNEL__ @@ -129,6 +130,7 @@ # define expf(x) native_exp(((float)(x))) # define sqrtf(x) native_sqrt(((float)(x))) # define logf(x) native_log(((float)(x))) +# define rcp(x) native_recip(x) #else # define sinf(x) sin(((float)(x))) # define cosf(x) cos(((float)(x))) @@ -136,11 +138,12 @@ # define expf(x) exp(((float)(x))) # define sqrtf(x) sqrt(((float)(x))) # define logf(x) log(((float)(x))) +# define rcp(x) recip(x)) #endif /* data lookup defines */ #define kernel_data (*kg->data) -#define kernel_tex_fetch(t, index) kg->t[index] +#define kernel_tex_fetch(tex, index) ((ccl_global tex##_t*)(kg->buffers[kg->tex.buffer] + kg->tex.offset))[(index)] /* define NULL */ #define NULL 0 diff --git a/intern/cycles/kernel/kernel_debug.h b/intern/cycles/kernel/kernel_debug.h deleted file mode 100644 index 5647bbae5b5..00000000000 --- a/intern/cycles/kernel/kernel_debug.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2011-2014 Blender Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -CCL_NAMESPACE_BEGIN - -ccl_device_inline void debug_data_init(DebugData *debug_data) -{ - debug_data->num_bvh_traversed_nodes = 0; - debug_data->num_bvh_traversed_instances = 0; - debug_data->num_bvh_intersections = 0; - debug_data->num_ray_bounces = 0; -} - -ccl_device_inline void kernel_write_debug_passes(KernelGlobals *kg, - ccl_global float *buffer, - ccl_addr_space PathState *state, - DebugData *debug_data, - int sample) -{ - int flag = kernel_data.film.pass_flag; - if(flag & PASS_BVH_TRAVERSED_NODES) { - kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_traversed_nodes, - sample, - debug_data->num_bvh_traversed_nodes); - } - if(flag & PASS_BVH_TRAVERSED_INSTANCES) { - kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_traversed_instances, - sample, - debug_data->num_bvh_traversed_instances); - } - if(flag & PASS_BVH_INTERSECTIONS) { - kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_intersections, - sample, - debug_data->num_bvh_intersections); - } - if(flag & PASS_RAY_BOUNCES) { - kernel_write_pass_float(buffer + kernel_data.film.pass_ray_bounces, - sample, - debug_data->num_ray_bounces); - } -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index 9e7d51f23f5..45b8c6311e1 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -37,16 +37,14 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg, ray.D = ls->D; ray.P = ls->P; ray.t = 1.0f; -# ifdef __OBJECT_MOTION__ ray.time = time; -# endif ray.dP = differential3_zero(); ray.dD = dI; shader_setup_from_background(kg, emission_sd, &ray); path_state_modify_bounce(state, true); - eval = shader_eval_background(kg, emission_sd, state, 0, SHADER_CONTEXT_EMISSION); + eval = shader_eval_background(kg, emission_sd, state, 0); path_state_modify_bounce(state, false); } else @@ -72,7 +70,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg, /* no path flag, we're evaluating this for all closures. that's weak but * we'd have to do multiple evaluations otherwise */ path_state_modify_bounce(state, true); - shader_eval_surface(kg, emission_sd, NULL, state, 0.0f, 0, SHADER_CONTEXT_EMISSION); + shader_eval_surface(kg, emission_sd, state, 0); path_state_modify_bounce(state, false); /* evaluate emissive closure */ @@ -216,7 +214,7 @@ ccl_device_noinline float3 indirect_primitive_emission(KernelGlobals *kg, Shader { /* multiple importance sampling, get triangle light pdf, * and compute weight with respect to BSDF pdf */ - float pdf = triangle_light_pdf(kg, sd->Ng, sd->I, t); + float pdf = triangle_light_pdf(kg, sd, t); float mis_weight = power_heuristic(bsdf_pdf, pdf); return L*mis_weight; @@ -319,7 +317,7 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg, # endif path_state_modify_bounce(state, true); - float3 L = shader_eval_background(kg, emission_sd, state, state->flag, SHADER_CONTEXT_EMISSION); + float3 L = shader_eval_background(kg, emission_sd, state, state->flag); path_state_modify_bounce(state, false); #ifdef __BACKGROUND_MIS__ diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h index f95f0d98c52..9d55183d94b 100644 --- a/intern/cycles/kernel/kernel_globals.h +++ b/intern/cycles/kernel/kernel_globals.h @@ -23,6 +23,10 @@ # include "util/util_vector.h" #endif +#ifdef __KERNEL_OPENCL__ +# include "util/util_atomic.h" +#endif + CCL_NAMESPACE_BEGIN /* On the CPU, we pass along the struct KernelGlobals to nearly everywhere in @@ -109,11 +113,22 @@ typedef struct KernelGlobals { #ifdef __KERNEL_OPENCL__ +# define KERNEL_TEX(type, ttype, name) \ +typedef type name##_t; +# include "kernel/kernel_textures.h" + +typedef struct tex_info_t { + uint buffer, padding; + uint64_t offset; + uint width, height, depth, options; +} tex_info_t; + typedef ccl_addr_space struct KernelGlobals { ccl_constant KernelData *data; + ccl_global char *buffers[8]; # define KERNEL_TEX(type, ttype, name) \ - ccl_global type *name; + tex_info_t name; # include "kernel/kernel_textures.h" # ifdef __SPLIT_KERNEL__ @@ -122,6 +137,57 @@ typedef ccl_addr_space struct KernelGlobals { # endif } KernelGlobals; +#define KERNEL_BUFFER_PARAMS \ + ccl_global char *buffer0, \ + ccl_global char *buffer1, \ + ccl_global char *buffer2, \ + ccl_global char *buffer3, \ + ccl_global char *buffer4, \ + ccl_global char *buffer5, \ + ccl_global char *buffer6, \ + ccl_global char *buffer7 + +#define KERNEL_BUFFER_ARGS buffer0, buffer1, buffer2, buffer3, buffer4, buffer5, buffer6, buffer7 + +ccl_device_inline void kernel_set_buffer_pointers(KernelGlobals *kg, KERNEL_BUFFER_PARAMS) +{ +#ifdef __SPLIT_KERNEL__ + if(ccl_local_id(0) + ccl_local_id(1) == 0) +#endif + { + kg->buffers[0] = buffer0; + kg->buffers[1] = buffer1; + kg->buffers[2] = buffer2; + kg->buffers[3] = buffer3; + kg->buffers[4] = buffer4; + kg->buffers[5] = buffer5; + kg->buffers[6] = buffer6; + kg->buffers[7] = buffer7; + } + +# ifdef __SPLIT_KERNEL__ + ccl_barrier(CCL_LOCAL_MEM_FENCE); +# endif +} + +ccl_device_inline void kernel_set_buffer_info(KernelGlobals *kg) +{ +# ifdef __SPLIT_KERNEL__ + if(ccl_local_id(0) + ccl_local_id(1) == 0) +# endif + { + ccl_global tex_info_t *info = (ccl_global tex_info_t*)kg->buffers[0]; + +# define KERNEL_TEX(type, ttype, name) \ + kg->name = *(info++); +# include "kernel/kernel_textures.h" + } + +# ifdef __SPLIT_KERNEL__ + ccl_barrier(CCL_LOCAL_MEM_FENCE); +# endif +} + #endif /* __KERNEL_OPENCL__ */ /* Interpolated lookup table access */ diff --git a/intern/cycles/kernel/kernel_image_opencl.h b/intern/cycles/kernel/kernel_image_opencl.h index 90747e09357..9e3373432ec 100644 --- a/intern/cycles/kernel/kernel_image_opencl.h +++ b/intern/cycles/kernel/kernel_image_opencl.h @@ -15,30 +15,42 @@ */ -/* For OpenCL all images are packed in a single array, and we do manual lookup - * and interpolation. */ +/* For OpenCL we do manual lookup and interpolation. */ + +ccl_device_inline ccl_global tex_info_t* kernel_tex_info(KernelGlobals *kg, uint id) { + const uint tex_offset = id +#define KERNEL_TEX(type, ttype, name) + 1 +#include "kernel/kernel_textures.h" + ; + + return &((ccl_global tex_info_t*)kg->buffers[0])[tex_offset]; +} + +#define tex_fetch(type, info, index) ((ccl_global type*)(kg->buffers[info->buffer] + info->offset))[(index)] ccl_device_inline float4 svm_image_texture_read(KernelGlobals *kg, int id, int offset) { + const ccl_global tex_info_t *info = kernel_tex_info(kg, id); const int texture_type = kernel_tex_type(id); + /* Float4 */ if(texture_type == IMAGE_DATA_TYPE_FLOAT4) { - return kernel_tex_fetch(__tex_image_float4_packed, offset); + return tex_fetch(float4, info, offset); } /* Byte4 */ else if(texture_type == IMAGE_DATA_TYPE_BYTE4) { - uchar4 r = kernel_tex_fetch(__tex_image_byte4_packed, offset); + uchar4 r = tex_fetch(uchar4, info, offset); float f = 1.0f/255.0f; return make_float4(r.x*f, r.y*f, r.z*f, r.w*f); } /* Float */ else if(texture_type == IMAGE_DATA_TYPE_FLOAT) { - float f = kernel_tex_fetch(__tex_image_float_packed, offset); + float f = tex_fetch(float, info, offset); return make_float4(f, f, f, 1.0f); } /* Byte */ else { - uchar r = kernel_tex_fetch(__tex_image_byte_packed, offset); + uchar r = tex_fetch(uchar, info, offset); float f = r * (1.0f/255.0f); return make_float4(f, f, f, 1.0f); } @@ -64,17 +76,17 @@ ccl_device_inline float svm_image_texture_frac(float x, int *ix) return x - (float)i; } -ccl_device_inline uint kernel_decode_image_interpolation(uint4 info) +ccl_device_inline uint kernel_decode_image_interpolation(uint info) { - return (info.w & (1 << 0)) ? INTERPOLATION_CLOSEST : INTERPOLATION_LINEAR; + return (info & (1 << 0)) ? INTERPOLATION_CLOSEST : INTERPOLATION_LINEAR; } -ccl_device_inline uint kernel_decode_image_extension(uint4 info) +ccl_device_inline uint kernel_decode_image_extension(uint info) { - if(info.w & (1 << 1)) { + if(info & (1 << 1)) { return EXTENSION_REPEAT; } - else if(info.w & (1 << 2)) { + else if(info & (1 << 2)) { return EXTENSION_EXTEND; } else { @@ -84,13 +96,16 @@ ccl_device_inline uint kernel_decode_image_extension(uint4 info) ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, float y) { - uint4 info = kernel_tex_fetch(__tex_image_packed_info, id*2); - uint width = info.x; - uint height = info.y; - uint offset = info.z; + const ccl_global tex_info_t *info = kernel_tex_info(kg, id); + + uint width = info->width; + uint height = info->height; + uint offset = 0; + /* Decode image options. */ - uint interpolation = kernel_decode_image_interpolation(info); - uint extension = kernel_decode_image_extension(info); + uint interpolation = kernel_decode_image_interpolation(info->options); + uint extension = kernel_decode_image_extension(info->options); + /* Actual sampling. */ float4 r; int ix, iy, nix, niy; @@ -150,14 +165,17 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float x, float y, float z) { - uint4 info = kernel_tex_fetch(__tex_image_packed_info, id*2); - uint width = info.x; - uint height = info.y; - uint offset = info.z; - uint depth = kernel_tex_fetch(__tex_image_packed_info, id*2+1).x; + const ccl_global tex_info_t *info = kernel_tex_info(kg, id); + + uint width = info->width; + uint height = info->height; + uint offset = 0; + uint depth = info->depth; + /* Decode image options. */ - uint interpolation = kernel_decode_image_interpolation(info); - uint extension = kernel_decode_image_extension(info); + uint interpolation = kernel_decode_image_interpolation(info->options); + uint extension = kernel_decode_image_extension(info->options); + /* Actual sampling. */ float4 r; int ix, iy, iz, nix, niy, niz; diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index 9baa9d54957..c806deee8e7 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -396,11 +396,13 @@ ccl_device_inline float3 background_light_sample(KernelGlobals *kg, + (1.0f - portal_sampling_pdf) * cdf_pdf); } return D; - } else { + } + else { /* Sample map, but with nonzero portal_sampling_pdf for MIS. */ randu = (randu - portal_sampling_pdf) / (1.0f - portal_sampling_pdf); } - } else { + } + else { /* We can't sample a portal. * Check if we can sample the map instead. */ @@ -763,78 +765,280 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, /* Triangle Light */ -ccl_device void object_transform_light_sample(KernelGlobals *kg, LightSample *ls, int object, float time) +/* returns true if the triangle is has motion blur or an instancing transform applied */ +ccl_device_inline bool triangle_world_space_vertices(KernelGlobals *kg, int object, int prim, float time, float3 V[3]) { + bool has_motion = false; + const int object_flag = kernel_tex_fetch(__object_flag, object); + + if(object_flag & SD_OBJECT_HAS_VERTEX_MOTION && time >= 0.0f) { + motion_triangle_vertices(kg, object, prim, time, V); + has_motion = true; + } + else { + triangle_vertices(kg, prim, V); + } + #ifdef __INSTANCING__ - /* instance transform */ - if(!(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED)) { + if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { # ifdef __OBJECT_MOTION__ - Transform itfm; - Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm); + Transform tfm = object_fetch_transform_motion_test(kg, object, time, NULL); # else Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); # endif - - ls->P = transform_point(&tfm, ls->P); - ls->Ng = normalize(transform_direction(&tfm, ls->Ng)); + V[0] = transform_point(&tfm, V[0]); + V[1] = transform_point(&tfm, V[1]); + V[2] = transform_point(&tfm, V[2]); + has_motion = true; } #endif + return has_motion; } -ccl_device void triangle_light_sample(KernelGlobals *kg, int prim, int object, - float randu, float randv, float time, LightSample *ls) +ccl_device_inline float triangle_light_pdf_area(KernelGlobals *kg, const float3 Ng, const float3 I, float t) { - float u, v; + float pdf = kernel_data.integrator.pdf_triangles; + float cos_pi = fabsf(dot(Ng, I)); - /* compute random point in triangle */ - randu = sqrtf(randu); + if(cos_pi == 0.0f) + return 0.0f; + + return t*t*pdf/cos_pi; +} - u = 1.0f - randu; - v = randv*randu; +ccl_device_forceinline float triangle_light_pdf(KernelGlobals *kg, ShaderData *sd, float t) +{ + /* A naive heuristic to decide between costly solid angle sampling + * and simple area sampling, comparing the distance to the triangle plane + * to the length of the edges of the triangle. */ + + float3 V[3]; + bool has_motion = triangle_world_space_vertices(kg, sd->object, sd->prim, sd->time, V); + + const float3 e0 = V[1] - V[0]; + const float3 e1 = V[2] - V[0]; + const float3 e2 = V[2] - V[1]; + const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2))); + const float3 N = cross(e0, e1); + const float distance_to_plane = fabsf(dot(N, sd->I * t))/dot(N, N); + + if(longest_edge_squared > distance_to_plane*distance_to_plane) { + /* sd contains the point on the light source + * calculate Px, the point that we're shading */ + const float3 Px = sd->P + sd->I * t; + const float3 v0_p = V[0] - Px; + const float3 v1_p = V[1] - Px; + const float3 v2_p = V[2] - Px; + + const float3 u01 = safe_normalize(cross(v0_p, v1_p)); + const float3 u02 = safe_normalize(cross(v0_p, v2_p)); + const float3 u12 = safe_normalize(cross(v1_p, v2_p)); + + const float alpha = fast_acosf(dot(u02, u01)); + const float beta = fast_acosf(-dot(u01, u12)); + const float gamma = fast_acosf(dot(u02, u12)); + const float solid_angle = alpha + beta + gamma - M_PI_F; + + /* pdf_triangles is calculated over triangle area, but we're not sampling over its area */ + if(UNLIKELY(solid_angle == 0.0f)) { + return 0.0f; + } + else { + float area = 1.0f; + if(has_motion) { + /* get the center frame vertices, this is what the PDF was calculated from */ + triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V); + area = triangle_area(V[0], V[1], V[2]); + } + else { + area = 0.5f * len(N); + } + const float pdf = area * kernel_data.integrator.pdf_triangles; + return pdf / solid_angle; + } + } + else { + float pdf = triangle_light_pdf_area(kg, sd->Ng, sd->I, t); + if(has_motion) { + const float area = 0.5f * len(N); + if(UNLIKELY(area == 0.0f)) { + return 0.0f; + } + /* scale the PDF. + * area = the area the sample was taken from + * area_pre = the are from which pdf_triangles was calculated from */ + triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V); + const float area_pre = triangle_area(V[0], V[1], V[2]); + pdf = pdf * area_pre / area; + } + return pdf; + } +} - /* triangle, so get position, normal, shader */ - triangle_point_normal(kg, object, prim, u, v, &ls->P, &ls->Ng, &ls->shader); +ccl_device_forceinline void triangle_light_sample(KernelGlobals *kg, int prim, int object, + float randu, float randv, float time, LightSample *ls, const float3 P) +{ + /* A naive heuristic to decide between costly solid angle sampling + * and simple area sampling, comparing the distance to the triangle plane + * to the length of the edges of the triangle. */ + + float3 V[3]; + bool has_motion = triangle_world_space_vertices(kg, object, prim, time, V); + + const float3 e0 = V[1] - V[0]; + const float3 e1 = V[2] - V[0]; + const float3 e2 = V[2] - V[1]; + const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2))); + const float3 N0 = cross(e0, e1); + float Nl = 0.0f; + ls->Ng = safe_normalize_len(N0, &Nl); + float area = 0.5f * Nl; + + /* flip normal if necessary */ + const int object_flag = kernel_tex_fetch(__object_flag, object); + if(object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) { + ls->Ng = -ls->Ng; + } + ls->eval_fac = 1.0f; + ls->shader = kernel_tex_fetch(__tri_shader, prim); ls->object = object; ls->prim = prim; ls->lamp = LAMP_NONE; ls->shader |= SHADER_USE_MIS; - ls->t = 0.0f; - ls->u = u; - ls->v = v; ls->type = LIGHT_TRIANGLE; - ls->eval_fac = 1.0f; - object_transform_light_sample(kg, ls, object, time); -} + float distance_to_plane = fabsf(dot(N0, V[0] - P)/dot(N0, N0)); + + if(longest_edge_squared > distance_to_plane*distance_to_plane) { + /* see James Arvo, "Stratified Sampling of Spherical Triangles" + * http://www.graphics.cornell.edu/pubs/1995/Arv95c.pdf */ + + /* project the triangle to the unit sphere + * and calculate its edges and angles */ + const float3 v0_p = V[0] - P; + const float3 v1_p = V[1] - P; + const float3 v2_p = V[2] - P; + + const float3 u01 = safe_normalize(cross(v0_p, v1_p)); + const float3 u02 = safe_normalize(cross(v0_p, v2_p)); + const float3 u12 = safe_normalize(cross(v1_p, v2_p)); + + const float3 A = safe_normalize(v0_p); + const float3 B = safe_normalize(v1_p); + const float3 C = safe_normalize(v2_p); + + const float cos_alpha = dot(u02, u01); + const float cos_beta = -dot(u01, u12); + const float cos_gamma = dot(u02, u12); + + /* calculate dihedral angles */ + const float alpha = fast_acosf(cos_alpha); + const float beta = fast_acosf(cos_beta); + const float gamma = fast_acosf(cos_gamma); + /* the area of the unit spherical triangle = solid angle */ + const float solid_angle = alpha + beta + gamma - M_PI_F; + + /* precompute a few things + * these could be re-used to take several samples + * as they are independent of randu/randv */ + const float cos_c = dot(A, B); + const float sin_alpha = fast_sinf(alpha); + const float product = sin_alpha * cos_c; + + /* Select a random sub-area of the spherical triangle + * and calculate the third vertex C_ of that new triangle */ + const float phi = randu * solid_angle - alpha; + float s, t; + fast_sincosf(phi, &s, &t); + const float u = t - cos_alpha; + const float v = s + product; + + const float3 U = safe_normalize(C - dot(C, A) * A); + + float q = 1.0f; + const float det = ((v * s + u * t) * sin_alpha); + if(det != 0.0f) { + q = ((v * t - u * s) * cos_alpha - v) / det; + } + const float temp = max(1.0f - q*q, 0.0f); -ccl_device float triangle_light_pdf(KernelGlobals *kg, - const float3 Ng, const float3 I, float t) -{ - float pdf = kernel_data.integrator.pdf_triangles; - float cos_pi = fabsf(dot(Ng, I)); + const float3 C_ = safe_normalize(q * A + sqrtf(temp) * U); - if(cos_pi == 0.0f) - return 0.0f; - - return t*t*pdf/cos_pi; + /* Finally, select a random point along the edge of the new triangle + * That point on the spherical triangle is the sampled ray direction */ + const float z = 1.0f - randv * (1.0f - dot(C_, B)); + ls->D = z * B + safe_sqrtf(1.0f - z*z) * safe_normalize(C_ - dot(C_, B) * B); + + /* calculate intersection with the planar triangle */ + if(!ray_triangle_intersect(P, ls->D, FLT_MAX, +#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) + (ssef*)V, +#else + V[0], V[1], V[2], +#endif + &ls->u, &ls->v, &ls->t)) { + ls->pdf = 0.0f; + return; + } + + ls->P = P + ls->D * ls->t; + + /* pdf_triangles is calculated over triangle area, but we're sampling over solid angle */ + if(UNLIKELY(solid_angle == 0.0f)) { + ls->pdf = 0.0f; + return; + } + else { + if(has_motion) { + /* get the center frame vertices, this is what the PDF was calculated from */ + triangle_world_space_vertices(kg, object, prim, -1.0f, V); + area = triangle_area(V[0], V[1], V[2]); + } + const float pdf = area * kernel_data.integrator.pdf_triangles; + ls->pdf = pdf / solid_angle; + } + } + else { + /* compute random point in triangle */ + randu = sqrtf(randu); + + const float u = 1.0f - randu; + const float v = randv*randu; + const float t = 1.0f - u - v; + ls->P = u * V[0] + v * V[1] + t * V[2]; + /* compute incoming direction, distance and pdf */ + ls->D = normalize_len(ls->P - P, &ls->t); + ls->pdf = triangle_light_pdf_area(kg, ls->Ng, -ls->D, ls->t); + if(has_motion && area != 0.0f) { + /* scale the PDF. + * area = the area the sample was taken from + * area_pre = the are from which pdf_triangles was calculated from */ + triangle_world_space_vertices(kg, object, prim, -1.0f, V); + const float area_pre = triangle_area(V[0], V[1], V[2]); + ls->pdf = ls->pdf * area_pre / area; + } + ls->u = u; + ls->v = v; + } } /* Light Distribution */ -ccl_device int light_distribution_sample(KernelGlobals *kg, float randt) +ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu) { - /* this is basically std::upper_bound as used by pbrt, to find a point light or + /* 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 * also sample proportional to power, though it's not so well defined with - * OSL shaders. */ + * arbitrary shaders. */ int first = 0; int len = kernel_data.integrator.num_distribution + 1; + float r = *randu; while(len > 0) { int half_len = len >> 1; int middle = first + half_len; - if(randt < kernel_tex_fetch(__light_distribution, middle).x) { + if(r < kernel_tex_fetch(__light_distribution, middle).x) { len = half_len; } else { @@ -843,9 +1047,17 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float randt) } } - /* clamping should not be needed but float rounding errors seem to - * make this fail on rare occasions */ - return clamp(first-1, 0, kernel_data.integrator.num_distribution-1); + /* Clamping should not be needed but float rounding errors seem to + * 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_tex_fetch(__light_distribution, index).x; + float distr_max = kernel_tex_fetch(__light_distribution, index+1).x; + *randu = (r - distr_min)/(distr_max - distr_min); + + return index; } /* Generic Light */ @@ -857,7 +1069,6 @@ ccl_device bool light_select_reached_max_bounces(KernelGlobals *kg, int index, i } ccl_device_noinline bool light_sample(KernelGlobals *kg, - float randt, float randu, float randv, float time, @@ -866,7 +1077,7 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg, LightSample *ls) { /* sample index */ - int index = light_distribution_sample(kg, randt); + int index = light_distribution_sample(kg, &randu); /* fetch light data */ float4 l = kernel_tex_fetch(__light_distribution, index); @@ -876,10 +1087,7 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg, int object = __float_as_int(l.w); int shader_flag = __float_as_int(l.z); - triangle_light_sample(kg, prim, object, randu, randv, time, ls); - /* compute incoming direction, distance and pdf */ - ls->D = normalize_len(ls->P - P, &ls->t); - ls->pdf = triangle_light_pdf(kg, ls->Ng, -ls->D, ls->t); + triangle_light_sample(kg, prim, object, randu, randv, time, ls, P); ls->shader |= shader_flag; return (ls->pdf > 0.0f); } diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h index 9cd7ffb181d..fff7f4cfdb7 100644 --- a/intern/cycles/kernel/kernel_passes.h +++ b/intern/cycles/kernel/kernel_passes.h @@ -194,8 +194,38 @@ ccl_device_inline void kernel_update_denoising_features(KernelGlobals *kg, #endif /* __DENOISING_FEATURES__ */ } +#ifdef __KERNEL_DEBUG__ +ccl_device_inline void kernel_write_debug_passes(KernelGlobals *kg, + ccl_global float *buffer, + PathRadiance *L, + int sample) +{ + int flag = kernel_data.film.pass_flag; + if(flag & PASS_BVH_TRAVERSED_NODES) { + kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_traversed_nodes, + sample, + L->debug_data.num_bvh_traversed_nodes); + } + if(flag & PASS_BVH_TRAVERSED_INSTANCES) { + kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_traversed_instances, + sample, + L->debug_data.num_bvh_traversed_instances); + } + if(flag & PASS_BVH_INTERSECTIONS) { + kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_intersections, + sample, + L->debug_data.num_bvh_intersections); + } + if(flag & PASS_RAY_BOUNCES) { + kernel_write_pass_float(buffer + kernel_data.film.pass_ray_bounces, + sample, + L->debug_data.num_ray_bounces); + } +} +#endif /* __KERNEL_DEBUG__ */ + ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global float *buffer, PathRadiance *L, - ShaderData *sd, int sample, ccl_addr_space PathState *state, float3 throughput) + ShaderData *sd, ccl_addr_space PathState *state, float3 throughput) { #ifdef __PASSES__ int path_flag = state->flag; @@ -213,6 +243,7 @@ ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global fl kernel_data.film.pass_alpha_threshold == 0.0f || average(shader_bsdf_alpha(kg, sd)) >= kernel_data.film.pass_alpha_threshold) { + int sample = state->sample; if(sample == 0) { if(flag & PASS_DEPTH) { @@ -230,7 +261,7 @@ ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global fl } if(flag & PASS_NORMAL) { - float3 normal = sd->N; + float3 normal = shader_bsdf_average_normal(kg, sd); kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, sample, normal); } if(flag & PASS_UV) { @@ -334,19 +365,11 @@ ccl_device_inline void kernel_write_light_passes(KernelGlobals *kg, ccl_global f } ccl_device_inline void kernel_write_result(KernelGlobals *kg, ccl_global float *buffer, - int sample, PathRadiance *L, float alpha, bool is_shadow_catcher) + int sample, PathRadiance *L) { if(L) { - float3 L_sum; -#ifdef __SHADOW_TRICKS__ - if(is_shadow_catcher) { - L_sum = path_radiance_sum_shadowcatcher(kg, L, &alpha); - } - else -#endif /* __SHADOW_TRICKS__ */ - { - L_sum = path_radiance_clamp_and_sum(kg, L); - } + float alpha; + float3 L_sum = path_radiance_clamp_and_sum(kg, L, &alpha); kernel_write_pass_float4(buffer, sample, make_float4(L_sum.x, L_sum.y, L_sum.z, alpha)); @@ -361,16 +384,7 @@ ccl_device_inline void kernel_write_result(KernelGlobals *kg, ccl_global float * # endif if(kernel_data.film.pass_denoising_clean) { float3 noisy, clean; -#ifdef __SHADOW_TRICKS__ - if(is_shadow_catcher) { - noisy = L_sum; - clean = make_float3(0.0f, 0.0f, 0.0f); - } - else -#endif /* __SHADOW_TRICKS__ */ - { - path_radiance_split_denoising(kg, L, &noisy, &clean); - } + path_radiance_split_denoising(kg, L, &noisy, &clean); kernel_write_pass_float3_variance(buffer + kernel_data.film.pass_denoising_data + DENOISING_PASS_COLOR, sample, noisy); kernel_write_pass_float3_unaligned(buffer + kernel_data.film.pass_denoising_clean, @@ -389,6 +403,11 @@ ccl_device_inline void kernel_write_result(KernelGlobals *kg, ccl_global float * sample, L->denoising_depth); } #endif /* __DENOISING_FEATURES__ */ + + +#ifdef __KERNEL_DEBUG__ + kernel_write_debug_passes(kg, buffer, L, sample); +#endif } else { kernel_write_pass_float4(buffer, sample, make_float4(0.0f, 0.0f, 0.0f, 0.0f)); diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index fc093ad8319..793fede0deb 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -48,25 +48,308 @@ #include "kernel/kernel_path_volume.h" #include "kernel/kernel_path_subsurface.h" +CCL_NAMESPACE_BEGIN + +ccl_device_forceinline bool kernel_path_scene_intersect( + KernelGlobals *kg, + ccl_addr_space PathState *state, + Ray *ray, + Intersection *isect, + PathRadiance *L) +{ + uint visibility = path_state_ray_visibility(kg, state); + +#ifdef __HAIR__ + float difl = 0.0f, extmax = 0.0f; + uint lcg_state = 0; + + if(kernel_data.bvh.have_curves) { + if((kernel_data.cam.resolution == 1) && (state->flag & PATH_RAY_CAMERA)) { + float3 pixdiff = ray->dD.dx + ray->dD.dy; + /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/ + difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f; + } + + extmax = kernel_data.curve.maximum_width; + lcg_state = lcg_state_init_addrspace(state, 0x51633e2d); + } + + if(path_state_ao_bounce(kg, state)) { + visibility = PATH_RAY_SHADOW; + ray->t = kernel_data.background.ao_distance; + } + + bool hit = scene_intersect(kg, *ray, visibility, isect, &lcg_state, difl, extmax); +#else + bool hit = scene_intersect(kg, *ray, visibility, isect, NULL, 0.0f, 0.0f); +#endif /* __HAIR__ */ + #ifdef __KERNEL_DEBUG__ -# include "kernel/kernel_debug.h" -#endif + if(state->flag & PATH_RAY_CAMERA) { + L->debug_data.num_bvh_traversed_nodes += isect->num_traversed_nodes; + L->debug_data.num_bvh_traversed_instances += isect->num_traversed_instances; + L->debug_data.num_bvh_intersections += isect->num_intersections; + } + L->debug_data.num_ray_bounces++; +#endif /* __KERNEL_DEBUG__ */ -CCL_NAMESPACE_BEGIN + return hit; +} + +ccl_device_forceinline void kernel_path_lamp_emission( + KernelGlobals *kg, + ccl_addr_space PathState *state, + Ray *ray, + float3 throughput, + ccl_addr_space Intersection *isect, + ShaderData *emission_sd, + PathRadiance *L) +{ +#ifdef __LAMP_MIS__ + if(kernel_data.integrator.use_lamp_mis && !(state->flag & PATH_RAY_CAMERA)) { + /* ray starting from previous non-transparent bounce */ + Ray light_ray; + + light_ray.P = ray->P - state->ray_t*ray->D; + state->ray_t += isect->t; + light_ray.D = ray->D; + light_ray.t = state->ray_t; + light_ray.time = ray->time; + light_ray.dD = ray->dD; + light_ray.dP = ray->dP; + + /* intersect with lamp */ + float3 emission; + + if(indirect_lamp_emission(kg, emission_sd, state, &light_ray, &emission)) + path_radiance_accum_emission(L, state, throughput, emission); + } +#endif /* __LAMP_MIS__ */ +} + +ccl_device_forceinline void kernel_path_background( + KernelGlobals *kg, + ccl_addr_space PathState *state, + ccl_addr_space Ray *ray, + float3 throughput, + ShaderData *emission_sd, + PathRadiance *L) +{ + /* eval background shader if nothing hit */ + if(kernel_data.background.transparent && (state->flag & PATH_RAY_CAMERA)) { + L->transparent += average(throughput); + +#ifdef __PASSES__ + if(!(kernel_data.film.pass_flag & PASS_BACKGROUND)) +#endif /* __PASSES__ */ + return; + } + +#ifdef __BACKGROUND__ + /* sample background shader */ + float3 L_background = indirect_background(kg, emission_sd, state, ray); + path_radiance_accum_background(L, state, throughput, L_background); +#endif /* __BACKGROUND__ */ +} + +#ifndef __SPLIT_KERNEL__ + +#ifdef __VOLUME__ +ccl_device_forceinline VolumeIntegrateResult kernel_path_volume( + KernelGlobals *kg, + ShaderData *sd, + PathState *state, + Ray *ray, + float3 *throughput, + ccl_addr_space Intersection *isect, + bool hit, + ShaderData *emission_sd, + PathRadiance *L) +{ + /* Sanitize volume stack. */ + if(!hit) { + kernel_volume_clean_stack(kg, state->volume_stack); + } + /* volume attenuation, emission, scatter */ + if(state->volume_stack[0].shader != SHADER_NONE) { + Ray volume_ray = *ray; + volume_ray.t = (hit)? isect->t: FLT_MAX; + + bool heterogeneous = volume_stack_is_heterogeneous(kg, state->volume_stack); + +# ifdef __VOLUME_DECOUPLED__ + int sampling_method = volume_stack_sampling_method(kg, state->volume_stack); + bool direct = (state->flag & PATH_RAY_CAMERA) != 0; + bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, direct, sampling_method); + + if(decoupled) { + /* cache steps along volume for repeated sampling */ + VolumeSegment volume_segment; + + shader_setup_from_volume(kg, sd, &volume_ray); + kernel_volume_decoupled_record(kg, state, + &volume_ray, sd, &volume_segment, heterogeneous); + + volume_segment.sampling_method = sampling_method; + + /* emission */ + if(volume_segment.closure_flag & SD_EMISSION) + path_radiance_accum_emission(L, state, *throughput, volume_segment.accum_emission); + + /* scattering */ + VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED; + + if(volume_segment.closure_flag & SD_SCATTER) { + int all = kernel_data.integrator.sample_all_lights_indirect; + + /* direct light sampling */ + kernel_branched_path_volume_connect_light(kg, sd, + emission_sd, *throughput, state, L, all, + &volume_ray, &volume_segment); + + /* indirect sample. if we use distance sampling and take just + * one sample for direct and indirect light, we could share + * this computation, but makes code a bit complex */ + float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL); + float rscatter = path_state_rng_1D(kg, state, PRNG_SCATTER_DISTANCE); + + result = kernel_volume_decoupled_scatter(kg, + state, &volume_ray, sd, throughput, + rphase, rscatter, &volume_segment, NULL, true); + } + + /* free cached steps */ + kernel_volume_decoupled_free(kg, &volume_segment); + + if(result == VOLUME_PATH_SCATTERED) { + if(kernel_path_volume_bounce(kg, sd, throughput, state, &L->state, ray)) + return VOLUME_PATH_SCATTERED; + else + return VOLUME_PATH_MISSED; + } + else { + *throughput *= volume_segment.accum_transmittance; + } + } + else +# endif /* __VOLUME_DECOUPLED__ */ + { + /* integrate along volume segment with distance sampling */ + VolumeIntegrateResult result = kernel_volume_integrate( + kg, state, sd, &volume_ray, L, throughput, heterogeneous); + +# ifdef __VOLUME_SCATTER__ + if(result == VOLUME_PATH_SCATTERED) { + /* direct lighting */ + kernel_path_volume_connect_light(kg, sd, emission_sd, *throughput, state, L); + + /* indirect light bounce */ + if(kernel_path_volume_bounce(kg, sd, throughput, state, &L->state, ray)) + return VOLUME_PATH_SCATTERED; + else + return VOLUME_PATH_MISSED; + } +# endif /* __VOLUME_SCATTER__ */ + } + } + + return VOLUME_PATH_ATTENUATED; +} +#endif /* __VOLUME__ */ + +#endif /* __SPLIT_KERNEL__ */ + +ccl_device_forceinline bool kernel_path_shader_apply( + KernelGlobals *kg, + ShaderData *sd, + ccl_addr_space PathState *state, + ccl_addr_space Ray *ray, + float3 throughput, + ShaderData *emission_sd, + PathRadiance *L, + ccl_global float *buffer) +{ +#ifdef __SHADOW_TRICKS__ + if((sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) { + if(state->flag & PATH_RAY_CAMERA) { + state->flag |= (PATH_RAY_SHADOW_CATCHER | + PATH_RAY_STORE_SHADOW_INFO); + + float3 bg = make_float3(0.0f, 0.0f, 0.0f); + if(!kernel_data.background.transparent) { + bg = indirect_background(kg, emission_sd, state, ray); + } + path_radiance_accum_shadowcatcher(L, throughput, bg); + } + } + else if(state->flag & PATH_RAY_SHADOW_CATCHER) { + /* Only update transparency after shadow catcher bounce. */ + L->shadow_transparency *= + average(shader_bsdf_transparency(kg, sd)); + } +#endif /* __SHADOW_TRICKS__ */ + + /* holdout */ +#ifdef __HOLDOUT__ + if(((sd->flag & SD_HOLDOUT) || + (sd->object_flag & SD_OBJECT_HOLDOUT_MASK)) && + (state->flag & PATH_RAY_CAMERA)) + { + if(kernel_data.background.transparent) { + float3 holdout_weight; + if(sd->object_flag & SD_OBJECT_HOLDOUT_MASK) { + holdout_weight = make_float3(1.0f, 1.0f, 1.0f); + } + else { + holdout_weight = shader_holdout_eval(kg, sd); + } + /* any throughput is ok, should all be identical here */ + L->transparent += average(holdout_weight*throughput); + } + + if(sd->object_flag & SD_OBJECT_HOLDOUT_MASK) { + return false; + } + } +#endif /* __HOLDOUT__ */ + + /* holdout mask objects do not write data passes */ + kernel_write_data_passes(kg, buffer, L, sd, state, throughput); + + /* blurring of bsdf after bounces, for rays that have a small likelihood + * of following this particular path (diffuse, rough glossy) */ + if(kernel_data.integrator.filter_glossy != FLT_MAX) { + float blur_pdf = kernel_data.integrator.filter_glossy*state->min_ray_pdf; + + if(blur_pdf < 1.0f) { + float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f; + shader_bsdf_blur(kg, sd, blur_roughness); + } + } + +#ifdef __EMISSION__ + /* emission */ + if(sd->flag & SD_EMISSION) { + float3 emission = indirect_primitive_emission(kg, sd, sd->ray_length, state->flag, state->ray_pdf); + path_radiance_accum_emission(L, state, throughput, emission); + } +#endif /* __EMISSION__ */ + + return true; +} ccl_device_noinline void kernel_path_ao(KernelGlobals *kg, ShaderData *sd, ShaderData *emission_sd, PathRadiance *L, ccl_addr_space PathState *state, - RNG *rng, float3 throughput, float3 ao_alpha) { /* todo: solve correlation */ float bsdf_u, bsdf_v; - path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); + path_state_rng_2D(kg, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); float ao_factor = kernel_data.background.ao_factor; float3 ao_N; @@ -83,13 +366,11 @@ ccl_device_noinline void kernel_path_ao(KernelGlobals *kg, light_ray.P = ray_offset(sd->P, sd->Ng); light_ray.D = ao_D; light_ray.t = kernel_data.background.ao_distance; -#ifdef __OBJECT_MOTION__ light_ray.time = sd->time; -#endif /* __OBJECT_MOTION__ */ light_ray.dP = sd->dP; light_ray.dD = differential3_zero(); - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) { + if(!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &ao_shadow)) { path_radiance_accum_ao(L, state, throughput, ao_alpha, ao_bsdf, ao_shadow); } else { @@ -100,265 +381,85 @@ ccl_device_noinline void kernel_path_ao(KernelGlobals *kg, #ifndef __SPLIT_KERNEL__ +#if defined(__BRANCHED_PATH__) || defined(__BAKING__) + ccl_device void kernel_path_indirect(KernelGlobals *kg, ShaderData *sd, ShaderData *emission_sd, - RNG *rng, Ray *ray, float3 throughput, - int num_samples, PathState *state, PathRadiance *L) { /* path iteration */ for(;;) { - /* intersect scene */ + /* Find intersection with objects in scene. */ Intersection isect; - uint visibility = path_state_ray_visibility(kg, state); - if(state->bounce > kernel_data.integrator.ao_bounces) { - visibility = PATH_RAY_SHADOW; - ray->t = kernel_data.background.ao_distance; - } - bool hit = scene_intersect(kg, - *ray, - visibility, - &isect, - NULL, - 0.0f, 0.0f); + bool hit = kernel_path_scene_intersect(kg, state, ray, &isect, L); -#ifdef __LAMP_MIS__ - if(kernel_data.integrator.use_lamp_mis && !(state->flag & PATH_RAY_CAMERA)) { - /* ray starting from previous non-transparent bounce */ - Ray light_ray; - - light_ray.P = ray->P - state->ray_t*ray->D; - state->ray_t += isect.t; - light_ray.D = ray->D; - light_ray.t = state->ray_t; - light_ray.time = ray->time; - light_ray.dD = ray->dD; - light_ray.dP = ray->dP; - - /* intersect with lamp */ - float3 emission; - if(indirect_lamp_emission(kg, emission_sd, state, &light_ray, &emission)) { - path_radiance_accum_emission(L, - throughput, - emission, - state->bounce); - } - } -#endif /* __LAMP_MIS__ */ + /* Find intersection with lamps and compute emission for MIS. */ + kernel_path_lamp_emission(kg, state, ray, throughput, &isect, emission_sd, L); #ifdef __VOLUME__ - /* Sanitize volume stack. */ - if(!hit) { - kernel_volume_clean_stack(kg, state->volume_stack); - } - /* volume attenuation, emission, scatter */ - if(state->volume_stack[0].shader != SHADER_NONE) { - Ray volume_ray = *ray; - volume_ray.t = (hit)? isect.t: FLT_MAX; - - bool heterogeneous = - volume_stack_is_heterogeneous(kg, - state->volume_stack); - -# ifdef __VOLUME_DECOUPLED__ - int sampling_method = - volume_stack_sampling_method(kg, - state->volume_stack); - bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, false, sampling_method); - - if(decoupled) { - /* cache steps along volume for repeated sampling */ - VolumeSegment volume_segment; - - shader_setup_from_volume(kg, - sd, - &volume_ray); - kernel_volume_decoupled_record(kg, - state, - &volume_ray, - sd, - &volume_segment, - heterogeneous); - - volume_segment.sampling_method = sampling_method; - - /* emission */ - if(volume_segment.closure_flag & SD_EMISSION) { - path_radiance_accum_emission(L, - throughput, - volume_segment.accum_emission, - state->bounce); - } - - /* scattering */ - VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED; - - if(volume_segment.closure_flag & SD_SCATTER) { - int all = kernel_data.integrator.sample_all_lights_indirect; - - /* direct light sampling */ - kernel_branched_path_volume_connect_light(kg, - rng, - sd, - emission_sd, - throughput, - state, - L, - all, - &volume_ray, - &volume_segment); - - /* indirect sample. if we use distance sampling and take just - * one sample for direct and indirect light, we could share - * this computation, but makes code a bit complex */ - float rphase = path_state_rng_1D_for_decision(kg, rng, state, PRNG_PHASE); - float rscatter = path_state_rng_1D_for_decision(kg, rng, state, PRNG_SCATTER_DISTANCE); - - result = kernel_volume_decoupled_scatter(kg, - state, - &volume_ray, - sd, - &throughput, - rphase, - rscatter, - &volume_segment, - NULL, - true); - } - - /* free cached steps */ - kernel_volume_decoupled_free(kg, &volume_segment); - - if(result == VOLUME_PATH_SCATTERED) { - if(kernel_path_volume_bounce(kg, - rng, - sd, - &throughput, - state, - L, - ray)) - { - continue; - } - else { - break; - } - } - else { - throughput *= volume_segment.accum_transmittance; - } - } - else -# endif /* __VOLUME_DECOUPLED__ */ - { - /* integrate along volume segment with distance sampling */ - VolumeIntegrateResult result = kernel_volume_integrate( - kg, state, sd, &volume_ray, L, &throughput, rng, heterogeneous); - -# ifdef __VOLUME_SCATTER__ - if(result == VOLUME_PATH_SCATTERED) { - /* direct lighting */ - kernel_path_volume_connect_light(kg, - rng, - sd, - emission_sd, - throughput, - state, - L); - - /* indirect light bounce */ - if(kernel_path_volume_bounce(kg, - rng, - sd, - &throughput, - state, - L, - ray)) - { - continue; - } - else { - break; - } - } -# endif /* __VOLUME_SCATTER__ */ - } + /* Volume integration. */ + VolumeIntegrateResult result = kernel_path_volume(kg, + sd, + state, + ray, + &throughput, + &isect, + hit, + emission_sd, + L); + + if(result == VOLUME_PATH_SCATTERED) { + continue; + } + else if(result == VOLUME_PATH_MISSED) { + break; } -#endif /* __VOLUME__ */ +#endif /* __VOLUME__*/ + /* Shade background. */ if(!hit) { -#ifdef __BACKGROUND__ - /* sample background shader */ - float3 L_background = indirect_background(kg, emission_sd, state, ray); - path_radiance_accum_background(L, - state, - throughput, - L_background); -#endif /* __BACKGROUND__ */ - + kernel_path_background(kg, state, ray, throughput, emission_sd, L); break; } - else if(state->bounce > kernel_data.integrator.ao_bounces) { + else if(path_state_ao_bounce(kg, state)) { break; } - /* setup shading */ + /* Setup and evaluate shader. */ shader_setup_from_ray(kg, sd, &isect, ray); - float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF); - shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); -#ifdef __BRANCHED_PATH__ - shader_merge_closures(sd); -#endif /* __BRANCHED_PATH__ */ - -#ifdef __SHADOW_TRICKS__ - if(!(sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) { - state->flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; - } -#endif /* __SHADOW_TRICKS__ */ - - /* blurring of bsdf after bounces, for rays that have a small likelihood - * of following this particular path (diffuse, rough glossy) */ - if(kernel_data.integrator.filter_glossy != FLT_MAX) { - float blur_pdf = kernel_data.integrator.filter_glossy*state->min_ray_pdf; - - if(blur_pdf < 1.0f) { - float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f; - shader_bsdf_blur(kg, sd, blur_roughness); - } - } - -#ifdef __EMISSION__ - /* emission */ - if(sd->flag & SD_EMISSION) { - float3 emission = indirect_primitive_emission(kg, - sd, - isect.t, - state->flag, - state->ray_pdf); - path_radiance_accum_emission(L, throughput, emission, state->bounce); + shader_eval_surface(kg, sd, state, state->flag); + shader_prepare_closures(sd, state); + + /* Apply shadow catcher, holdout, emission. */ + if(!kernel_path_shader_apply(kg, + sd, + state, + ray, + throughput, + emission_sd, + L, + NULL)) + { + break; } -#endif /* __EMISSION__ */ /* path termination. this is a strange place to put the termination, it's * mainly due to the mixed in MIS that we use. gives too many unneeded * shader evaluations, only need emission if we are going to terminate */ - float probability = - path_state_terminate_probability(kg, - state, - throughput*num_samples); + float probability = path_state_continuation_probability(kg, state, throughput); if(probability == 0.0f) { break; } else if(probability != 1.0f) { - float terminate = path_state_rng_1D_for_decision(kg, rng, state, PRNG_TERMINATE); + float terminate = path_state_rng_1D(kg, state, PRNG_TERMINATE); if(terminate >= probability) break; @@ -371,7 +472,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, #ifdef __AO__ /* ambient occlusion */ if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) { - kernel_path_ao(kg, sd, emission_sd, L, state, rng, throughput, make_float3(0.0f, 0.0f, 0.0f)); + kernel_path_ao(kg, sd, emission_sd, L, state, throughput, make_float3(0.0f, 0.0f, 0.0f)); } #endif /* __AO__ */ @@ -379,22 +480,18 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, /* bssrdf scatter to a different location on the same object, replacing * the closures with a diffuse BSDF */ if(sd->flag & SD_BSSRDF) { - float bssrdf_probability; - ShaderClosure *sc = subsurface_scatter_pick_closure(kg, sd, &bssrdf_probability); + float bssrdf_u, bssrdf_v; + path_state_rng_2D(kg, + state, + PRNG_BSDF_U, + &bssrdf_u, &bssrdf_v); - /* modify throughput for picking bssrdf or bsdf */ - throughput *= bssrdf_probability; + const ShaderClosure *sc = shader_bssrdf_pick(sd, &throughput, &bssrdf_u); /* do bssrdf scatter step if we picked a bssrdf closure */ if(sc) { - uint lcg_state = lcg_state_init(rng, state->rng_offset, state->sample, 0x68bc21eb); - - float bssrdf_u, bssrdf_v; - path_state_rng_2D(kg, - rng, - state, - PRNG_BSDF_U, - &bssrdf_u, &bssrdf_v); + uint lcg_state = lcg_state_init(state, 0x68bc21eb); + subsurface_scatter_step(kg, sd, state, @@ -412,7 +509,6 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, int all = (kernel_data.integrator.sample_all_lights_indirect) || (state->flag & PATH_RAY_SHADOW_CATCHER); kernel_branched_path_surface_connect_light(kg, - rng, sd, emission_sd, state, @@ -423,38 +519,24 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, } #endif /* defined(__EMISSION__) */ - if(!kernel_path_surface_bounce(kg, rng, sd, &throughput, state, L, ray)) + if(!kernel_path_surface_bounce(kg, sd, &throughput, state, &L->state, ray)) break; } } +#endif /* defined(__BRANCHED_PATH__) || defined(__BAKING__) */ -ccl_device_inline float kernel_path_integrate(KernelGlobals *kg, - RNG *rng, - int sample, - Ray ray, - ccl_global float *buffer, - PathRadiance *L, - bool *is_shadow_catcher) +ccl_device_forceinline void kernel_path_integrate( + KernelGlobals *kg, + PathState *state, + float3 throughput, + Ray *ray, + PathRadiance *L, + ccl_global float *buffer, + ShaderData *emission_sd) { - /* initialize */ - float3 throughput = make_float3(1.0f, 1.0f, 1.0f); - float L_transparent = 0.0f; - - path_radiance_init(L, kernel_data.film.use_light_pass); - - /* shader data memory used for both volumes and surfaces, saves stack space */ + /* Shader data memory used for both volumes and surfaces, saves stack space. */ ShaderData sd; - /* shader data used by emission, shadows, volume stacks */ - ShaderData emission_sd; - - PathState state; - path_state_init(kg, &emission_sd, &state, rng, sample, &ray); - -#ifdef __KERNEL_DEBUG__ - DebugData debug_data; - debug_data_init(&debug_data); -#endif /* __KERNEL_DEBUG__ */ #ifdef __SUBSURFACE__ SubsurfaceIndirectRays ss_indirect; @@ -465,265 +547,82 @@ ccl_device_inline float kernel_path_integrate(KernelGlobals *kg, /* path iteration */ for(;;) { - /* intersect scene */ + /* Find intersection with objects in scene. */ Intersection isect; - uint visibility = path_state_ray_visibility(kg, &state); - -#ifdef __HAIR__ - float difl = 0.0f, extmax = 0.0f; - uint lcg_state = 0; - - if(kernel_data.bvh.have_curves) { - if((kernel_data.cam.resolution == 1) && (state.flag & PATH_RAY_CAMERA)) { - float3 pixdiff = ray.dD.dx + ray.dD.dy; - /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/ - difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f; - } - - extmax = kernel_data.curve.maximum_width; - lcg_state = lcg_state_init(rng, state.rng_offset, state.sample, 0x51633e2d); - } - - if(state.bounce > kernel_data.integrator.ao_bounces) { - visibility = PATH_RAY_SHADOW; - ray.t = kernel_data.background.ao_distance; - } - - bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax); -#else - bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f); -#endif /* __HAIR__ */ + bool hit = kernel_path_scene_intersect(kg, state, ray, &isect, L); -#ifdef __KERNEL_DEBUG__ - if(state.flag & PATH_RAY_CAMERA) { - debug_data.num_bvh_traversed_nodes += isect.num_traversed_nodes; - debug_data.num_bvh_traversed_instances += isect.num_traversed_instances; - debug_data.num_bvh_intersections += isect.num_intersections; - } - debug_data.num_ray_bounces++; -#endif /* __KERNEL_DEBUG__ */ - -#ifdef __LAMP_MIS__ - if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) { - /* ray starting from previous non-transparent bounce */ - Ray light_ray; - - light_ray.P = ray.P - state.ray_t*ray.D; - state.ray_t += isect.t; - light_ray.D = ray.D; - light_ray.t = state.ray_t; - light_ray.time = ray.time; - light_ray.dD = ray.dD; - light_ray.dP = ray.dP; - - /* intersect with lamp */ - float3 emission; - - if(indirect_lamp_emission(kg, &emission_sd, &state, &light_ray, &emission)) - path_radiance_accum_emission(L, throughput, emission, state.bounce); - } -#endif /* __LAMP_MIS__ */ + /* Find intersection with lamps and compute emission for MIS. */ + kernel_path_lamp_emission(kg, state, ray, throughput, &isect, emission_sd, L); #ifdef __VOLUME__ - /* Sanitize volume stack. */ - if(!hit) { - kernel_volume_clean_stack(kg, state.volume_stack); - } - /* volume attenuation, emission, scatter */ - if(state.volume_stack[0].shader != SHADER_NONE) { - Ray volume_ray = ray; - volume_ray.t = (hit)? isect.t: FLT_MAX; - - bool heterogeneous = volume_stack_is_heterogeneous(kg, state.volume_stack); - -# ifdef __VOLUME_DECOUPLED__ - int sampling_method = volume_stack_sampling_method(kg, state.volume_stack); - bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, true, sampling_method); - - if(decoupled) { - /* cache steps along volume for repeated sampling */ - VolumeSegment volume_segment; - - shader_setup_from_volume(kg, &sd, &volume_ray); - kernel_volume_decoupled_record(kg, &state, - &volume_ray, &sd, &volume_segment, heterogeneous); - - volume_segment.sampling_method = sampling_method; - - /* emission */ - if(volume_segment.closure_flag & SD_EMISSION) - path_radiance_accum_emission(L, throughput, volume_segment.accum_emission, state.bounce); - - /* scattering */ - VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED; - - if(volume_segment.closure_flag & SD_SCATTER) { - int all = false; - - /* direct light sampling */ - kernel_branched_path_volume_connect_light(kg, rng, &sd, - &emission_sd, throughput, &state, L, all, - &volume_ray, &volume_segment); - - /* indirect sample. if we use distance sampling and take just - * one sample for direct and indirect light, we could share - * this computation, but makes code a bit complex */ - float rphase = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_PHASE); - float rscatter = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_SCATTER_DISTANCE); - - result = kernel_volume_decoupled_scatter(kg, - &state, &volume_ray, &sd, &throughput, - rphase, rscatter, &volume_segment, NULL, true); - } - - /* free cached steps */ - kernel_volume_decoupled_free(kg, &volume_segment); - - if(result == VOLUME_PATH_SCATTERED) { - if(kernel_path_volume_bounce(kg, rng, &sd, &throughput, &state, L, &ray)) - continue; - else - break; - } - else { - throughput *= volume_segment.accum_transmittance; - } - } - else -# endif /* __VOLUME_DECOUPLED__ */ - { - /* integrate along volume segment with distance sampling */ - VolumeIntegrateResult result = kernel_volume_integrate( - kg, &state, &sd, &volume_ray, L, &throughput, rng, heterogeneous); - -# ifdef __VOLUME_SCATTER__ - if(result == VOLUME_PATH_SCATTERED) { - /* direct lighting */ - kernel_path_volume_connect_light(kg, rng, &sd, &emission_sd, throughput, &state, L); - - /* indirect light bounce */ - if(kernel_path_volume_bounce(kg, rng, &sd, &throughput, &state, L, &ray)) - continue; - else - break; - } -# endif /* __VOLUME_SCATTER__ */ - } + /* Volume integration. */ + VolumeIntegrateResult result = kernel_path_volume(kg, + &sd, + state, + ray, + &throughput, + &isect, + hit, + emission_sd, + L); + + if(result == VOLUME_PATH_SCATTERED) { + continue; + } + else if(result == VOLUME_PATH_MISSED) { + break; } -#endif /* __VOLUME__ */ +#endif /* __VOLUME__*/ + /* Shade background. */ if(!hit) { - /* eval background shader if nothing hit */ - if(kernel_data.background.transparent && (state.flag & PATH_RAY_CAMERA)) { - L_transparent += average(throughput); - -#ifdef __PASSES__ - if(!(kernel_data.film.pass_flag & PASS_BACKGROUND)) -#endif /* __PASSES__ */ - break; - } - -#ifdef __BACKGROUND__ - /* sample background shader */ - float3 L_background = indirect_background(kg, &emission_sd, &state, &ray); - path_radiance_accum_background(L, &state, throughput, L_background); -#endif /* __BACKGROUND__ */ - + kernel_path_background(kg, state, ray, throughput, emission_sd, L); break; } - else if(state.bounce > kernel_data.integrator.ao_bounces) { + else if(path_state_ao_bounce(kg, state)) { break; } - /* setup shading */ - shader_setup_from_ray(kg, &sd, &isect, &ray); - float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF); - shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); - -#ifdef __SHADOW_TRICKS__ - if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) { - if(state.flag & PATH_RAY_CAMERA) { - state.flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_SHADOW_CATCHER_ONLY | PATH_RAY_STORE_SHADOW_INFO); - state.catcher_object = sd.object; - if(!kernel_data.background.transparent) { - L->shadow_color = indirect_background(kg, &emission_sd, &state, &ray); - } - } - } - else { - state.flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; - } -#endif /* __SHADOW_TRICKS__ */ - - /* holdout */ -#ifdef __HOLDOUT__ - if(((sd.flag & SD_HOLDOUT) || - (sd.object_flag & SD_OBJECT_HOLDOUT_MASK)) && - (state.flag & PATH_RAY_CAMERA)) + /* Setup and evaluate shader. */ + shader_setup_from_ray(kg, &sd, &isect, ray); + shader_eval_surface(kg, &sd, state, state->flag); + shader_prepare_closures(&sd, state); + + /* Apply shadow catcher, holdout, emission. */ + if(!kernel_path_shader_apply(kg, + &sd, + state, + ray, + throughput, + emission_sd, + L, + buffer)) { - if(kernel_data.background.transparent) { - float3 holdout_weight; - if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) { - holdout_weight = make_float3(1.0f, 1.0f, 1.0f); - } - else { - holdout_weight = shader_holdout_eval(kg, &sd); - } - /* any throughput is ok, should all be identical here */ - L_transparent += average(holdout_weight*throughput); - } - - if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) { - break; - } - } -#endif /* __HOLDOUT__ */ - - /* holdout mask objects do not write data passes */ - kernel_write_data_passes(kg, buffer, L, &sd, sample, &state, throughput); - - /* blurring of bsdf after bounces, for rays that have a small likelihood - * of following this particular path (diffuse, rough glossy) */ - if(kernel_data.integrator.filter_glossy != FLT_MAX) { - float blur_pdf = kernel_data.integrator.filter_glossy*state.min_ray_pdf; - - if(blur_pdf < 1.0f) { - float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f; - shader_bsdf_blur(kg, &sd, blur_roughness); - } - } - -#ifdef __EMISSION__ - /* emission */ - if(sd.flag & SD_EMISSION) { - /* todo: is isect.t wrong here for transparent surfaces? */ - float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf); - path_radiance_accum_emission(L, throughput, emission, state.bounce); + break; } -#endif /* __EMISSION__ */ /* path termination. this is a strange place to put the termination, it's * mainly due to the mixed in MIS that we use. gives too many unneeded * shader evaluations, only need emission if we are going to terminate */ - float probability = path_state_terminate_probability(kg, &state, throughput); + float probability = path_state_continuation_probability(kg, state, throughput); if(probability == 0.0f) { break; } else if(probability != 1.0f) { - float terminate = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_TERMINATE); + float terminate = path_state_rng_1D(kg, state, PRNG_TERMINATE); if(terminate >= probability) break; throughput /= probability; } - kernel_update_denoising_features(kg, &sd, &state, L); + kernel_update_denoising_features(kg, &sd, state, L); #ifdef __AO__ /* ambient occlusion */ if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { - kernel_path_ao(kg, &sd, &emission_sd, L, &state, rng, throughput, shader_bsdf_alpha(kg, &sd)); + kernel_path_ao(kg, &sd, emission_sd, L, state, throughput, shader_bsdf_alpha(kg, &sd)); } #endif /* __AO__ */ @@ -733,11 +632,10 @@ ccl_device_inline float kernel_path_integrate(KernelGlobals *kg, if(sd.flag & SD_BSSRDF) { if(kernel_path_subsurface_scatter(kg, &sd, - &emission_sd, + emission_sd, L, - &state, - rng, - &ray, + state, + ray, &throughput, &ss_indirect)) { @@ -747,24 +645,22 @@ ccl_device_inline float kernel_path_integrate(KernelGlobals *kg, #endif /* __SUBSURFACE__ */ /* direct lighting */ - kernel_path_surface_connect_light(kg, rng, &sd, &emission_sd, throughput, &state, L); + kernel_path_surface_connect_light(kg, &sd, emission_sd, throughput, state, L); /* compute direct lighting and next bounce */ - if(!kernel_path_surface_bounce(kg, rng, &sd, &throughput, &state, L, &ray)) + if(!kernel_path_surface_bounce(kg, &sd, &throughput, state, &L->state, ray)) break; } #ifdef __SUBSURFACE__ - kernel_path_subsurface_accum_indirect(&ss_indirect, L); - /* Trace indirect subsurface rays by restarting the loop. this uses less * stack memory than invoking kernel_path_indirect. */ if(ss_indirect.num_rays) { kernel_path_subsurface_setup_indirect(kg, &ss_indirect, - &state, - &ray, + state, + ray, L, &throughput); } @@ -773,16 +669,6 @@ ccl_device_inline float kernel_path_integrate(KernelGlobals *kg, } } #endif /* __SUBSURFACE__ */ - -#ifdef __SHADOW_TRICKS__ - *is_shadow_catcher = (state.flag & PATH_RAY_SHADOW_CATCHER); -#endif /* __SHADOW_TRICKS__ */ - -#ifdef __KERNEL_DEBUG__ - kernel_write_debug_passes(kg, buffer, &state, &debug_data, sample); -#endif /* __KERNEL_DEBUG__ */ - - return 1.0f - L_transparent; } ccl_device void kernel_path_trace(KernelGlobals *kg, @@ -796,25 +682,37 @@ ccl_device void kernel_path_trace(KernelGlobals *kg, rng_state += index; buffer += index*pass_stride; - /* initialize random numbers and ray */ - RNG rng; + /* Initialize random numbers and sample ray. */ + uint rng_hash; Ray ray; - kernel_path_trace_setup(kg, rng_state, sample, x, y, &rng, &ray); - - /* integrate */ - PathRadiance L; - bool is_shadow_catcher; + kernel_path_trace_setup(kg, rng_state, sample, x, y, &rng_hash, &ray); - if(ray.t != 0.0f) { - float alpha = kernel_path_integrate(kg, &rng, sample, ray, buffer, &L, &is_shadow_catcher); - kernel_write_result(kg, buffer, sample, &L, alpha, is_shadow_catcher); - } - else { - kernel_write_result(kg, buffer, sample, NULL, 0.0f, false); + if(ray.t == 0.0f) { + kernel_write_result(kg, buffer, sample, NULL); + return; } - path_rng_end(kg, rng_state, rng); + /* Initialize state. */ + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + + PathRadiance L; + path_radiance_init(&L, kernel_data.film.use_light_pass); + + ShaderData emission_sd; + PathState state; + path_state_init(kg, &emission_sd, &state, rng_hash, sample, &ray); + + /* Integrate. */ + kernel_path_integrate(kg, + &state, + throughput, + &ray, + &L, + buffer, + &emission_sd); + + kernel_write_result(kg, buffer, sample, &L); } #endif /* __SPLIT_KERNEL__ */ diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index 10816d3e5d1..6e0ec22d581 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -23,7 +23,6 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg, ShaderData *emission_sd, PathRadiance *L, ccl_addr_space PathState *state, - RNG *rng, float3 throughput) { int num_samples = kernel_data.integrator.ao_samples; @@ -35,7 +34,7 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg, for(int j = 0; j < num_samples; j++) { float bsdf_u, bsdf_v; - path_branched_rng_2D(kg, rng, state, j, num_samples, PRNG_BSDF_U, &bsdf_u, &bsdf_v); + path_branched_rng_2D(kg, state->rng_hash, state, j, num_samples, PRNG_BSDF_U, &bsdf_u, &bsdf_v); float3 ao_D; float ao_pdf; @@ -49,13 +48,11 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg, light_ray.P = ray_offset(sd->P, sd->Ng); light_ray.D = ao_D; light_ray.t = kernel_data.background.ao_distance; -#ifdef __OBJECT_MOTION__ light_ray.time = sd->time; -#endif /* __OBJECT_MOTION__ */ light_ray.dP = sd->dP; light_ray.dD = differential3_zero(); - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) { + if(!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &ao_shadow)) { path_radiance_accum_ao(L, state, throughput*num_samples_inv, ao_alpha, ao_bsdf, ao_shadow); } else { @@ -69,7 +66,7 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg, /* bounce off surface and integrate indirect light */ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGlobals *kg, - RNG *rng, ShaderData *sd, ShaderData *indirect_sd, ShaderData *emission_sd, + ShaderData *sd, ShaderData *indirect_sd, ShaderData *emission_sd, float3 throughput, float num_samples_adjust, PathState *state, PathRadiance *L) { float sum_sample_weight = 0.0f; @@ -113,35 +110,38 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba num_samples = ceil_to_int(num_samples_adjust*num_samples); float num_samples_inv = num_samples_adjust/num_samples; - RNG bsdf_rng = cmj_hash(*rng, i); for(int j = 0; j < num_samples; j++) { PathState ps = *state; float3 tp = throughput; Ray bsdf_ray; +#ifdef __SHADOW_TRICKS__ + float shadow_transparency = L->shadow_transparency; +#endif + + ps.rng_hash = cmj_hash(state->rng_hash, i); if(!kernel_branched_path_surface_bounce(kg, - &bsdf_rng, sd, sc, j, num_samples, &tp, &ps, - L, + &L->state, &bsdf_ray, sum_sample_weight)) { continue; } + ps.rng_hash = state->rng_hash; + kernel_path_indirect(kg, indirect_sd, emission_sd, - rng, &bsdf_ray, tp*num_samples_inv, - num_samples, &ps, L); @@ -149,6 +149,10 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba * for the next samples */ path_radiance_sum_indirect(L); path_radiance_reset_indirect(L); + +#ifdef __SHADOW_TRICKS__ + L->shadow_transparency = shadow_transparency; +#endif } } } @@ -160,7 +164,6 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, ShaderData *emission_sd, PathRadiance *L, PathState *state, - RNG *rng, Ray *ray, float3 throughput) { @@ -171,17 +174,17 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, continue; /* set up random number generator */ - uint lcg_state = lcg_state_init(rng, state->rng_offset, state->sample, 0x68bc21eb); + uint lcg_state = lcg_state_init(state, 0x68bc21eb); int num_samples = kernel_data.integrator.subsurface_samples; float num_samples_inv = 1.0f/num_samples; - RNG bssrdf_rng = cmj_hash(*rng, i); + uint bssrdf_rng_hash = cmj_hash(state->rng_hash, i); /* do subsurface scatter step with copy of shader data, this will * replace the BSSRDF with a diffuse BSDF closure */ for(int j = 0; j < num_samples; j++) { SubsurfaceIntersection ss_isect; float bssrdf_u, bssrdf_v; - path_branched_rng_2D(kg, &bssrdf_rng, state, j, num_samples, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v); + path_branched_rng_2D(kg, bssrdf_rng_hash, state, j, num_samples, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v); int num_hits = subsurface_scatter_multi_intersect(kg, &ss_isect, sd, @@ -234,7 +237,6 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, (state->flag & PATH_RAY_SHADOW_CATCHER); kernel_branched_path_surface_connect_light( kg, - rng, &bssrdf_sd, emission_sd, &hit_state, @@ -248,7 +250,6 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, /* indirect light */ kernel_branched_path_surface_indirect_light( kg, - rng, &bssrdf_sd, indirect_sd, emission_sd, @@ -262,17 +263,15 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, } #endif /* __SUBSURFACE__ */ -ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, - RNG *rng, - int sample, - Ray ray, - ccl_global float *buffer, - PathRadiance *L, - bool *is_shadow_catcher) +ccl_device void kernel_branched_path_integrate(KernelGlobals *kg, + uint rng_hash, + int sample, + Ray ray, + ccl_global float *buffer, + PathRadiance *L) { /* initialize */ float3 throughput = make_float3(1.0f, 1.0f, 1.0f); - float L_transparent = 0.0f; path_radiance_init(L, kernel_data.film.use_light_pass); @@ -282,48 +281,16 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, ShaderData emission_sd, indirect_sd; PathState state; - path_state_init(kg, &emission_sd, &state, rng, sample, &ray); - -#ifdef __KERNEL_DEBUG__ - DebugData debug_data; - debug_data_init(&debug_data); -#endif /* __KERNEL_DEBUG__ */ + path_state_init(kg, &emission_sd, &state, rng_hash, sample, &ray); /* Main Loop * Here we only handle transparency intersections from the camera ray. * Indirect bounces are handled in kernel_branched_path_surface_indirect_light(). */ for(;;) { - /* intersect scene */ + /* Find intersection with objects in scene. */ Intersection isect; - uint visibility = path_state_ray_visibility(kg, &state); - -#ifdef __HAIR__ - float difl = 0.0f, extmax = 0.0f; - uint lcg_state = 0; - - if(kernel_data.bvh.have_curves) { - if(kernel_data.cam.resolution == 1) { - float3 pixdiff = ray.dD.dx + ray.dD.dy; - /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/ - difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f; - } - - extmax = kernel_data.curve.maximum_width; - lcg_state = lcg_state_init(rng, state.rng_offset, state.sample, 0x51633e2d); - } - - bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax); -#else - bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f); -#endif /* __HAIR__ */ - -#ifdef __KERNEL_DEBUG__ - debug_data.num_bvh_traversed_nodes += isect.num_traversed_nodes; - debug_data.num_bvh_traversed_instances += isect.num_traversed_instances; - debug_data.num_bvh_intersections += isect.num_intersections; - debug_data.num_ray_bounces++; -#endif /* __KERNEL_DEBUG__ */ + bool hit = kernel_path_scene_intersect(kg, &state, &ray, &isect, L); #ifdef __VOLUME__ /* Sanitize volume stack. */ @@ -353,7 +320,7 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, int all = kernel_data.integrator.sample_all_lights_direct; - kernel_branched_path_volume_connect_light(kg, rng, &sd, + kernel_branched_path_volume_connect_light(kg, &sd, &emission_sd, throughput, &state, L, all, &volume_ray, &volume_segment); @@ -372,30 +339,25 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, /* scatter sample. if we use distance sampling and take just one * sample for direct and indirect light, we could share this * computation, but makes code a bit complex */ - float rphase = path_state_rng_1D_for_decision(kg, rng, &ps, PRNG_PHASE); - float rscatter = path_state_rng_1D_for_decision(kg, rng, &ps, PRNG_SCATTER_DISTANCE); + float rphase = path_state_rng_1D(kg, &ps, PRNG_PHASE_CHANNEL); + float rscatter = path_state_rng_1D(kg, &ps, PRNG_SCATTER_DISTANCE); VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg, &ps, &pray, &sd, &tp, rphase, rscatter, &volume_segment, NULL, false); - (void)result; - kernel_assert(result == VOLUME_PATH_SCATTERED); - - if(kernel_path_volume_bounce(kg, - rng, + if(result == VOLUME_PATH_SCATTERED && + kernel_path_volume_bounce(kg, &sd, &tp, &ps, - L, + &L->state, &pray)) { kernel_path_indirect(kg, &indirect_sd, &emission_sd, - rng, &pray, tp*num_samples_inv, - num_samples, &ps, L); @@ -409,7 +371,7 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, /* emission and transmittance */ if(volume_segment.closure_flag & SD_EMISSION) - path_radiance_accum_emission(L, throughput, volume_segment.accum_emission, state.bounce); + path_radiance_accum_emission(L, &state, throughput, volume_segment.accum_emission); throughput *= volume_segment.accum_transmittance; /* free cached steps */ @@ -431,29 +393,26 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, path_state_branch(&ps, j, num_samples); VolumeIntegrateResult result = kernel_volume_integrate( - kg, &ps, &sd, &volume_ray, L, &tp, rng, heterogeneous); + kg, &ps, &sd, &volume_ray, L, &tp, heterogeneous); #ifdef __VOLUME_SCATTER__ if(result == VOLUME_PATH_SCATTERED) { /* todo: support equiangular, MIS and all light sampling. * alternatively get decoupled ray marching working on the GPU */ - kernel_path_volume_connect_light(kg, rng, &sd, &emission_sd, tp, &state, L); + kernel_path_volume_connect_light(kg, &sd, &emission_sd, tp, &state, L); if(kernel_path_volume_bounce(kg, - rng, &sd, &tp, &ps, - L, + &L->state, &pray)) { kernel_path_indirect(kg, &indirect_sd, &emission_sd, - rng, &pray, tp, - num_samples, &ps, L); @@ -472,89 +431,42 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, } #endif /* __VOLUME__ */ + /* Shade background. */ if(!hit) { - /* eval background shader if nothing hit */ - if(kernel_data.background.transparent) { - L_transparent += average(throughput); - -#ifdef __PASSES__ - if(!(kernel_data.film.pass_flag & PASS_BACKGROUND)) -#endif /* __PASSES__ */ - break; - } - -#ifdef __BACKGROUND__ - /* sample background shader */ - float3 L_background = indirect_background(kg, &emission_sd, &state, &ray); - path_radiance_accum_background(L, &state, throughput, L_background); -#endif /* __BACKGROUND__ */ - + kernel_path_background(kg, &state, &ray, throughput, &emission_sd, L); break; } - /* setup shading */ + /* Setup and evaluate shader. */ shader_setup_from_ray(kg, &sd, &isect, &ray); - shader_eval_surface(kg, &sd, rng, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, &state, state.flag); shader_merge_closures(&sd); -#ifdef __SHADOW_TRICKS__ - if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) { - if(state.flag & PATH_RAY_CAMERA) { - state.flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_SHADOW_CATCHER_ONLY | PATH_RAY_STORE_SHADOW_INFO); - state.catcher_object = sd.object; - if(!kernel_data.background.transparent) { - L->shadow_color = indirect_background(kg, &emission_sd, &state, &ray); - } - } - } - else { - state.flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; - } -#endif /* __SHADOW_TRICKS__ */ - - /* holdout */ -#ifdef __HOLDOUT__ - if((sd.flag & SD_HOLDOUT) || (sd.object_flag & SD_OBJECT_HOLDOUT_MASK)) { - if(kernel_data.background.transparent) { - float3 holdout_weight; - if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) { - holdout_weight = make_float3(1.0f, 1.0f, 1.0f); - } - else { - holdout_weight = shader_holdout_eval(kg, &sd); - } - /* any throughput is ok, should all be identical here */ - L_transparent += average(holdout_weight*throughput); - } - if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) { - break; - } - } -#endif /* __HOLDOUT__ */ - - /* holdout mask objects do not write data passes */ - kernel_write_data_passes(kg, buffer, L, &sd, sample, &state, throughput); - -#ifdef __EMISSION__ - /* emission */ - if(sd.flag & SD_EMISSION) { - float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf); - path_radiance_accum_emission(L, throughput, emission, state.bounce); + /* Apply shadow catcher, holdout, emission. */ + if(!kernel_path_shader_apply(kg, + &sd, + &state, + &ray, + throughput, + &emission_sd, + L, + buffer)) + { + break; } -#endif /* __EMISSION__ */ /* transparency termination */ if(state.flag & PATH_RAY_TRANSPARENT) { /* path termination. this is a strange place to put the termination, it's * mainly due to the mixed in MIS that we use. gives too many unneeded * shader evaluations, only need emission if we are going to terminate */ - float probability = path_state_terminate_probability(kg, &state, throughput); + float probability = path_state_continuation_probability(kg, &state, throughput); if(probability == 0.0f) { break; } else if(probability != 1.0f) { - float terminate = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_TERMINATE); + float terminate = path_state_rng_1D(kg, &state, PRNG_TERMINATE); if(terminate >= probability) break; @@ -568,7 +480,7 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, #ifdef __AO__ /* ambient occlusion */ if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { - kernel_branched_path_ao(kg, &sd, &emission_sd, L, &state, rng, throughput); + kernel_branched_path_ao(kg, &sd, &emission_sd, L, &state, throughput); } #endif /* __AO__ */ @@ -576,7 +488,7 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, /* bssrdf scatter to a different location on the same object */ if(sd.flag & SD_BSSRDF) { kernel_branched_path_subsurface_scatter(kg, &sd, &indirect_sd, &emission_sd, - L, &state, rng, &ray, throughput); + L, &state, &ray, throughput); } #endif /* __SUBSURFACE__ */ @@ -588,13 +500,13 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, if(kernel_data.integrator.use_direct_light) { int all = (kernel_data.integrator.sample_all_lights_direct) || (state.flag & PATH_RAY_SHADOW_CATCHER); - kernel_branched_path_surface_connect_light(kg, rng, + kernel_branched_path_surface_connect_light(kg, &sd, &emission_sd, &hit_state, throughput, 1.0f, L, all); } #endif /* __EMISSION__ */ /* indirect light */ - kernel_branched_path_surface_indirect_light(kg, rng, + kernel_branched_path_surface_indirect_light(kg, &sd, &indirect_sd, &emission_sd, throughput, 1.0f, &hit_state, L); /* continue in case of transparency */ @@ -623,16 +535,6 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack); #endif /* __VOLUME__ */ } - -#ifdef __SHADOW_TRICKS__ - *is_shadow_catcher = (state.flag & PATH_RAY_SHADOW_CATCHER); -#endif /* __SHADOW_TRICKS__ */ - -#ifdef __KERNEL_DEBUG__ - kernel_write_debug_passes(kg, buffer, &state, &debug_data, sample); -#endif /* __KERNEL_DEBUG__ */ - - return 1.0f - L_transparent; } ccl_device void kernel_branched_path_trace(KernelGlobals *kg, @@ -647,24 +549,21 @@ ccl_device void kernel_branched_path_trace(KernelGlobals *kg, buffer += index*pass_stride; /* initialize random numbers and ray */ - RNG rng; + uint rng_hash; Ray ray; - kernel_path_trace_setup(kg, rng_state, sample, x, y, &rng, &ray); + kernel_path_trace_setup(kg, rng_state, sample, x, y, &rng_hash, &ray); /* integrate */ PathRadiance L; - bool is_shadow_catcher; if(ray.t != 0.0f) { - float alpha = kernel_branched_path_integrate(kg, &rng, sample, ray, buffer, &L, &is_shadow_catcher); - kernel_write_result(kg, buffer, sample, &L, alpha, is_shadow_catcher); + kernel_branched_path_integrate(kg, rng_hash, sample, ray, buffer, &L); + kernel_write_result(kg, buffer, sample, &L); } else { - kernel_write_result(kg, buffer, sample, NULL, 0.0f, false); + kernel_write_result(kg, buffer, sample, NULL); } - - path_rng_end(kg, rng_state, rng); } #endif /* __SPLIT_KERNEL__ */ diff --git a/intern/cycles/kernel/kernel_path_common.h b/intern/cycles/kernel/kernel_path_common.h index 82f83deb595..54dd278a185 100644 --- a/intern/cycles/kernel/kernel_path_common.h +++ b/intern/cycles/kernel/kernel_path_common.h @@ -22,7 +22,7 @@ ccl_device_inline void kernel_path_trace_setup(KernelGlobals *kg, ccl_global uint *rng_state, int sample, int x, int y, - RNG *rng, + uint *rng_hash, ccl_addr_space Ray *ray) { float filter_u; @@ -34,20 +34,20 @@ ccl_device_inline void kernel_path_trace_setup(KernelGlobals *kg, *rng_state = hash_int_2d(x, y); } - path_rng_init(kg, rng_state, sample, num_samples, rng, x, y, &filter_u, &filter_v); + path_rng_init(kg, rng_state, sample, num_samples, rng_hash, x, y, &filter_u, &filter_v); /* sample camera ray */ float lens_u = 0.0f, lens_v = 0.0f; if(kernel_data.cam.aperturesize > 0.0f) - path_rng_2D(kg, rng, sample, num_samples, PRNG_LENS_U, &lens_u, &lens_v); + path_rng_2D(kg, *rng_hash, sample, num_samples, PRNG_LENS_U, &lens_u, &lens_v); float time = 0.0f; #ifdef __CAMERA_MOTION__ if(kernel_data.cam.shuttertime != -1.0f) - time = path_rng_1D(kg, rng, sample, num_samples, PRNG_TIME); + time = path_rng_1D(kg, *rng_hash, sample, num_samples, PRNG_TIME); #endif camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, time, ray); diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h index 5d92fd12201..eccee54c0e3 100644 --- a/intern/cycles/kernel/kernel_path_state.h +++ b/intern/cycles/kernel/kernel_path_state.h @@ -19,15 +19,17 @@ CCL_NAMESPACE_BEGIN ccl_device_inline void path_state_init(KernelGlobals *kg, ShaderData *stack_sd, ccl_addr_space PathState *state, - RNG *rng, + uint rng_hash, int sample, ccl_addr_space Ray *ray) { state->flag = PATH_RAY_CAMERA|PATH_RAY_MIS_SKIP; + state->rng_hash = rng_hash; state->rng_offset = PRNG_BASE_NUM; state->sample = sample; state->num_samples = kernel_data.integrator.aa_samples; + state->branch_factor = 1.0f; state->bounce = 0; state->diffuse_bounce = 0; @@ -58,16 +60,12 @@ ccl_device_inline void path_state_init(KernelGlobals *kg, /* Initialize volume stack with volume we are inside of. */ kernel_volume_stack_init(kg, stack_sd, state, ray, state->volume_stack); /* Seed RNG for cases where we can't use stratified samples .*/ - state->rng_congruential = lcg_init(*rng + sample*0x51633e2d); + state->rng_congruential = lcg_init(rng_hash + sample*0x51633e2d); } else { state->volume_stack[0].shader = SHADER_NONE; } #endif - -#ifdef __SHADOW_TRICKS__ - state->catcher_object = OBJECT_NONE; -#endif } ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathState *state, int label) @@ -78,12 +76,12 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta state->flag |= PATH_RAY_TRANSPARENT; state->transparent_bounce++; - /* don't increase random number generator offset here, to avoid some - * unwanted patterns, see path_state_rng_1D_for_decision */ - if(!kernel_data.integrator.transparent_shadows) state->flag |= PATH_RAY_MIS_SKIP; + /* random number generator next bounce */ + state->rng_offset += PRNG_BOUNCE_NUM; + return; } @@ -146,7 +144,7 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta #endif } -ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, PathState *state) +ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, ccl_addr_space PathState *state) { uint flag = state->flag & PATH_RAY_ALL_VISIBILITY; @@ -160,17 +158,28 @@ ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, PathState *s return flag; } -ccl_device_inline float path_state_terminate_probability(KernelGlobals *kg, ccl_addr_space PathState *state, const float3 throughput) +ccl_device_inline float path_state_continuation_probability(KernelGlobals *kg, + ccl_addr_space PathState *state, + const float3 throughput) { if(state->flag & PATH_RAY_TRANSPARENT) { - /* transparent rays treated separately */ - if(state->transparent_bounce >= kernel_data.integrator.transparent_max_bounce) + /* Transparent rays are treated separately with own max bounces. */ + if(state->transparent_bounce >= kernel_data.integrator.transparent_max_bounce) { return 0.0f; - else if(state->transparent_bounce <= kernel_data.integrator.transparent_min_bounce) + } + /* Do at least one bounce without RR. */ + else if(state->transparent_bounce <= 1) { return 1.0f; + } +#ifdef __SHADOW_TRICKS__ + /* Exception for shadow catcher not working correctly with RR. */ + else if((state->flag & PATH_RAY_SHADOW_CATCHER) && (state->transparent_bounce <= 8)) { + return 1.0f; + } +#endif } else { - /* other rays */ + /* Test max bounces for various ray types. */ if((state->bounce >= kernel_data.integrator.max_bounce) || (state->diffuse_bounce >= kernel_data.integrator.max_diffuse_bounce) || (state->glossy_bounce >= kernel_data.integrator.max_glossy_bounce) || @@ -181,13 +190,21 @@ ccl_device_inline float path_state_terminate_probability(KernelGlobals *kg, ccl_ { return 0.0f; } - else if(state->bounce <= kernel_data.integrator.min_bounce) { + /* Do at least one bounce without RR. */ + else if(state->bounce <= 1) { return 1.0f; } +#ifdef __SHADOW_TRICKS__ + /* Exception for shadow catcher not working correctly with RR. */ + else if((state->flag & PATH_RAY_SHADOW_CATCHER) && (state->bounce <= 3)) { + return 1.0f; + } +#endif } - /* probalistic termination */ - return average(throughput); /* todo: try using max here */ + /* Probalistic termination: use sqrt() to roughly match typical view + * transform and do path termination a bit later on average. */ + return min(sqrtf(max3(fabs(throughput)) * state->branch_factor), 1.0f); } /* TODO(DingTo): Find more meaningful name for this */ @@ -200,5 +217,30 @@ ccl_device_inline void path_state_modify_bounce(ccl_addr_space PathState *state, state->bounce -= 1; } +ccl_device_inline bool path_state_ao_bounce(KernelGlobals *kg, ccl_addr_space PathState *state) +{ + if(state->bounce <= kernel_data.integrator.ao_bounces) { + return false; + } + + int bounce = state->bounce - state->transmission_bounce - (state->glossy_bounce > 0); + return (bounce > kernel_data.integrator.ao_bounces); +} + +ccl_device_inline void path_state_branch(ccl_addr_space PathState *state, + int branch, + int num_branches) +{ + state->rng_offset += PRNG_BOUNCE_NUM; + + if(num_branches > 1) { + /* Path is splitting into a branch, adjust so that each branch + * still gets a unique sample from the same sequence. */ + state->sample = state->sample*num_branches + branch; + state->num_samples = state->num_samples*num_branches; + state->branch_factor *= num_branches; + } +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_path_subsurface.h b/intern/cycles/kernel/kernel_path_subsurface.h index 10b568ac3dd..1436e8e5a5b 100644 --- a/intern/cycles/kernel/kernel_path_subsurface.h +++ b/intern/cycles/kernel/kernel_path_subsurface.h @@ -28,16 +28,14 @@ bool kernel_path_subsurface_scatter( ShaderData *emission_sd, PathRadiance *L, ccl_addr_space PathState *state, - RNG *rng, ccl_addr_space Ray *ray, ccl_addr_space float3 *throughput, ccl_addr_space SubsurfaceIndirectRays *ss_indirect) { - float bssrdf_probability; - ShaderClosure *sc = subsurface_scatter_pick_closure(kg, sd, &bssrdf_probability); + float bssrdf_u, bssrdf_v; + path_state_rng_2D(kg, state, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v); - /* modify throughput for picking bssrdf or bsdf */ - *throughput *= bssrdf_probability; + const ShaderClosure *sc = shader_bssrdf_pick(sd, throughput, &bssrdf_u); /* do bssrdf scatter step if we picked a bssrdf closure */ if(sc) { @@ -45,13 +43,11 @@ bool kernel_path_subsurface_scatter( * the second one should be converted to a diffuse BSDF to * avoid this. */ - kernel_assert(!ss_indirect->tracing); + kernel_assert(!(state->flag & PATH_RAY_DIFFUSE_ANCESTOR)); - uint lcg_state = lcg_state_init(rng, state->rng_offset, state->sample, 0x68bc21eb); + uint lcg_state = lcg_state_init_addrspace(state, 0x68bc21eb); SubsurfaceIntersection ss_isect; - float bssrdf_u, bssrdf_v; - path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v); int num_hits = subsurface_scatter_multi_intersect(kg, &ss_isect, sd, @@ -60,7 +56,7 @@ bool kernel_path_subsurface_scatter( bssrdf_u, bssrdf_v, false); # ifdef __VOLUME__ - ss_indirect->need_update_volume_stack = + bool need_update_volume_stack = kernel_data.integrator.use_volumes && sd->object_flag & SD_OBJECT_INTERSECTS_VOLUME; # endif /* __VOLUME__ */ @@ -79,29 +75,25 @@ bool kernel_path_subsurface_scatter( sc, false); + kernel_path_surface_connect_light(kg, sd, emission_sd, *throughput, state, L); + ccl_addr_space PathState *hit_state = &ss_indirect->state[ss_indirect->num_rays]; ccl_addr_space Ray *hit_ray = &ss_indirect->rays[ss_indirect->num_rays]; ccl_addr_space float3 *hit_tp = &ss_indirect->throughputs[ss_indirect->num_rays]; - PathRadiance *hit_L = &ss_indirect->L[ss_indirect->num_rays]; + PathRadianceState *hit_L_state = &ss_indirect->L_state[ss_indirect->num_rays]; *hit_state = *state; *hit_ray = *ray; *hit_tp = *throughput; + *hit_L_state = L->state; hit_state->rng_offset += PRNG_BOUNCE_NUM; - path_radiance_init(hit_L, kernel_data.film.use_light_pass); - hit_L->direct_throughput = L->direct_throughput; - path_radiance_copy_indirect(hit_L, L); - - kernel_path_surface_connect_light(kg, rng, sd, emission_sd, *hit_tp, state, hit_L); - if(kernel_path_surface_bounce(kg, - rng, sd, hit_tp, hit_state, - hit_L, + hit_L_state, hit_ray)) { # ifdef __LAMP_MIS__ @@ -109,7 +101,7 @@ bool kernel_path_subsurface_scatter( # endif /* __LAMP_MIS__ */ # ifdef __VOLUME__ - if(ss_indirect->need_update_volume_stack) { + if(need_update_volume_stack) { Ray volume_ray = *ray; /* Setup ray from previous surface point to the new one. */ volume_ray.D = normalize_len(hit_ray->P - volume_ray.P, @@ -122,12 +114,8 @@ bool kernel_path_subsurface_scatter( hit_state->volume_stack); } # endif /* __VOLUME__ */ - path_radiance_reset_indirect(L); ss_indirect->num_rays++; } - else { - path_radiance_accum_sample(L, hit_L, 1); - } } return true; } @@ -137,23 +125,9 @@ bool kernel_path_subsurface_scatter( ccl_device_inline void kernel_path_subsurface_init_indirect( ccl_addr_space SubsurfaceIndirectRays *ss_indirect) { - ss_indirect->tracing = false; ss_indirect->num_rays = 0; } -ccl_device void kernel_path_subsurface_accum_indirect( - ccl_addr_space SubsurfaceIndirectRays *ss_indirect, - PathRadiance *L) -{ - if(ss_indirect->tracing) { - path_radiance_sum_indirect(L); - path_radiance_accum_sample(&ss_indirect->direct_L, L, 1); - if(ss_indirect->num_rays == 0) { - *L = ss_indirect->direct_L; - } - } -} - ccl_device void kernel_path_subsurface_setup_indirect( KernelGlobals *kg, ccl_addr_space SubsurfaceIndirectRays *ss_indirect, @@ -162,20 +136,15 @@ ccl_device void kernel_path_subsurface_setup_indirect( PathRadiance *L, ccl_addr_space float3 *throughput) { - if(!ss_indirect->tracing) { - ss_indirect->direct_L = *L; - } - ss_indirect->tracing = true; - /* Setup state, ray and throughput for indirect SSS rays. */ ss_indirect->num_rays--; - ccl_addr_space Ray *indirect_ray = &ss_indirect->rays[ss_indirect->num_rays]; - PathRadiance *indirect_L = &ss_indirect->L[ss_indirect->num_rays]; + path_radiance_sum_indirect(L); + path_radiance_reset_indirect(L); *state = ss_indirect->state[ss_indirect->num_rays]; - *ray = *indirect_ray; - *L = *indirect_L; + *ray = ss_indirect->rays[ss_indirect->num_rays]; + L->state = ss_indirect->L_state[ss_indirect->num_rays]; *throughput = ss_indirect->throughputs[ss_indirect->num_rays]; state->rng_offset += ss_indirect->num_rays * PRNG_BOUNCE_NUM; diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h index dcb577e176f..7b566b01b04 100644 --- a/intern/cycles/kernel/kernel_path_surface.h +++ b/intern/cycles/kernel/kernel_path_surface.h @@ -20,7 +20,6 @@ CCL_NAMESPACE_BEGIN /* branched path tracing: connect path directly to position on one or more lights and add it to L */ ccl_device_noinline void kernel_branched_path_surface_connect_light( KernelGlobals *kg, - RNG *rng, ShaderData *sd, ShaderData *emission_sd, ccl_addr_space PathState *state, @@ -50,12 +49,12 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light( int num_samples = ceil_to_int(num_samples_adjust*light_select_num_samples(kg, i)); float num_samples_inv = num_samples_adjust/(num_samples*kernel_data.integrator.num_all_lights); - RNG lamp_rng = cmj_hash(*rng, i); + uint lamp_rng_hash = cmj_hash(state->rng_hash, i); for(int j = 0; j < num_samples; j++) { float light_u, light_v; - path_branched_rng_2D(kg, &lamp_rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v); - float terminate = path_branched_rng_light_termination(kg, &lamp_rng, state, j, num_samples); + path_branched_rng_2D(kg, lamp_rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v); + float terminate = path_branched_rng_light_termination(kg, lamp_rng_hash, state, j, num_samples); LightSample ls; if(lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls)) { @@ -68,7 +67,7 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light( /* trace shadow ray */ float3 shadow; - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) { + if(!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) { /* accumulate */ path_radiance_accum_light(L, state, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp); } @@ -86,17 +85,16 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light( float num_samples_inv = num_samples_adjust/num_samples; for(int j = 0; j < num_samples; j++) { - float light_t = path_branched_rng_1D(kg, rng, state, j, num_samples, PRNG_LIGHT); float light_u, light_v; - path_branched_rng_2D(kg, rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v); - float terminate = path_branched_rng_light_termination(kg, rng, state, j, num_samples); + path_branched_rng_2D(kg, state->rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v); + float terminate = path_branched_rng_light_termination(kg, state->rng_hash, state, j, num_samples); /* only sample triangle lights */ if(kernel_data.integrator.num_all_lights) - light_t = 0.5f*light_t; + light_u = 0.5f*light_u; LightSample ls; - if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { + if(light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { /* Same as above, probability needs to be corrected since the sampling was forced to select a mesh light. */ if(kernel_data.integrator.num_all_lights) ls.pdf *= 2.0f; @@ -105,7 +103,7 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light( /* trace shadow ray */ float3 shadow; - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) { + if(!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) { /* accumulate */ path_radiance_accum_light(L, state, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp); } @@ -119,19 +117,18 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light( } else { /* sample one light at random */ - float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT); float light_u, light_v; - path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v); - float terminate = path_state_rng_light_termination(kg, rng, state); + path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v); + float terminate = path_state_rng_light_termination(kg, state); LightSample ls; - if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { + if(light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { /* sample random light */ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) { + if(!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) { /* accumulate */ path_radiance_accum_light(L, state, throughput*num_samples_adjust, &L_light, shadow, num_samples_adjust, is_lamp); } @@ -147,14 +144,13 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light( /* branched path tracing: bounce off or through surface to with new direction stored in ray */ ccl_device bool kernel_branched_path_surface_bounce( KernelGlobals *kg, - RNG *rng, ShaderData *sd, const ShaderClosure *sc, int sample, int num_samples, ccl_addr_space float3 *throughput, ccl_addr_space PathState *state, - PathRadiance *L, + PathRadianceState *L_state, ccl_addr_space Ray *ray, float sum_sample_weight) { @@ -164,7 +160,7 @@ ccl_device bool kernel_branched_path_surface_bounce( float3 bsdf_omega_in; differential3 bsdf_domega_in; float bsdf_u, bsdf_v; - path_branched_rng_2D(kg, rng, state, sample, num_samples, PRNG_BSDF_U, &bsdf_u, &bsdf_v); + path_branched_rng_2D(kg, state->rng_hash, state, sample, num_samples, PRNG_BSDF_U, &bsdf_u, &bsdf_v); int label; label = shader_bsdf_sample_closure(kg, sd, sc, bsdf_u, bsdf_v, &bsdf_eval, @@ -174,7 +170,7 @@ ccl_device bool kernel_branched_path_surface_bounce( return false; /* modify throughput */ - path_radiance_bsdf_bounce(L, throughput, &bsdf_eval, bsdf_pdf, state->bounce, label); + path_radiance_bsdf_bounce(kg, L_state, throughput, &bsdf_eval, bsdf_pdf, state->bounce, label); #ifdef __DENOISING_FEATURES__ state->denoising_feature_weight *= sc->sample_weight / (sum_sample_weight * num_samples); @@ -217,7 +213,7 @@ ccl_device bool kernel_branched_path_surface_bounce( #endif /* path tracing: connect path directly to position on a light and add it to L */ -ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, RNG *rng, +ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ShaderData *sd, ShaderData *emission_sd, float3 throughput, ccl_addr_space PathState *state, PathRadiance *L) { @@ -228,7 +224,6 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, RNG #ifdef __SHADOW_TRICKS__ if(state->flag & PATH_RAY_SHADOW_CATCHER) { kernel_branched_path_surface_connect_light(kg, - rng, sd, emission_sd, state, @@ -241,9 +236,8 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, RNG #endif /* sample illumination from lights to find path contribution */ - float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT); float light_u, light_v; - path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v); + path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v); Ray light_ray; BsdfEval L_light; @@ -254,13 +248,13 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, RNG #endif LightSample ls; - if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { - float terminate = path_state_rng_light_termination(kg, rng, state); + if(light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { + float terminate = path_state_rng_light_termination(kg, state); if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) { + if(!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) { /* accumulate */ path_radiance_accum_light(L, state, throughput, &L_light, shadow, 1.0f, is_lamp); } @@ -274,11 +268,10 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, RNG /* path tracing: bounce off or through surface to with new direction stored in ray */ ccl_device bool kernel_path_surface_bounce(KernelGlobals *kg, - RNG *rng, ShaderData *sd, ccl_addr_space float3 *throughput, ccl_addr_space PathState *state, - PathRadiance *L, + PathRadianceState *L_state, ccl_addr_space Ray *ray) { /* no BSDF? we can stop here */ @@ -289,7 +282,7 @@ ccl_device bool kernel_path_surface_bounce(KernelGlobals *kg, float3 bsdf_omega_in; differential3 bsdf_domega_in; float bsdf_u, bsdf_v; - path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); + path_state_rng_2D(kg, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); int label; label = shader_bsdf_sample(kg, sd, bsdf_u, bsdf_v, &bsdf_eval, @@ -299,7 +292,7 @@ ccl_device bool kernel_path_surface_bounce(KernelGlobals *kg, return false; /* modify throughput */ - path_radiance_bsdf_bounce(L, throughput, &bsdf_eval, bsdf_pdf, state->bounce, label); + path_radiance_bsdf_bounce(kg, L_state, throughput, &bsdf_eval, bsdf_pdf, state->bounce, label); /* set labels */ if(!(label & LABEL_TRANSPARENT)) { diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h index dcedf51e479..b6a856baf24 100644 --- a/intern/cycles/kernel/kernel_path_volume.h +++ b/intern/cycles/kernel/kernel_path_volume.h @@ -20,7 +20,6 @@ CCL_NAMESPACE_BEGIN ccl_device_inline void kernel_path_volume_connect_light( KernelGlobals *kg, - RNG *rng, ShaderData *sd, ShaderData *emission_sd, float3 throughput, @@ -32,9 +31,8 @@ ccl_device_inline void kernel_path_volume_connect_light( return; /* sample illumination from lights to find path contribution */ - float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT); float light_u, light_v; - path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v); + path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v); Ray light_ray; BsdfEval L_light; @@ -42,18 +40,16 @@ ccl_device_inline void kernel_path_volume_connect_light( bool is_lamp; /* connect to light from given point where shader has been evaluated */ -# ifdef __OBJECT_MOTION__ light_ray.time = sd->time; -# endif - if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) + if(light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { - float terminate = path_state_rng_light_termination(kg, rng, state); + float terminate = path_state_rng_light_termination(kg, state); if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) { + if(!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) { /* accumulate */ path_radiance_accum_light(L, state, throughput, &L_light, shadow, 1.0f, is_lamp); } @@ -69,11 +65,10 @@ ccl_device #endif bool kernel_path_volume_bounce( KernelGlobals *kg, - RNG *rng, ShaderData *sd, ccl_addr_space float3 *throughput, ccl_addr_space PathState *state, - PathRadiance *L, + PathRadianceState *L_state, ccl_addr_space Ray *ray) { /* sample phase function */ @@ -82,7 +77,7 @@ bool kernel_path_volume_bounce( float3 phase_omega_in; differential3 phase_domega_in; float phase_u, phase_v; - path_state_rng_2D(kg, rng, state, PRNG_PHASE_U, &phase_u, &phase_v); + path_state_rng_2D(kg, state, PRNG_BSDF_U, &phase_u, &phase_v); int label; label = shader_volume_phase_sample(kg, sd, phase_u, phase_v, &phase_eval, @@ -92,7 +87,7 @@ bool kernel_path_volume_bounce( return false; /* modify throughput */ - path_radiance_bsdf_bounce(L, throughput, &phase_eval, phase_pdf, state->bounce, label); + path_radiance_bsdf_bounce(kg, L_state, throughput, &phase_eval, phase_pdf, state->bounce, label); /* set labels */ state->ray_pdf = phase_pdf; @@ -120,7 +115,6 @@ bool kernel_path_volume_bounce( #ifndef __SPLIT_KERNEL__ ccl_device void kernel_branched_path_volume_connect_light( KernelGlobals *kg, - RNG *rng, ShaderData *sd, ShaderData *emission_sd, float3 throughput, @@ -138,9 +132,7 @@ ccl_device void kernel_branched_path_volume_connect_light( BsdfEval L_light; bool is_lamp; -# ifdef __OBJECT_MOTION__ light_ray.time = sd->time; -# endif if(sample_all_lights) { /* lamp sampling */ @@ -150,12 +142,12 @@ ccl_device void kernel_branched_path_volume_connect_light( int num_samples = light_select_num_samples(kg, i); float num_samples_inv = 1.0f/(num_samples*kernel_data.integrator.num_all_lights); - RNG lamp_rng = cmj_hash(*rng, i); + uint lamp_rng_hash = cmj_hash(state->rng_hash, i); for(int j = 0; j < num_samples; j++) { /* sample random position on given light */ float light_u, light_v; - path_branched_rng_2D(kg, &lamp_rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v); + path_branched_rng_2D(kg, lamp_rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v); LightSample ls; lamp_light_sample(kg, i, light_u, light_v, ray->P, &ls); @@ -163,26 +155,24 @@ ccl_device void kernel_branched_path_volume_connect_light( float3 tp = throughput; /* sample position on volume segment */ - float rphase = path_branched_rng_1D_for_decision(kg, rng, state, j, num_samples, PRNG_PHASE); - float rscatter = path_branched_rng_1D_for_decision(kg, rng, state, j, num_samples, PRNG_SCATTER_DISTANCE); + float rphase = path_branched_rng_1D(kg, state->rng_hash, state, j, num_samples, PRNG_PHASE_CHANNEL); + float rscatter = path_branched_rng_1D(kg, state->rng_hash, state, j, num_samples, PRNG_SCATTER_DISTANCE); VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg, state, ray, sd, &tp, rphase, rscatter, segment, (ls.t != FLT_MAX)? &ls.P: NULL, false); - (void)result; - kernel_assert(result == VOLUME_PATH_SCATTERED); - /* todo: split up light_sample so we don't have to call it again with new position */ - if(lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls)) { + if(result == VOLUME_PATH_SCATTERED && + lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls)) { if(kernel_data.integrator.pdf_triangles != 0.0f) ls.pdf *= 2.0f; - float terminate = path_branched_rng_light_termination(kg, rng, state, j, num_samples); + float terminate = path_branched_rng_light_termination(kg, state->rng_hash, state, j, num_samples); if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) { + if(!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) { /* accumulate */ path_radiance_accum_light(L, state, tp*num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp); } @@ -198,40 +188,37 @@ ccl_device void kernel_branched_path_volume_connect_light( for(int j = 0; j < num_samples; j++) { /* sample random position on random triangle */ - float light_t = path_branched_rng_1D_for_decision(kg, rng, state, j, num_samples, PRNG_LIGHT); float light_u, light_v; - path_branched_rng_2D(kg, rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v); + path_branched_rng_2D(kg, state->rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v); /* only sample triangle lights */ if(kernel_data.integrator.num_all_lights) - light_t = 0.5f*light_t; + light_u = 0.5f*light_u; LightSample ls; - light_sample(kg, light_t, light_u, light_v, sd->time, ray->P, state->bounce, &ls); + light_sample(kg, light_u, light_v, sd->time, ray->P, state->bounce, &ls); float3 tp = throughput; /* sample position on volume segment */ - float rphase = path_branched_rng_1D_for_decision(kg, rng, state, j, num_samples, PRNG_PHASE); - float rscatter = path_branched_rng_1D_for_decision(kg, rng, state, j, num_samples, PRNG_SCATTER_DISTANCE); + float rphase = path_branched_rng_1D(kg, state->rng_hash, state, j, num_samples, PRNG_PHASE_CHANNEL); + float rscatter = path_branched_rng_1D(kg, state->rng_hash, state, j, num_samples, PRNG_SCATTER_DISTANCE); VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg, state, ray, sd, &tp, rphase, rscatter, segment, (ls.t != FLT_MAX)? &ls.P: NULL, false); - (void)result; - kernel_assert(result == VOLUME_PATH_SCATTERED); - /* todo: split up light_sample so we don't have to call it again with new position */ - if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { + if(result == VOLUME_PATH_SCATTERED && + light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { if(kernel_data.integrator.num_all_lights) ls.pdf *= 2.0f; - float terminate = path_branched_rng_light_termination(kg, rng, state, j, num_samples); + float terminate = path_branched_rng_light_termination(kg, state->rng_hash, state, j, num_samples); if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) { + if(!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) { /* accumulate */ path_radiance_accum_light(L, state, tp*num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp); } @@ -242,34 +229,31 @@ ccl_device void kernel_branched_path_volume_connect_light( } else { /* sample random position on random light */ - float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT); float light_u, light_v; - path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v); + path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v); LightSample ls; - light_sample(kg, light_t, light_u, light_v, sd->time, ray->P, state->bounce, &ls); + light_sample(kg, light_u, light_v, sd->time, ray->P, state->bounce, &ls); float3 tp = throughput; /* sample position on volume segment */ - float rphase = path_state_rng_1D_for_decision(kg, rng, state, PRNG_PHASE); - float rscatter = path_state_rng_1D_for_decision(kg, rng, state, PRNG_SCATTER_DISTANCE); + float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL); + float rscatter = path_state_rng_1D(kg, state, PRNG_SCATTER_DISTANCE); VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg, state, ray, sd, &tp, rphase, rscatter, segment, (ls.t != FLT_MAX)? &ls.P: NULL, false); - (void)result; - kernel_assert(result == VOLUME_PATH_SCATTERED); - /* todo: split up light_sample so we don't have to call it again with new position */ - if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { + if(result == VOLUME_PATH_SCATTERED && + light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { /* sample random light */ - float terminate = path_state_rng_light_termination(kg, rng, state); + float terminate = path_state_rng_light_termination(kg, state); if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) { + if(!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) { /* accumulate */ path_radiance_accum_light(L, state, tp, &L_light, shadow, 1.0f, is_lamp); } diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h index e8a912ccc0b..11798d87cb5 100644 --- a/intern/cycles/kernel/kernel_random.h +++ b/intern/cycles/kernel/kernel_random.h @@ -18,55 +18,18 @@ CCL_NAMESPACE_BEGIN -#ifdef __SOBOL__ - -/* Skip initial numbers that are not as well distributed, especially the - * first sequence is just 0 everywhere, which can be problematic for e.g. - * path termination. - */ -#define SOBOL_SKIP 64 +/* Pseudo random numbers, uncomment this for debugging correlations. Only run + * this single threaded on a CPU for repeatable resutls. */ +//#define __DEBUG_CORRELATION__ -/* High Dimensional Sobol. */ -/* Van der Corput radical inverse. */ -ccl_device uint van_der_corput(uint bits) -{ - bits = (bits << 16) | (bits >> 16); - bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8); - bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4); - bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2); - bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1); - return bits; -} - -/* Sobol radical inverse. */ -ccl_device uint sobol(uint i) -{ - uint r = 0; - for(uint v = 1U << 31; i; i >>= 1, v ^= v >> 1) { - if(i & 1) { - r ^= v; - } - } - return r; -} +/* High Dimensional Sobol. + * + * Multidimensional sobol with generator matrices. Dimension 0 and 1 are equal + * to classic Van der Corput and Sobol sequences. */ -/* Inverse of sobol radical inverse. */ -ccl_device uint sobol_inverse(uint i) -{ - const uint msb = 1U << 31; - uint r = 0; - for(uint v = 1; i; i <<= 1, v ^= v << 1) { - if(i & msb) { - r ^= v; - } - } - return r; -} +#ifdef __SOBOL__ -/* Multidimensional sobol with generator matrices - * dimension 0 and 1 are equal to van_der_corput() and sobol() respectively. - */ ccl_device uint sobol_dimension(KernelGlobals *kg, int index, int dimension) { uint result = 0; @@ -79,51 +42,32 @@ ccl_device uint sobol_dimension(KernelGlobals *kg, int index, int dimension) return result; } -/* Lookup index and x/y coordinate, assumes m is a power of two. */ -ccl_device uint sobol_lookup(const uint m, - const uint frame, - const uint ex, - const uint ey, - uint *x, uint *y) -{ - /* Shift is constant per frame. */ - const uint shift = frame << (m << 1); - const uint sobol_shift = sobol(shift); - /* Van der Corput is its own inverse. */ - const uint lower = van_der_corput(ex << (32 - m)); - /* Need to compensate for ey difference and shift. */ - const uint sobol_lower = sobol(lower); - const uint mask = ~-(1 << m) << (32 - m); /* Only m upper bits. */ - const uint delta = ((ey << (32 - m)) ^ sobol_lower ^ sobol_shift) & mask; - /* Only use m upper bits for the index (m is a power of two). */ - const uint sobol_result = delta | (delta >> m); - const uint upper = sobol_inverse(sobol_result); - const uint index = shift | upper | lower; - *x = van_der_corput(index); - *y = sobol_shift ^ sobol_result ^ sobol_lower; - return index; -} +#endif /* __SOBOL__ */ + ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, - RNG *rng, + uint rng_hash, int sample, int num_samples, int dimension) { +#ifdef __DEBUG_CORRELATION__ + return (float)drand48(); +#endif + #ifdef __CMJ__ - if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) { +# ifdef __SOBOL__ + if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) +# endif + { /* Correlated multi-jitter. */ - int p = *rng + dimension; + int p = rng_hash + dimension; return cmj_sample_1D(sample, num_samples, p); } #endif -#ifdef __SOBOL_FULL_SCREEN__ - uint result = sobol_dimension(kg, *rng, dimension); - float r = (float)result * (1.0f/(float)0xFFFFFFFF); - return r; -#else - /* Compute sobol sequence value using direction vectors. */ - uint result = sobol_dimension(kg, sample + SOBOL_SKIP, dimension); +#ifdef __SOBOL__ + /* Sobol sequence value using direction vectors. */ + uint result = sobol_dimension(kg, sample, dimension); float r = (float)result * (1.0f/(float)0xFFFFFFFF); /* Cranly-Patterson rotation using rng seed */ @@ -132,7 +76,7 @@ ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, /* Hash rng with dimension to solve correlation issues. * See T38710, T50116. */ - RNG tmp_rng = cmj_hash_simple(dimension, *rng); + uint tmp_rng = cmj_hash_simple(dimension, rng_hash); shift = tmp_rng * (1.0f/(float)0xFFFFFFFF); return r + shift - floorf(r + shift); @@ -140,128 +84,60 @@ ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, } ccl_device_forceinline void path_rng_2D(KernelGlobals *kg, - RNG *rng, + uint rng_hash, int sample, int num_samples, int dimension, float *fx, float *fy) { +#ifdef __DEBUG_CORRELATION__ + *fx = (float)drand48(); + *fy = (float)drand48(); + return; +#endif + #ifdef __CMJ__ - if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) { +# ifdef __SOBOL__ + if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) +# endif + { /* Correlated multi-jitter. */ - int p = *rng + dimension; + int p = rng_hash + dimension; cmj_sample_2D(sample, num_samples, p, fx, fy); + return; } - else #endif - { - /* Sobol. */ - *fx = path_rng_1D(kg, rng, sample, num_samples, dimension); - *fy = path_rng_1D(kg, rng, sample, num_samples, dimension + 1); - } + +#ifdef __SOBOL__ + /* Sobol. */ + *fx = path_rng_1D(kg, rng_hash, sample, num_samples, dimension); + *fy = path_rng_1D(kg, rng_hash, sample, num_samples, dimension + 1); +#endif } ccl_device_inline void path_rng_init(KernelGlobals *kg, ccl_global uint *rng_state, int sample, int num_samples, - RNG *rng, + uint *rng_hash, int x, int y, float *fx, float *fy) { -#ifdef __SOBOL_FULL_SCREEN__ - uint px, py; - uint bits = 16; /* limits us to 65536x65536 and 65536 samples */ - uint size = 1 << bits; - uint frame = sample; - - *rng = sobol_lookup(bits, frame, x, y, &px, &py); - - *rng ^= kernel_data.integrator.seed; - - if(sample == 0) { - *fx = 0.5f; - *fy = 0.5f; - } - else { - *fx = size * (float)px * (1.0f/(float)0xFFFFFFFF) - x; - *fy = size * (float)py * (1.0f/(float)0xFFFFFFFF) - y; - } -#else - *rng = *rng_state; - - *rng ^= kernel_data.integrator.seed; - - if(sample == 0) { - *fx = 0.5f; - *fy = 0.5f; - } - else { - path_rng_2D(kg, rng, sample, num_samples, PRNG_FILTER_U, fx, fy); - } -#endif -} - -ccl_device void path_rng_end(KernelGlobals *kg, - ccl_global uint *rng_state, - RNG rng) -{ - /* nothing to do */ -} - -#else /* __SOBOL__ */ - -/* Linear Congruential Generator */ - -ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, - RNG *rng, - int sample, int num_samples, - int dimension) -{ - /* implicit mod 2^32 */ - *rng = (1103515245*(*rng) + 12345); - return (float)*rng * (1.0f/(float)0xFFFFFFFF); -} - -ccl_device_inline void path_rng_2D(KernelGlobals *kg, - RNG *rng, - int sample, int num_samples, - int dimension, - float *fx, float *fy) -{ - *fx = path_rng_1D(kg, rng, sample, num_samples, dimension); - *fy = path_rng_1D(kg, rng, sample, num_samples, dimension + 1); -} - -ccl_device void path_rng_init(KernelGlobals *kg, - ccl_global uint *rng_state, - int sample, int num_samples, - RNG *rng, - int x, int y, - float *fx, float *fy) -{ /* load state */ - *rng = *rng_state; + *rng_hash = *rng_state; + *rng_hash ^= kernel_data.integrator.seed; - *rng ^= kernel_data.integrator.seed; +#ifdef __DEBUG_CORRELATION__ + srand48(*rng_hash + sample); +#endif if(sample == 0) { *fx = 0.5f; *fy = 0.5f; } else { - path_rng_2D(kg, rng, sample, num_samples, PRNG_FILTER_U, fx, fy); + path_rng_2D(kg, *rng_hash, sample, num_samples, PRNG_FILTER_U, fx, fy); } } -ccl_device void path_rng_end(KernelGlobals *kg, - ccl_global uint *rng_state, - RNG rng) -{ - /* store state for next sample */ - *rng_state = rng; -} - -#endif /* __SOBOL__ */ - /* Linear Congruential Generator */ ccl_device uint lcg_step_uint(uint *rng) @@ -295,44 +171,22 @@ ccl_device uint lcg_init(uint seed) */ ccl_device_inline float path_state_rng_1D(KernelGlobals *kg, - RNG *rng, const ccl_addr_space PathState *state, int dimension) { return path_rng_1D(kg, - rng, + state->rng_hash, state->sample, state->num_samples, state->rng_offset + dimension); } -ccl_device_inline float path_state_rng_1D_for_decision( - KernelGlobals *kg, - RNG *rng, - const ccl_addr_space PathState *state, - int dimension) -{ - /* The rng_offset is not increased for transparent bounces. if we do then - * fully transparent objects can become subtly visible by the different - * sampling patterns used where the transparent object is. - * - * however for some random numbers that will determine if we next bounce - * is transparent we do need to increase the offset to avoid always making - * the same decision. */ - const int rng_offset = state->rng_offset + state->transparent_bounce * PRNG_BOUNCE_NUM; - return path_rng_1D(kg, - rng, - state->sample, state->num_samples, - rng_offset + dimension); -} - ccl_device_inline void path_state_rng_2D(KernelGlobals *kg, - RNG *rng, const ccl_addr_space PathState *state, int dimension, float *fx, float *fy) { path_rng_2D(kg, - rng, + state->rng_hash, state->sample, state->num_samples, state->rng_offset + dimension, fx, fy); @@ -340,38 +194,22 @@ ccl_device_inline void path_state_rng_2D(KernelGlobals *kg, ccl_device_inline float path_branched_rng_1D( KernelGlobals *kg, - RNG *rng, + uint rng_hash, const ccl_addr_space PathState *state, int branch, int num_branches, int dimension) { return path_rng_1D(kg, - rng, + rng_hash, state->sample * num_branches + branch, state->num_samples * num_branches, state->rng_offset + dimension); } -ccl_device_inline float path_branched_rng_1D_for_decision( - KernelGlobals *kg, - RNG *rng, - const ccl_addr_space PathState *state, - int branch, - int num_branches, - int dimension) -{ - const int rng_offset = state->rng_offset + state->transparent_bounce * PRNG_BOUNCE_NUM; - return path_rng_1D(kg, - rng, - state->sample * num_branches + branch, - state->num_samples * num_branches, - rng_offset + dimension); -} - ccl_device_inline void path_branched_rng_2D( KernelGlobals *kg, - RNG *rng, + uint rng_hash, const ccl_addr_space PathState *state, int branch, int num_branches, @@ -379,7 +217,7 @@ ccl_device_inline void path_branched_rng_2D( float *fx, float *fy) { path_rng_2D(kg, - rng, + rng_hash, state->sample * num_branches + branch, state->num_samples * num_branches, state->rng_offset + dimension, @@ -391,52 +229,45 @@ ccl_device_inline void path_branched_rng_2D( */ ccl_device_inline float path_state_rng_light_termination( KernelGlobals *kg, - RNG *rng, const ccl_addr_space PathState *state) { if(kernel_data.integrator.light_inv_rr_threshold > 0.0f) { - return path_state_rng_1D_for_decision(kg, rng, state, PRNG_LIGHT_TERMINATE); + return path_state_rng_1D(kg, state, PRNG_LIGHT_TERMINATE); } return 0.0f; } ccl_device_inline float path_branched_rng_light_termination( KernelGlobals *kg, - RNG *rng, + uint rng_hash, const ccl_addr_space PathState *state, int branch, int num_branches) { if(kernel_data.integrator.light_inv_rr_threshold > 0.0f) { - return path_branched_rng_1D_for_decision(kg, - rng, - state, - branch, - num_branches, - PRNG_LIGHT_TERMINATE); + return path_branched_rng_1D(kg, + rng_hash, + state, + branch, + num_branches, + PRNG_LIGHT_TERMINATE); } return 0.0f; } -ccl_device_inline void path_state_branch(ccl_addr_space PathState *state, - int branch, - int num_branches) +ccl_device_inline uint lcg_state_init(PathState *state, + uint scramble) { - /* path is splitting into a branch, adjust so that each branch - * still gets a unique sample from the same sequence */ - state->rng_offset += PRNG_BOUNCE_NUM; - state->sample = state->sample*num_branches + branch; - state->num_samples = state->num_samples*num_branches; + return lcg_init(state->rng_hash + state->rng_offset + state->sample*scramble); } -ccl_device_inline uint lcg_state_init(RNG *rng, - int rng_offset, - int sample, - uint scramble) +ccl_device_inline uint lcg_state_init_addrspace(ccl_addr_space PathState *state, + uint scramble) { - return lcg_init(*rng + rng_offset + sample*scramble); + return lcg_init(state->rng_hash + state->rng_offset + state->sample*scramble); } + ccl_device float lcg_step_float_addrspace(ccl_addr_space uint *rng) { /* Implicit mod 2^32 */ diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index c66f52255f0..eeb4eb0097f 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -66,8 +66,8 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg, /* matrices and time */ #ifdef __OBJECT_MOTION__ shader_setup_object_transforms(kg, sd, ray->time); - sd->time = ray->time; #endif + sd->time = ray->time; sd->prim = kernel_tex_fetch(__prim_index, isect->prim); sd->ray_length = isect->t; @@ -83,7 +83,7 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg, float4 curvedata = kernel_tex_fetch(__curves, sd->prim); sd->shader = __float_as_int(curvedata.z); - sd->P = bvh_curve_refine(kg, sd, isect, ray); + sd->P = curve_refine(kg, sd, isect, ray); } else #endif @@ -271,17 +271,17 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg, sd->u = u; sd->v = v; #endif + sd->time = time; sd->ray_length = t; sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE); sd->object_flag = 0; if(sd->object != OBJECT_NONE) { sd->object_flag |= kernel_tex_fetch(__object_flag, - sd->object); + sd->object); #ifdef __OBJECT_MOTION__ shader_setup_object_transforms(kg, sd, time); - sd->time = time; } else if(lamp != LAMP_NONE) { sd->ob_tfm = lamp_fetch_transform(kg, lamp, false); @@ -385,9 +385,7 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat sd->shader = kernel_data.background.surface_shader; sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE); sd->object_flag = 0; -#ifdef __OBJECT_MOTION__ sd->time = ray->time; -#endif sd->ray_length = 0.0f; #ifdef __INSTANCING__ @@ -427,9 +425,7 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s sd->shader = SHADER_NONE; sd->flag = 0; sd->object_flag = 0; -#ifdef __OBJECT_MOTION__ sd->time = ray->time; -#endif sd->ray_length = 0.0f; /* todo: can we set this to some useful value? */ #ifdef __INSTANCING__ @@ -498,20 +494,45 @@ ccl_device_inline void shader_merge_closures(ShaderData *sd) } #endif +/* Defensive sampling. */ + +ccl_device_inline void shader_prepare_closures(ShaderData *sd, + ccl_addr_space PathState *state) +{ + /* We can likely also do defensive sampling at deeper bounces, particularly + * for cases like a perfect mirror but possibly also others. This will need + * a good heuristic. */ + if(state->bounce + state->transparent_bounce == 0 && sd->num_closure > 1) { + float sum = 0.0f; + + for(int i = 0; i < sd->num_closure; i++) { + ShaderClosure *sc = &sd->closure[i]; + if(CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + sum += sc->sample_weight; + } + } + + for(int i = 0; i < sd->num_closure; i++) { + ShaderClosure *sc = &sd->closure[i]; + if(CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + sc->sample_weight = max(sc->sample_weight, 0.125f * sum); + } + } + } +} + + /* BSDF */ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, ShaderData *sd, const float3 omega_in, float *pdf, - int skip_bsdf, BsdfEval *result_eval, float sum_pdf, float sum_sample_weight) + const ShaderClosure *skip_sc, BsdfEval *result_eval, float sum_pdf, float sum_sample_weight) { /* this is the veach one-sample model with balance heuristic, some pdf * factors drop out when using balance heuristic weighting */ for(int i = 0; i < sd->num_closure; i++) { - if(i == skip_bsdf) - continue; - const ShaderClosure *sc = &sd->closure[i]; - if(CLOSURE_IS_BSDF(sc->type)) { + if(sc != skip_sc && CLOSURE_IS_BSDF(sc->type)) { float bsdf_pdf = 0.0f; float3 eval = bsdf_eval(kg, sd, sc, omega_in, &bsdf_pdf); @@ -574,7 +595,7 @@ void shader_bsdf_eval(KernelGlobals *kg, #endif { float pdf; - _shader_bsdf_multi_eval(kg, sd, omega_in, &pdf, -1, eval, 0.0f, 0.0f); + _shader_bsdf_multi_eval(kg, sd, omega_in, &pdf, NULL, eval, 0.0f, 0.0f); if(use_mis) { float weight = power_heuristic(light_pdf, pdf); bsdf_eval_mis(eval, weight); @@ -582,48 +603,120 @@ void shader_bsdf_eval(KernelGlobals *kg, } } -ccl_device_inline int shader_bsdf_sample(KernelGlobals *kg, - ShaderData *sd, - float randu, float randv, - BsdfEval *bsdf_eval, - float3 *omega_in, - differential3 *domega_in, - float *pdf) +ccl_device_inline const ShaderClosure *shader_bsdf_pick(ShaderData *sd, + float *randu) { int sampled = 0; if(sd->num_closure > 1) { - /* pick a BSDF closure based on sample weights */ + /* Pick a BSDF or based on sample weights. */ float sum = 0.0f; - for(sampled = 0; sampled < sd->num_closure; sampled++) { - const ShaderClosure *sc = &sd->closure[sampled]; - - if(CLOSURE_IS_BSDF(sc->type)) + for(int i = 0; i < sd->num_closure; i++) { + const ShaderClosure *sc = &sd->closure[i]; + + if(CLOSURE_IS_BSDF(sc->type)) { sum += sc->sample_weight; + } } - float r = sd->randb_closure*sum; - sum = 0.0f; + float r = (*randu)*sum; + float partial_sum = 0.0f; + + for(int i = 0; i < sd->num_closure; i++) { + const ShaderClosure *sc = &sd->closure[i]; - for(sampled = 0; sampled < sd->num_closure; sampled++) { - const ShaderClosure *sc = &sd->closure[sampled]; - if(CLOSURE_IS_BSDF(sc->type)) { - sum += sc->sample_weight; + float next_sum = partial_sum + sc->sample_weight; + + if(r < next_sum) { + sampled = i; - if(r <= sum) + /* Rescale to reuse for direction sample, to better + * preserve stratifaction. */ + *randu = (r - partial_sum) / sc->sample_weight; break; + } + + partial_sum = next_sum; } } + } - if(sampled == sd->num_closure) { - *pdf = 0.0f; - return LABEL_NONE; + return &sd->closure[sampled]; +} + +ccl_device_inline const ShaderClosure *shader_bssrdf_pick(ShaderData *sd, + ccl_addr_space float3 *throughput, + float *randu) +{ + int sampled = 0; + + if(sd->num_closure > 1) { + /* Pick a BSDF or BSSRDF or based on sample weights. */ + float sum_bsdf = 0.0f; + float sum_bssrdf = 0.0f; + + for(int i = 0; i < sd->num_closure; i++) { + const ShaderClosure *sc = &sd->closure[i]; + + if(CLOSURE_IS_BSDF(sc->type)) { + sum_bsdf += sc->sample_weight; + } + else if(CLOSURE_IS_BSSRDF(sc->type)) { + sum_bssrdf += sc->sample_weight; + } + } + + float r = (*randu)*(sum_bsdf + sum_bssrdf); + float partial_sum = 0.0f; + + for(int i = 0; i < sd->num_closure; i++) { + const ShaderClosure *sc = &sd->closure[i]; + + if(CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + float next_sum = partial_sum + sc->sample_weight; + + if(r < next_sum) { + if(CLOSURE_IS_BSDF(sc->type)) { + *throughput *= (sum_bsdf + sum_bssrdf) / sum_bsdf; + return NULL; + } + else { + *throughput *= (sum_bsdf + sum_bssrdf) / sum_bssrdf; + sampled = i; + + /* Rescale to reuse for direction sample, to better + * preserve stratifaction. */ + *randu = (r - partial_sum) / sc->sample_weight; + break; + } + } + + partial_sum = next_sum; + } } } - const ShaderClosure *sc = &sd->closure[sampled]; + return &sd->closure[sampled]; +} + +ccl_device_inline int shader_bsdf_sample(KernelGlobals *kg, + ShaderData *sd, + float randu, float randv, + BsdfEval *bsdf_eval, + float3 *omega_in, + differential3 *domega_in, + float *pdf) +{ + const ShaderClosure *sc = shader_bsdf_pick(sd, &randu); + if(sc == NULL) { + *pdf = 0.0f; + return LABEL_NONE; + } + + /* BSSRDF should already have been handled elsewhere. */ + kernel_assert(CLOSURE_IS_BSDF(sc->type)); int label; float3 eval; @@ -636,7 +729,7 @@ ccl_device_inline int shader_bsdf_sample(KernelGlobals *kg, if(sd->num_closure > 1) { float sweight = sc->sample_weight; - _shader_bsdf_multi_eval(kg, sd, *omega_in, pdf, sampled, bsdf_eval, *pdf*sweight, sweight); + _shader_bsdf_multi_eval(kg, sd, *omega_in, pdf, sc, bsdf_eval, *pdf*sweight, sweight); } } @@ -669,7 +762,7 @@ ccl_device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughn } } -ccl_device float3 shader_bsdf_transparency(KernelGlobals *kg, ShaderData *sd) +ccl_device float3 shader_bsdf_transparency(KernelGlobals *kg, const ShaderData *sd) { if(sd->flag & SD_HAS_ONLY_VOLUME) return make_float3(1.0f, 1.0f, 1.0f); @@ -677,7 +770,7 @@ ccl_device float3 shader_bsdf_transparency(KernelGlobals *kg, ShaderData *sd) float3 eval = make_float3(0.0f, 0.0f, 0.0f); for(int i = 0; i < sd->num_closure; i++) { - ShaderClosure *sc = &sd->closure[i]; + const ShaderClosure *sc = &sd->closure[i]; if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID) // todo: make this work for osl eval += sc->weight; @@ -764,6 +857,19 @@ ccl_device float3 shader_bsdf_subsurface(KernelGlobals *kg, ShaderData *sd) return eval; } +ccl_device float3 shader_bsdf_average_normal(KernelGlobals *kg, ShaderData *sd) +{ + float3 N = make_float3(0.0f, 0.0f, 0.0f); + + for(int i = 0; i < sd->num_closure; i++) { + ShaderClosure *sc = &sd->closure[i]; + if(CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) + N += sc->N*average(sc->weight); + } + + return (is_zero(N))? sd->N : normalize(N); +} + ccl_device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_factor, float3 *N_) { float3 eval = make_float3(0.0f, 0.0f, 0.0f); @@ -783,12 +889,7 @@ ccl_device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_fac } } - if(is_zero(N)) - N = sd->N; - else - N = normalize(N); - - *N_ = N; + *N_ = (is_zero(N))? sd->N : normalize(N); return eval; } @@ -863,16 +964,15 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd) /* Surface Evaluation */ -ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, RNG *rng, - ccl_addr_space PathState *state, float randb, int path_flag, ShaderContext ctx) +ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, + ccl_addr_space PathState *state, int path_flag) { sd->num_closure = 0; sd->num_closure_extra = 0; - sd->randb_closure = randb; #ifdef __OSL__ if(kg->osl) - OSLShader::eval_surface(kg, sd, state, path_flag, ctx); + OSLShader::eval_surface(kg, sd, state, path_flag); else #endif { @@ -887,24 +987,23 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, RNG *rng, #endif } - if(rng && (sd->flag & SD_BSDF_NEEDS_LCG)) { - sd->lcg_state = lcg_state_init(rng, state->rng_offset, state->sample, 0xb4bc3953); + if(sd->flag & SD_BSDF_NEEDS_LCG) { + sd->lcg_state = lcg_state_init_addrspace(state, 0xb4bc3953); } } /* Background Evaluation */ ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, - ccl_addr_space PathState *state, int path_flag, ShaderContext ctx) + ccl_addr_space PathState *state, int path_flag) { sd->num_closure = 0; sd->num_closure_extra = 0; - sd->randb_closure = 0.0f; #ifdef __SVM__ #ifdef __OSL__ if(kg->osl) { - OSLShader::eval_background(kg, sd, state, path_flag, ctx); + OSLShader::eval_background(kg, sd, state, path_flag); } else #endif @@ -981,17 +1080,22 @@ ccl_device int shader_volume_phase_sample(KernelGlobals *kg, const ShaderData *s sum += sc->sample_weight; } - float r = sd->randb_closure*sum; - sum = 0.0f; + float r = randu*sum; + float partial_sum = 0.0f; for(sampled = 0; sampled < sd->num_closure; sampled++) { const ShaderClosure *sc = &sd->closure[sampled]; if(CLOSURE_IS_PHASE(sc->type)) { - sum += sc->sample_weight; + float next_sum = partial_sum + sc->sample_weight; - if(r <= sum) + if(r <= next_sum) { + /* Rescale to reuse for BSDF direction sample. */ + randu = (r - partial_sum) / sc->sample_weight; break; + } + + partial_sum = next_sum; } } @@ -1039,8 +1143,7 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state, ccl_addr_space VolumeStack *stack, - int path_flag, - ShaderContext ctx) + int path_flag) { /* reset closures once at the start, we will be accumulating the closures * for all volumes in the stack into a single array of closures */ @@ -1073,7 +1176,7 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg, #ifdef __SVM__ # ifdef __OSL__ if(kg->osl) { - OSLShader::eval_volume(kg, sd, state, path_flag, ctx); + OSLShader::eval_volume(kg, sd, state, path_flag); } else # endif @@ -1092,17 +1195,16 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg, /* Displacement Evaluation */ -ccl_device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state, ShaderContext ctx) +ccl_device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state) { sd->num_closure = 0; sd->num_closure_extra = 0; - sd->randb_closure = 0.0f; /* this will modify sd->P */ #ifdef __SVM__ # ifdef __OSL__ if(kg->osl) - OSLShader::eval_displacement(kg, sd, ctx); + OSLShader::eval_displacement(kg, sd); else # endif { diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h index fab5946970d..8a0da6c3b13 100644 --- a/intern/cycles/kernel/kernel_shadow.h +++ b/intern/cycles/kernel/kernel_shadow.h @@ -16,6 +16,42 @@ CCL_NAMESPACE_BEGIN +#ifdef __VOLUME__ +typedef struct VolumeState { +# ifdef __SPLIT_KERNEL__ +# else + PathState ps; +# endif +} VolumeState; + +/* Get PathState ready for use for volume stack evaluation. */ +# ifdef __SPLIT_KERNEL__ +ccl_addr_space +# endif +ccl_device_inline PathState *shadow_blocked_volume_path_state( + KernelGlobals *kg, + VolumeState *volume_state, + ccl_addr_space PathState *state, + ShaderData *sd, + Ray *ray) +{ +# ifdef __SPLIT_KERNEL__ + ccl_addr_space PathState *ps = + &kernel_split_state.state_shadow[ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0)]; +# else + PathState *ps = &volume_state->ps; +# endif + *ps = *state; + /* We are checking for shadow on the "other" side of the surface, so need + * to discard volume we are currently at. + */ + if(dot(sd->Ng, ray->D) < 0.0f) { + kernel_volume_stack_enter_exit(kg, sd, ps->volume_stack); + } + return ps; +} +#endif /* __VOLUME__ */ + /* Attenuate throughput accordingly to the given intersection event. * Returns true if the throughput is zero and traversal can be aborted. */ @@ -49,11 +85,8 @@ ccl_device_forceinline bool shadow_handle_transparent_isect( path_state_modify_bounce(state, true); shader_eval_surface(kg, shadow_sd, - NULL, state, - 0.0f, - PATH_RAY_SHADOW, - SHADER_CONTEXT_SHADOW); + PATH_RAY_SHADOW); path_state_modify_bounce(state, false); *throughput *= shader_bsdf_transparency(kg, shadow_sd); } @@ -72,13 +105,14 @@ ccl_device_forceinline bool shadow_handle_transparent_isect( ccl_device bool shadow_blocked_opaque(KernelGlobals *kg, ShaderData *shadow_sd, ccl_addr_space PathState *state, + const uint visibility, Ray *ray, Intersection *isect, float3 *shadow) { const bool blocked = scene_intersect(kg, *ray, - PATH_RAY_SHADOW_OPAQUE, + visibility & PATH_RAY_SHADOW_OPAQUE, isect, NULL, 0.0f, 0.0f); @@ -126,9 +160,10 @@ ccl_device bool shadow_blocked_opaque(KernelGlobals *kg, * Note that hits array should be as big as max_hits+1. */ ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg, + ShaderData *sd, ShaderData *shadow_sd, ccl_addr_space PathState *state, - const int skip_object, + const uint visibility, Ray *ray, Intersection *hits, uint max_hits, @@ -141,9 +176,12 @@ ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg, const bool blocked = scene_intersect_shadow_all(kg, ray, hits, - skip_object, + visibility, max_hits, &num_hits); +# ifdef __VOLUME__ + VolumeState volume_state; +# endif /* If no opaque surface found but we did find transparent hits, * shade them. */ @@ -155,12 +193,13 @@ ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg, Intersection *isect = hits; # ifdef __VOLUME__ # ifdef __SPLIT_KERNEL__ - ccl_addr_space PathState *ps = &kernel_split_state.state_shadow[ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0)]; -# else - PathState ps_object; - PathState *ps = &ps_object; + ccl_addr_space # endif - *ps = *state; + PathState *ps = shadow_blocked_volume_path_state(kg, + &volume_state, + state, + sd, + ray); # endif sort_intersections(hits, num_hits); for(int hit = 0; hit < num_hits; hit++, isect++) { @@ -205,8 +244,16 @@ ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg, } # ifdef __VOLUME__ if(!blocked && state->volume_stack[0].shader != SHADER_NONE) { - /* Apply attenuation from current volume shader/ */ - kernel_volume_shadow(kg, shadow_sd, state, ray, shadow); + /* Apply attenuation from current volume shader. */ +# ifdef __SPLIT_KERNEL__ + ccl_addr_space +# endif + PathState *ps = shadow_blocked_volume_path_state(kg, + &volume_state, + state, + sd, + ray); + kernel_volume_shadow(kg, shadow_sd, ps, ray, shadow); } # endif return blocked; @@ -216,9 +263,10 @@ ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg, * loop to help readability of the actual logic. */ ccl_device bool shadow_blocked_transparent_all(KernelGlobals *kg, + ShaderData *sd, ShaderData *shadow_sd, ccl_addr_space PathState *state, - const int skip_object, + const uint visibility, Ray *ray, uint max_hits, float3 *shadow) @@ -251,9 +299,10 @@ ccl_device bool shadow_blocked_transparent_all(KernelGlobals *kg, # endif /* __KERNEL_GPU__ */ /* Invoke actual traversal. */ return shadow_blocked_transparent_all_loop(kg, + sd, shadow_sd, state, - skip_object, + visibility, ray, hits, max_hits, @@ -276,27 +325,32 @@ ccl_device bool shadow_blocked_transparent_all(KernelGlobals *kg, */ ccl_device bool shadow_blocked_transparent_stepped_loop( KernelGlobals *kg, + ShaderData *sd, ShaderData *shadow_sd, ccl_addr_space PathState *state, - const int skip_object, + const uint visibility, Ray *ray, Intersection *isect, const bool blocked, const bool is_transparent_isect, float3 *shadow) { - if((blocked && is_transparent_isect) || skip_object != OBJECT_NONE) { +# ifdef __VOLUME__ + VolumeState volume_state; +# endif + if(blocked && is_transparent_isect) { float3 throughput = make_float3(1.0f, 1.0f, 1.0f); float3 Pend = ray->P + ray->D*ray->t; int bounce = state->transparent_bounce; # ifdef __VOLUME__ # ifdef __SPLIT_KERNEL__ - ccl_addr_space PathState *ps = &kernel_split_state.state_shadow[ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0)]; -# else - PathState ps_object; - PathState *ps = &ps_object; + ccl_addr_space # endif - *ps = *state; + PathState *ps = shadow_blocked_volume_path_state(kg, + &volume_state, + state, + sd, + ray); # endif for(;;) { if(bounce >= kernel_data.integrator.transparent_max_bounce) { @@ -304,30 +358,13 @@ ccl_device bool shadow_blocked_transparent_stepped_loop( } if(!scene_intersect(kg, *ray, - PATH_RAY_SHADOW_TRANSPARENT, + visibility & PATH_RAY_SHADOW_TRANSPARENT, isect, NULL, 0.0f, 0.0f)) { break; } -#ifdef __SHADOW_TRICKS__ - if(skip_object != OBJECT_NONE) { - const int isect_object = (isect->object == PRIM_NONE) - ? kernel_tex_fetch(__prim_object, isect->prim) - : isect->object; - if(isect_object == skip_object) { - shader_setup_from_ray(kg, shadow_sd, isect, ray); - /* Move ray forward. */ - ray->P = ray_offset(shadow_sd->P, -shadow_sd->Ng); - if(ray->t != FLT_MAX) { - ray->D = normalize_len(Pend - ray->P, &ray->t); - } - bounce++; - continue; - } - } -#endif if(!shader_transparent_shadow(kg, isect)) { return true; } @@ -363,7 +400,15 @@ ccl_device bool shadow_blocked_transparent_stepped_loop( # ifdef __VOLUME__ if(!blocked && state->volume_stack[0].shader != SHADER_NONE) { /* Apply attenuation from current volume shader. */ - kernel_volume_shadow(kg, shadow_sd, state, ray, shadow); +# ifdef __SPLIT_KERNEL__ + ccl_addr_space +# endif + PathState *ps = shadow_blocked_volume_path_state(kg, + &volume_state, + state, + sd, + ray); + kernel_volume_shadow(kg, shadow_sd, ps, ray, shadow); } # endif return blocked; @@ -371,33 +416,28 @@ ccl_device bool shadow_blocked_transparent_stepped_loop( ccl_device bool shadow_blocked_transparent_stepped( KernelGlobals *kg, + ShaderData *sd, ShaderData *shadow_sd, ccl_addr_space PathState *state, - const int skip_object, + const uint visibility, Ray *ray, Intersection *isect, float3 *shadow) { - bool blocked, is_transparent_isect; - if(skip_object == OBJECT_NONE) { - blocked = scene_intersect(kg, - *ray, - PATH_RAY_SHADOW_OPAQUE, - isect, - NULL, - 0.0f, 0.0f); - is_transparent_isect = blocked - ? shader_transparent_shadow(kg, isect) - : false; - } - else { - blocked = false; - is_transparent_isect = false; - } + bool blocked = scene_intersect(kg, + *ray, + visibility & PATH_RAY_SHADOW_OPAQUE, + isect, + NULL, + 0.0f, 0.0f); + bool is_transparent_isect = blocked + ? shader_transparent_shadow(kg, isect) + : false; return shadow_blocked_transparent_stepped_loop(kg, + sd, shadow_sd, state, - skip_object, + visibility, ray, isect, blocked, @@ -409,6 +449,7 @@ ccl_device bool shadow_blocked_transparent_stepped( #endif /* __TRANSPARENT_SHADOWS__ */ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, + ShaderData *sd, ShaderData *shadow_sd, ccl_addr_space PathState *state, Ray *ray_input, @@ -422,25 +463,24 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, return false; } #ifdef __SHADOW_TRICKS__ - const int skip_object = state->catcher_object; + const uint visibility = (state->flag & PATH_RAY_SHADOW_CATCHER) + ? PATH_RAY_SHADOW_NON_CATCHER + : PATH_RAY_SHADOW; #else - const int skip_object = OBJECT_NONE; + const uint visibility = PATH_RAY_SHADOW; #endif /* Do actual shadow shading. */ /* First of all, we check if integrator requires transparent shadows. * if not, we use simplest and fastest ever way to calculate occlusion. - * - * NOTE: We can't do quick opaque test here if we are on shadow-catcher - * path because we don't want catcher object to be casting shadow here. */ #ifdef __TRANSPARENT_SHADOWS__ - if(!kernel_data.integrator.transparent_shadows && - skip_object == OBJECT_NONE) + if(!kernel_data.integrator.transparent_shadows) #endif { return shadow_blocked_opaque(kg, shadow_sd, state, + visibility, ray, &isect, shadow); @@ -467,7 +507,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, */ const bool blocked = scene_intersect(kg, *ray, - PATH_RAY_SHADOW_OPAQUE, + visibility & PATH_RAY_SHADOW_OPAQUE, &isect, NULL, 0.0f, 0.0f); @@ -478,9 +518,10 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, max_hits + 1 >= SHADOW_STACK_MAX_HITS) { return shadow_blocked_transparent_stepped_loop(kg, + sd, shadow_sd, state, - skip_object, + visibility, ray, &isect, blocked, @@ -489,18 +530,20 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, } # endif /* __KERNEL_GPU__ */ return shadow_blocked_transparent_all(kg, + sd, shadow_sd, state, - skip_object, + visibility, ray, max_hits, shadow); # else /* __SHADOW_RECORD_ALL__ */ /* Fallback to a slowest version which works on all devices. */ return shadow_blocked_transparent_stepped(kg, + sd, shadow_sd, state, - skip_object, + visibility, ray, &isect, shadow); diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index 6475d4b66fd..23a09e5e2ca 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -28,87 +28,31 @@ CCL_NAMESPACE_BEGIN * - try to reduce one sample model variance */ -#define BSSRDF_MULTI_EVAL - -ccl_device ShaderClosure *subsurface_scatter_pick_closure(KernelGlobals *kg, ShaderData *sd, float *probability) -{ - /* sum sample weights of bssrdf and bsdf */ - float bsdf_sum = 0.0f; - float bssrdf_sum = 0.0f; - - for(int i = 0; i < sd->num_closure; i++) { - ShaderClosure *sc = &sd->closure[i]; - - if(CLOSURE_IS_BSDF(sc->type)) - bsdf_sum += sc->sample_weight; - else if(CLOSURE_IS_BSSRDF(sc->type)) - bssrdf_sum += sc->sample_weight; - } - - /* use bsdf or bssrdf? */ - float r = sd->randb_closure*(bsdf_sum + bssrdf_sum); - - if(r < bsdf_sum) { - /* use bsdf, and adjust randb so we can reuse it for picking a bsdf */ - sd->randb_closure = r/bsdf_sum; - *probability = (bsdf_sum > 0.0f)? (bsdf_sum + bssrdf_sum)/bsdf_sum: 1.0f; - return NULL; - } - - /* use bssrdf */ - r -= bsdf_sum; - - float sum = 0.0f; - - for(int i = 0; i < sd->num_closure; i++) { - ShaderClosure *sc = &sd->closure[i]; - - if(CLOSURE_IS_BSSRDF(sc->type)) { - sum += sc->sample_weight; - - if(r <= sum) { - sd->randb_closure = (r - (sum - sc->sample_weight))/sc->sample_weight; - -#ifdef BSSRDF_MULTI_EVAL - *probability = (bssrdf_sum > 0.0f)? (bsdf_sum + bssrdf_sum)/bssrdf_sum: 1.0f; -#else - *probability = (bssrdf_sum > 0.0f)? (bsdf_sum + bssrdf_sum)/sc->sample_weight: 1.0f; -#endif - return sc; - } - } - } - - /* should never happen */ - sd->randb_closure = 0.0f; - *probability = 1.0f; - return NULL; -} - ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd, - ShaderClosure *sc, + const ShaderClosure *sc, float disk_r, float r, bool all) { -#ifdef BSSRDF_MULTI_EVAL /* this is the veach one-sample model with balance heuristic, some pdf * factors drop out when using balance heuristic weighting */ float3 eval_sum = make_float3(0.0f, 0.0f, 0.0f); float pdf_sum = 0.0f; - float sample_weight_sum = 0.0f; - int num_bssrdf = 0; + float sample_weight_inv = 0.0f; - for(int i = 0; i < sd->num_closure; i++) { - sc = &sd->closure[i]; - - if(CLOSURE_IS_BSSRDF(sc->type)) { - float sample_weight = (all)? 1.0f: sc->sample_weight; - sample_weight_sum += sample_weight; + if(!all) { + float sample_weight_sum = 0.0f; + + for(int i = 0; i < sd->num_closure; i++) { + sc = &sd->closure[i]; + + if(CLOSURE_IS_BSSRDF(sc->type)) { + sample_weight_sum += sc->sample_weight; + } } - } - float sample_weight_inv = 1.0f/sample_weight_sum; + sample_weight_inv = 1.0f/sample_weight_sum; + } for(int i = 0; i < sd->num_closure; i++) { sc = &sd->closure[i]; @@ -125,25 +69,16 @@ ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd, /* TODO power heuristic is not working correct here */ eval_sum += sc->weight*pdf; //*sample_weight*disk_pdf; pdf_sum += sample_weight*disk_pdf; //*sample_weight*disk_pdf; - - num_bssrdf++; } } return (pdf_sum > 0.0f)? eval_sum / pdf_sum : make_float3(0.0f, 0.0f, 0.0f); -#else - float pdf = bssrdf_pdf(pick_sc, r); - float disk_pdf = bssrdf_pdf(pick_sc, disk_r); - - return pick_sc->weight * pdf / disk_pdf; -#endif } /* replace closures with a single diffuse bsdf closure after scatter step */ -ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, ShaderClosure *sc, float3 weight, bool hit, float3 N) +ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, const ShaderClosure *sc, float3 weight, bool hit, float3 N) { sd->flag &= ~SD_CLOSURE_FLAGS; - sd->randb_closure = 0.0f; sd->num_closure = 0; sd->num_closure_extra = 0; @@ -219,7 +154,7 @@ ccl_device void subsurface_color_bump_blur(KernelGlobals *kg, if(bump || texture_blur > 0.0f) { /* average color and normal at incoming point */ - shader_eval_surface(kg, sd, NULL, state, 0.0f, state_flag, SHADER_CONTEXT_SSS); + shader_eval_surface(kg, sd, state, state_flag); float3 in_color = shader_bssrdf_sum(sd, (bump)? N: NULL, NULL); /* we simply divide out the average color and multiply with the average @@ -242,8 +177,8 @@ ccl_device_inline int subsurface_scatter_multi_intersect( KernelGlobals *kg, SubsurfaceIntersection *ss_isect, ShaderData *sd, - ShaderClosure *sc, - RNG *lcg_state, + const ShaderClosure *sc, + uint *lcg_state, float disk_u, float disk_v, bool all) @@ -255,26 +190,20 @@ ccl_device_inline int subsurface_scatter_multi_intersect( disk_N = sd->Ng; make_orthonormals(disk_N, &disk_T, &disk_B); - /* reusing variable for picking the closure gives a bit nicer stratification - * for path tracer, for branched we do all closures so it doesn't help */ - float axisu = (all)? disk_u: sd->randb_closure; - - if(axisu < 0.5f) { + if(disk_u < 0.5f) { pick_pdf_N = 0.5f; pick_pdf_T = 0.25f; pick_pdf_B = 0.25f; - if(all) - disk_u *= 2.0f; + disk_u *= 2.0f; } - else if(axisu < 0.75f) { + else if(disk_u < 0.75f) { float3 tmp = disk_N; disk_N = disk_T; disk_T = tmp; pick_pdf_N = 0.25f; pick_pdf_T = 0.5f; pick_pdf_B = 0.25f; - if(all) - disk_u = (disk_u - 0.5f)*4.0f; + disk_u = (disk_u - 0.5f)*4.0f; } else { float3 tmp = disk_N; @@ -283,8 +212,7 @@ ccl_device_inline int subsurface_scatter_multi_intersect( pick_pdf_N = 0.25f; pick_pdf_T = 0.25f; pick_pdf_B = 0.5f; - if(all) - disk_u = (disk_u - 0.75f)*4.0f; + disk_u = (disk_u - 0.75f)*4.0f; } /* sample point on disk */ @@ -390,7 +318,7 @@ ccl_device_noinline void subsurface_scatter_multi_setup( ShaderData *sd, ccl_addr_space PathState *state, int state_flag, - ShaderClosure *sc, + const ShaderClosure *sc, bool all) { #ifdef __SPLIT_KERNEL__ @@ -419,7 +347,7 @@ ccl_device_noinline void subsurface_scatter_multi_setup( /* subsurface scattering step, from a point on the surface to another nearby point on the same object */ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state, - int state_flag, ShaderClosure *sc, uint *lcg_state, float disk_u, float disk_v, bool all) + int state_flag, const ShaderClosure *sc, uint *lcg_state, float disk_u, float disk_v, bool all) { float3 eval = make_float3(0.0f, 0.0f, 0.0f); @@ -430,18 +358,20 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, ccl_a disk_N = sd->Ng; make_orthonormals(disk_N, &disk_T, &disk_B); - if(sd->randb_closure < 0.5f) { + if(disk_u < 0.5f) { pick_pdf_N = 0.5f; pick_pdf_T = 0.25f; pick_pdf_B = 0.25f; + disk_u *= 2.0f; } - else if(sd->randb_closure < 0.75f) { + else if(disk_u < 0.75f) { float3 tmp = disk_N; disk_N = disk_T; disk_T = tmp; pick_pdf_N = 0.25f; pick_pdf_T = 0.5f; pick_pdf_B = 0.25f; + disk_u = (disk_u - 0.5f)*4.0f; } else { float3 tmp = disk_N; @@ -450,6 +380,7 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, ccl_a pick_pdf_N = 0.25f; pick_pdf_T = 0.25f; pick_pdf_B = 0.5f; + disk_u = (disk_u - 0.75f)*4.0f; } /* sample point on disk */ diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index cb1a3f40dee..5eab28a2953 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -82,115 +82,110 @@ KERNEL_TEX(uint, texture_uint, __sobol_directions) # if __CUDA_ARCH__ < 300 /* full-float image */ KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float4_000) -KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float4_001) -KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float4_002) -KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float4_003) -KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float4_004) +KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float4_008) +KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float4_016) +KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float4_024) +KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float4_032) KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float4_3d_000) -KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float4_3d_001) -KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float4_3d_002) -KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float4_3d_003) -KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float4_3d_004) - -/* image */ -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_005) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_006) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_007) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_008) +KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float4_3d_008) +KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float4_3d_016) +KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float4_3d_024) +KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float4_3d_032) + +/* image + * These texture names are encoded to their flattened slots as + * ImageManager::type_index_to_flattened_slot() returns them. */ +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_001) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_009) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_010) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_011) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_012) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_013) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_014) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_015) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_016) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_017) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_018) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_019) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_020) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_021) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_022) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_023) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_024) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_025) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_026) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_027) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_028) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_029) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_030) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_031) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_032) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_033) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_034) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_035) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_036) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_037) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_038) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_039) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_040) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_041) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_042) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_043) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_044) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_045) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_046) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_047) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_048) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_049) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_050) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_051) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_052) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_053) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_054) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_055) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_056) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_057) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_058) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_059) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_060) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_061) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_062) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_063) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_064) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_065) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_066) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_067) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_068) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_069) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_070) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_071) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_072) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_073) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_074) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_075) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_076) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_077) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_078) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_079) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_080) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_081) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_082) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_083) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_084) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_085) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_086) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_087) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_088) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_089) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_097) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_105) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_113) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_121) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_129) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_137) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_145) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_153) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_161) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_169) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_177) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_185) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_193) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_201) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_209) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_217) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_225) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_233) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_241) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_249) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_257) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_265) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_273) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_281) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_289) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_297) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_305) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_313) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_321) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_329) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_337) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_345) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_353) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_361) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_369) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_377) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_385) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_393) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_401) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_409) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_417) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_425) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_433) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_441) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_449) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_457) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_465) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_473) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_481) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_489) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_497) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_505) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_513) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_521) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_529) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_537) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_545) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_553) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_561) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_569) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_577) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_585) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_593) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_601) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_609) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_617) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_625) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_633) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_641) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_649) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_657) +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_665) # else /* bindless textures */ KERNEL_TEX(uint, texture_uint, __bindless_mapping) -# endif -#endif - -/* packed image (opencl) */ -KERNEL_TEX(uchar4, texture_uchar4, __tex_image_byte4_packed) -KERNEL_TEX(float4, texture_float4, __tex_image_float4_packed) -KERNEL_TEX(uchar, texture_uchar, __tex_image_byte_packed) -KERNEL_TEX(float, texture_float, __tex_image_float_packed) -KERNEL_TEX(uint4, texture_uint4, __tex_image_packed_info) +# endif /* __CUDA_ARCH__ */ +#endif /* __KERNEL_CUDA__ */ #undef KERNEL_TEX #undef KERNEL_IMAGE_TEX diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 34affab1b9d..6c5b6ca3b2d 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -130,6 +130,7 @@ CCL_NAMESPACE_BEGIN # ifdef __KERNEL_OPENCL_APPLE__ # define __KERNEL_SHADING__ # define __KERNEL_ADV_SHADING__ +# define __PRINCIPLED__ # define __CMJ__ /* TODO(sergey): Currently experimental section is ignored here, * this is because megakernel in device_opencl does not support @@ -154,6 +155,7 @@ CCL_NAMESPACE_BEGIN # define __CL_USE_NATIVE__ # define __KERNEL_SHADING__ # define __KERNEL_ADV_SHADING__ +# define __PRINCIPLED__ # define __CMJ__ # endif /* __KERNEL_OPENCL_INTEL_CPU__ */ @@ -240,10 +242,6 @@ CCL_NAMESPACE_BEGIN # undef __DENOISING_FEATURES__ #endif -/* Random Numbers */ - -typedef uint RNG; - /* Shader Evaluation */ typedef enum ShaderEvalType { @@ -283,31 +281,21 @@ enum PathTraceDimension { PRNG_FILTER_V = 1, PRNG_LENS_U = 2, PRNG_LENS_V = 3, -#ifdef __CAMERA_MOTION__ PRNG_TIME = 4, PRNG_UNUSED_0 = 5, PRNG_UNUSED_1 = 6, /* for some reason (6, 7) is a bad sobol pattern */ PRNG_UNUSED_2 = 7, /* with a low number of samples (< 64) */ -#endif - PRNG_BASE_NUM = 8, + PRNG_BASE_NUM = 10, PRNG_BSDF_U = 0, PRNG_BSDF_V = 1, - PRNG_BSDF = 2, - PRNG_LIGHT = 3, - PRNG_LIGHT_U = 4, - PRNG_LIGHT_V = 5, - PRNG_LIGHT_TERMINATE = 6, - PRNG_TERMINATE = 7, - -#ifdef __VOLUME__ - PRNG_PHASE_U = 8, - PRNG_PHASE_V = 9, - PRNG_PHASE = 10, - PRNG_SCATTER_DISTANCE = 11, -#endif - - PRNG_BOUNCE_NUM = 12, + PRNG_LIGHT_U = 2, + PRNG_LIGHT_V = 3, + PRNG_LIGHT_TERMINATE = 4, + PRNG_TERMINATE = 5, + PRNG_PHASE_CHANNEL = 6, + PRNG_SCATTER_DISTANCE = 7, + PRNG_BOUNCE_NUM = 8, }; enum SamplingPattern { @@ -328,24 +316,28 @@ enum PathRayFlag { PATH_RAY_SINGULAR = (1 << 5), PATH_RAY_TRANSPARENT = (1 << 6), - PATH_RAY_SHADOW_OPAQUE = (1 << 7), - PATH_RAY_SHADOW_TRANSPARENT = (1 << 8), - PATH_RAY_SHADOW = (PATH_RAY_SHADOW_OPAQUE|PATH_RAY_SHADOW_TRANSPARENT), + PATH_RAY_SHADOW_OPAQUE_NON_CATCHER = (1 << 7), + PATH_RAY_SHADOW_OPAQUE_CATCHER = (1 << 8), + PATH_RAY_SHADOW_OPAQUE = (PATH_RAY_SHADOW_OPAQUE_NON_CATCHER|PATH_RAY_SHADOW_OPAQUE_CATCHER), + PATH_RAY_SHADOW_TRANSPARENT_NON_CATCHER = (1 << 9), + PATH_RAY_SHADOW_TRANSPARENT_CATCHER = (1 << 10), + PATH_RAY_SHADOW_TRANSPARENT = (PATH_RAY_SHADOW_TRANSPARENT_NON_CATCHER|PATH_RAY_SHADOW_TRANSPARENT_CATCHER), + PATH_RAY_SHADOW_NON_CATCHER = (PATH_RAY_SHADOW_OPAQUE_NON_CATCHER|PATH_RAY_SHADOW_TRANSPARENT_NON_CATCHER), + PATH_RAY_SHADOW = (PATH_RAY_SHADOW_OPAQUE|PATH_RAY_SHADOW_TRANSPARENT), - PATH_RAY_CURVE = (1 << 9), /* visibility flag to define curve segments */ - PATH_RAY_VOLUME_SCATTER = (1 << 10), /* volume scattering */ + PATH_RAY_CURVE = (1 << 11), /* visibility flag to define curve segments */ + PATH_RAY_VOLUME_SCATTER = (1 << 12), /* volume scattering */ /* Special flag to tag unaligned BVH nodes. */ - PATH_RAY_NODE_UNALIGNED = (1 << 11), + PATH_RAY_NODE_UNALIGNED = (1 << 13), - PATH_RAY_ALL_VISIBILITY = ((1 << 12)-1), + PATH_RAY_ALL_VISIBILITY = ((1 << 14)-1), - PATH_RAY_MIS_SKIP = (1 << 12), - PATH_RAY_DIFFUSE_ANCESTOR = (1 << 13), - PATH_RAY_SINGLE_PASS_DONE = (1 << 14), - PATH_RAY_SHADOW_CATCHER = (1 << 15), - PATH_RAY_SHADOW_CATCHER_ONLY = (1 << 16), - PATH_RAY_STORE_SHADOW_INFO = (1 << 17), + PATH_RAY_MIS_SKIP = (1 << 15), + PATH_RAY_DIFFUSE_ANCESTOR = (1 << 16), + PATH_RAY_SINGLE_PASS_DONE = (1 << 17), + PATH_RAY_SHADOW_CATCHER = (1 << 18), + PATH_RAY_STORE_SHADOW_INFO = (1 << 19), }; /* Closure Label */ @@ -462,18 +454,42 @@ typedef enum DenoiseFlag { DENOISING_CLEAN_ALL_PASSES = (1 << 8)-1, } DenoiseFlag; +#ifdef __KERNEL_DEBUG__ +/* NOTE: This is a runtime-only struct, alignment is not + * really important here. + */ +typedef struct DebugData { + int num_bvh_traversed_nodes; + int num_bvh_traversed_instances; + int num_bvh_intersections; + int num_ray_bounces; +} DebugData; +#endif + +typedef ccl_addr_space struct PathRadianceState { +#ifdef __PASSES__ + float3 diffuse; + float3 glossy; + float3 transmission; + float3 subsurface; + float3 scatter; + + float3 direct; +#endif +} PathRadianceState; + typedef ccl_addr_space struct PathRadiance { #ifdef __PASSES__ int use_light_pass; #endif + float transparent; float3 emission; #ifdef __PASSES__ float3 background; float3 ao; float3 indirect; - float3 direct_throughput; float3 direct_emission; float3 color_diffuse; @@ -494,16 +510,12 @@ typedef ccl_addr_space struct PathRadiance { float3 indirect_subsurface; float3 indirect_scatter; - float3 path_diffuse; - float3 path_glossy; - float3 path_transmission; - float3 path_subsurface; - float3 path_scatter; - float4 shadow; float mist; #endif + struct PathRadianceState state; + #ifdef __SHADOW_TRICKS__ /* Total light reachable across the path, ignoring shadow blocked queries. */ float3 path_total; @@ -515,7 +527,18 @@ typedef ccl_addr_space struct PathRadiance { float3 path_total_shaded; /* Color of the background on which shadow is alpha-overed. */ - float3 shadow_color; + float3 shadow_background_color; + + /* Path radiance sum and throughput at the moment when ray hits shadow + * catcher object. + */ + float shadow_throughput; + + /* Accumulated transparency along the path after shadow catcher bounce. */ + float shadow_transparency; + + /* Indicate if any shadow catcher data is set. */ + int has_shadow_catcher; #endif #ifdef __DENOISING_FEATURES__ @@ -523,6 +546,10 @@ typedef ccl_addr_space struct PathRadiance { float3 denoising_albedo; float denoising_depth; #endif /* __DENOISING_FEATURES__ */ + +#ifdef __KERNEL_DEBUG__ + DebugData debug_data; +#endif /* __KERNEL_DEBUG__ */ } PathRadiance; typedef struct BsdfEval { @@ -774,20 +801,6 @@ typedef ccl_addr_space struct ccl_align(16) ShaderClosure { float data[10]; /* pad to 80 bytes */ } ShaderClosure; -/* Shader Context - * - * For OSL we recycle a fixed number of contexts for speed */ - -typedef enum ShaderContext { - SHADER_CONTEXT_MAIN = 0, - SHADER_CONTEXT_INDIRECT = 1, - SHADER_CONTEXT_EMISSION = 2, - SHADER_CONTEXT_SHADOW = 3, - SHADER_CONTEXT_SSS = 4, - SHADER_CONTEXT_VOLUME = 5, - SHADER_CONTEXT_NUM = 6 -} ShaderContext; - /* Shader Data * * Main shader state at a point on the surface or in a volume. All coordinates @@ -850,7 +863,7 @@ enum ShaderDataFlag { SD_VOLUME_MIS = (1 << 23), /* Use cubic interpolation for voxels. */ SD_VOLUME_CUBIC = (1 << 24), - /* Has data connected to the displacement input. */ + /* Has data connected to the displacement input or uses bump map. */ SD_HAS_BUMP = (1 << 25), /* Has true displacement. */ SD_HAS_DISPLACEMENT = (1 << 26), @@ -991,9 +1004,11 @@ typedef struct PathState { int flag; /* random number generator state */ - int rng_offset; /* dimension offset */ - int sample; /* path sample number */ - int num_samples; /* total number of times this path will be sampled */ + uint rng_hash; /* per pixel hash */ + int rng_offset; /* dimension offset */ + int sample; /* path sample number */ + int num_samples; /* total number of times this path will be sampled */ + float branch_factor; /* number of branches in indirect paths */ /* bounce counting */ int bounce; @@ -1016,20 +1031,15 @@ typedef struct PathState { /* volume rendering */ #ifdef __VOLUME__ int volume_bounce; - RNG rng_congruential; + uint rng_congruential; VolumeStack volume_stack[VOLUME_STACK_SIZE]; #endif - -#ifdef __SHADOW_TRICKS__ - int catcher_object; -#endif } PathState; /* Subsurface */ /* Struct to gather multiple SSS hits. */ -typedef struct SubsurfaceIntersection -{ +typedef struct SubsurfaceIntersection { Ray ray; float3 weight[BSSRDF_MAX_HITS]; @@ -1039,17 +1049,14 @@ typedef struct SubsurfaceIntersection } SubsurfaceIntersection; /* Struct to gather SSS indirect rays and delay tracing them. */ -typedef struct SubsurfaceIndirectRays -{ - bool need_update_volume_stack; - bool tracing; +typedef struct SubsurfaceIndirectRays { PathState state[BSSRDF_MAX_HITS]; - struct PathRadiance direct_L; int num_rays; + struct Ray rays[BSSRDF_MAX_HITS]; float3 throughputs[BSSRDF_MAX_HITS]; - struct PathRadiance L[BSSRDF_MAX_HITS]; + struct PathRadianceState L_state[BSSRDF_MAX_HITS]; } SubsurfaceIndirectRays; /* Constant Kernel Data @@ -1228,7 +1235,6 @@ typedef struct KernelIntegrator { int portal_offset; /* bounces */ - int min_bounce; int max_bounce; int max_diffuse_bounce; @@ -1239,7 +1245,6 @@ typedef struct KernelIntegrator { int ao_bounces; /* transparent */ - int transparent_min_bounce; int transparent_max_bounce; int transparent_shadows; @@ -1282,7 +1287,7 @@ typedef struct KernelIntegrator { float light_inv_rr_threshold; int start_sample; - int pad1, pad2, pad3; + int pad1; } KernelIntegrator; static_assert_align(KernelIntegrator, 16); @@ -1336,18 +1341,6 @@ typedef struct KernelData { } KernelData; static_assert_align(KernelData, 16); -#ifdef __KERNEL_DEBUG__ -/* NOTE: This is a runtime-only struct, alignment is not - * really important here. - */ -typedef ccl_addr_space struct DebugData { - int num_bvh_traversed_nodes; - int num_bvh_traversed_instances; - int num_bvh_intersections; - int num_ray_bounces; -} DebugData; -#endif - /* Declarations required for split kernel */ /* Macro for queues */ diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index 1e472aaf51a..d9c310a893e 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -43,7 +43,7 @@ ccl_device_inline bool volume_shader_extinction_sample(KernelGlobals *kg, float3 *extinction) { sd->P = P; - shader_eval_volume(kg, sd, state, state->volume_stack, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); + shader_eval_volume(kg, sd, state, state->volume_stack, PATH_RAY_SHADOW); if(!(sd->flag & (SD_ABSORPTION|SD_SCATTER))) return false; @@ -69,7 +69,7 @@ ccl_device_inline bool volume_shader_sample(KernelGlobals *kg, VolumeShaderCoefficients *coeff) { sd->P = P; - shader_eval_volume(kg, sd, state, state->volume_stack, state->flag, SHADER_CONTEXT_VOLUME); + shader_eval_volume(kg, sd, state, state->volume_stack, state->flag); if(!(sd->flag & (SD_ABSORPTION|SD_SCATTER|SD_EMISSION))) return false; @@ -360,7 +360,6 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous( ShaderData *sd, PathRadiance *L, ccl_addr_space float3 *throughput, - RNG *rng, bool probalistic_scatter) { VolumeShaderCoefficients coeff; @@ -380,13 +379,12 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous( /* pick random color channel, we use the Veach one-sample * model with balance heuristic for the channels */ - float rphase = path_state_rng_1D_for_decision(kg, rng, state, PRNG_PHASE); + float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL); int channel = (int)(rphase*3.0f); - sd->randb_closure = rphase*3.0f - channel; /* decide if we will hit or miss */ bool scatter = true; - float xi = path_state_rng_1D_for_decision(kg, rng, state, PRNG_SCATTER_DISTANCE); + float xi = path_state_rng_1D(kg, state, PRNG_SCATTER_DISTANCE); if(probalistic_scatter) { float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel); @@ -439,7 +437,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous( float3 sigma_t = coeff.sigma_a + coeff.sigma_s; float3 transmittance = volume_color_transmittance(sigma_t, ray->t); float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, ray->t); - path_radiance_accum_emission(L, *throughput, emission, state->bounce); + path_radiance_accum_emission(L, state, *throughput, emission); } /* modify throughput */ @@ -468,8 +466,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance( Ray *ray, ShaderData *sd, PathRadiance *L, - ccl_addr_space float3 *throughput, - RNG *rng) + ccl_addr_space float3 *throughput) { float3 tp = *throughput; const float tp_eps = 1e-6f; /* todo: this is likely not the right value */ @@ -485,10 +482,9 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance( /* pick random color channel, we use the Veach one-sample * model with balance heuristic for the channels */ - float xi = path_state_rng_1D_for_decision(kg, rng, state, PRNG_SCATTER_DISTANCE); - float rphase = path_state_rng_1D_for_decision(kg, rng, state, PRNG_PHASE); + float xi = path_state_rng_1D(kg, state, PRNG_SCATTER_DISTANCE); + float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL); int channel = (int)(rphase*3.0f); - sd->randb_closure = rphase*3.0f - channel; bool has_scatter = false; for(int i = 0; i < max_steps; i++) { @@ -560,7 +556,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance( /* integrate emission attenuated by absorption */ if(L && (closure_flag & SD_EMISSION)) { float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, dt); - path_radiance_accum_emission(L, tp, emission, state->bounce); + path_radiance_accum_emission(L, state, tp, emission); } /* modify throughput */ @@ -610,15 +606,14 @@ ccl_device_noinline VolumeIntegrateResult kernel_volume_integrate( Ray *ray, PathRadiance *L, ccl_addr_space float3 *throughput, - RNG *rng, bool heterogeneous) { shader_setup_from_volume(kg, sd, ray); if(heterogeneous) - return kernel_volume_integrate_heterogeneous_distance(kg, state, ray, sd, L, throughput, rng); + return kernel_volume_integrate_heterogeneous_distance(kg, state, ray, sd, L, throughput); else - return kernel_volume_integrate_homogeneous(kg, state, ray, sd, L, throughput, rng, true); + return kernel_volume_integrate_homogeneous(kg, state, ray, sd, L, throughput, true); } #ifndef __SPLIT_KERNEL__ @@ -846,7 +841,6 @@ ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter( /* pick random color channel, we use the Veach one-sample * model with balance heuristic for the channels */ int channel = (int)(rphase*3.0f); - sd->randb_closure = rphase*3.0f - channel; float xi = rscatter; /* probabilistic scattering decision based on transmittance */ @@ -1000,8 +994,8 @@ ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter( mis_weight = 2.0f*power_heuristic(pdf, distance_pdf); } } - if(sample_t < 1e-6f || pdf == 0.0f) { - return VOLUME_PATH_SCATTERED; + if(sample_t < 0.0f || pdf == 0.0f) { + return VOLUME_PATH_MISSED; } /* compute transmittance up to this step */ diff --git a/intern/cycles/kernel/kernel_work_stealing.h b/intern/cycles/kernel/kernel_work_stealing.h index 28fc5ce1c30..0c11158e8da 100644 --- a/intern/cycles/kernel/kernel_work_stealing.h +++ b/intern/cycles/kernel/kernel_work_stealing.h @@ -27,90 +27,54 @@ CCL_NAMESPACE_BEGIN # pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable #endif -ccl_device_inline uint kernel_total_work_size(KernelGlobals *kg) -{ - return kernel_split_params.w * kernel_split_params.h * kernel_split_params.num_samples; -} - -ccl_device_inline uint kernel_num_work_pools(KernelGlobals *kg) -{ - return ccl_global_size(0) * ccl_global_size(1) / WORK_POOL_SIZE; -} - -ccl_device_inline uint work_pool_from_ray_index(KernelGlobals *kg, uint ray_index) -{ - return ray_index / WORK_POOL_SIZE; -} - -ccl_device_inline uint work_pool_work_size(KernelGlobals *kg, uint work_pool) -{ - uint total_work_size = kernel_total_work_size(kg); - uint num_pools = kernel_num_work_pools(kg); - - if(work_pool >= num_pools || work_pool * WORK_POOL_SIZE >= total_work_size) { - return 0; - } - - uint work_size = (total_work_size / (num_pools * WORK_POOL_SIZE)) * WORK_POOL_SIZE; - - uint remainder = (total_work_size % (num_pools * WORK_POOL_SIZE)); - if(work_pool < remainder / WORK_POOL_SIZE) { - work_size += WORK_POOL_SIZE; - } - else if(work_pool == remainder / WORK_POOL_SIZE) { - work_size += remainder % WORK_POOL_SIZE; - } - - return work_size; -} - -ccl_device_inline uint get_global_work_index(KernelGlobals *kg, uint work_index, uint ray_index) -{ - uint num_pools = kernel_num_work_pools(kg); - uint pool = work_pool_from_ray_index(kg, ray_index); - - return (work_index / WORK_POOL_SIZE) * (num_pools * WORK_POOL_SIZE) - + (pool * WORK_POOL_SIZE) - + (work_index % WORK_POOL_SIZE); -} - /* Returns true if there is work */ -ccl_device bool get_next_work(KernelGlobals *kg, ccl_private uint *work_index, uint ray_index) +ccl_device bool get_next_work(KernelGlobals *kg, + uint thread_index, + ccl_private uint *global_work_index) { - uint work_pool = work_pool_from_ray_index(kg, ray_index); - uint pool_size = work_pool_work_size(kg, work_pool); + uint total_work_size = kernel_split_params.w + * kernel_split_params.h + * kernel_split_params.num_samples; - if(pool_size == 0) { + /* With a small amount of work there may be more threads than work due to + * rounding up of global size, stop such threads immediately. */ + if(thread_index >= total_work_size) { return false; } - *work_index = atomic_fetch_and_inc_uint32(&kernel_split_params.work_pools[work_pool]); - return (*work_index < pool_size); -} + /* Increase atomic work index counter in pool. */ + uint pool = thread_index / WORK_POOL_SIZE; + uint work_index = atomic_fetch_and_inc_uint32(&kernel_split_params.work_pools[pool]); -/* This function assumes that the passed `work` is valid. */ -/* Decode sample number w.r.t. assigned `work`. */ -ccl_device uint get_work_sample(KernelGlobals *kg, uint work_index, uint ray_index) -{ - return get_global_work_index(kg, work_index, ray_index) / (kernel_split_params.w * kernel_split_params.h); -} + /* Map per-pool work index to a global work index. */ + uint global_size = ccl_global_size(0) * ccl_global_size(1); + kernel_assert(global_size % WORK_POOL_SIZE == 0); + kernel_assert(thread_index < global_size); -/* Decode pixel and tile position w.r.t. assigned `work`. */ -ccl_device void get_work_pixel_tile_position(KernelGlobals *kg, - ccl_private uint *pixel_x, - ccl_private uint *pixel_y, - ccl_private uint *tile_x, - ccl_private uint *tile_y, - uint work_index, - uint ray_index) -{ - uint pixel_index = get_global_work_index(kg, work_index, ray_index) % (kernel_split_params.w*kernel_split_params.h); + *global_work_index = (work_index / WORK_POOL_SIZE) * global_size + + (pool * WORK_POOL_SIZE) + + (work_index % WORK_POOL_SIZE); - *tile_x = pixel_index % kernel_split_params.w; - *tile_y = pixel_index / kernel_split_params.w; + /* Test if all work for this pool is done. */ + return (*global_work_index < total_work_size); +} - *pixel_x = *tile_x + kernel_split_params.x; - *pixel_y = *tile_y + kernel_split_params.y; +/* Map global work index to pixel X/Y and sample. */ +ccl_device_inline void get_work_pixel(KernelGlobals *kg, + uint global_work_index, + ccl_private uint *x, + ccl_private uint *y, + ccl_private uint *sample) +{ + uint tile_pixels = kernel_split_params.w * kernel_split_params.h; + uint sample_offset = global_work_index / tile_pixels; + uint pixel_offset = global_work_index - sample_offset * tile_pixels; + uint y_offset = pixel_offset / kernel_split_params.w; + uint x_offset = pixel_offset - y_offset * kernel_split_params.w; + + *x = kernel_split_params.x + x_offset; + *y = kernel_split_params.y + y_offset; + *sample = kernel_split_params.start_sample + sample_offset; } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernels/cpu/filter_sse41.cpp b/intern/cycles/kernel/kernels/cpu/filter_sse41.cpp index 1a7b2040da1..254025be4e2 100644 --- a/intern/cycles/kernel/kernels/cpu/filter_sse41.cpp +++ b/intern/cycles/kernel/kernels/cpu/filter_sse41.cpp @@ -25,6 +25,7 @@ #else /* SSE optimization disabled for now on 32 bit, see bug #36316 */ # if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86))) +# define __KERNEL_SSE__ # define __KERNEL_SSE2__ # define __KERNEL_SSE3__ # define __KERNEL_SSSE3__ diff --git a/intern/cycles/kernel/kernels/cuda/kernel_config.h b/intern/cycles/kernel/kernels/cuda/kernel_config.h index 9fa39dc9ebb..7ae205b7e14 100644 --- a/intern/cycles/kernel/kernels/cuda/kernel_config.h +++ b/intern/cycles/kernel/kernels/cuda/kernel_config.h @@ -81,8 +81,13 @@ # error "Unknown or unsupported CUDA architecture, can't determine launch bounds" #endif -/* compute number of threads per block and minimum blocks per multiprocessor - * given the maximum number of registers per thread */ +/* For split kernel using all registers seems fastest for now, but this + * is unlikely to be optimal once we resolve other bottlenecks. */ + +#define CUDA_KERNEL_SPLIT_MAX_REGISTERS CUDA_THREAD_MAX_REGISTERS + +/* Compute number of threads per block and minimum blocks per multiprocessor + * given the maximum number of registers per thread. */ #define CUDA_LAUNCH_BOUNDS(threads_block_width, thread_num_registers) \ __launch_bounds__( \ diff --git a/intern/cycles/kernel/kernels/cuda/kernel_split.cu b/intern/cycles/kernel/kernels/cuda/kernel_split.cu index 628891b1458..e97e87285a5 100644 --- a/intern/cycles/kernel/kernels/cuda/kernel_split.cu +++ b/intern/cycles/kernel/kernels/cuda/kernel_split.cu @@ -90,7 +90,7 @@ kernel_cuda_path_trace_data_init( #define DEFINE_SPLIT_KERNEL_FUNCTION(name) \ extern "C" __global__ void \ - CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS) \ + CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_SPLIT_MAX_REGISTERS) \ kernel_cuda_##name() \ { \ kernel_##name(NULL); \ @@ -98,7 +98,7 @@ kernel_cuda_path_trace_data_init( #define DEFINE_SPLIT_KERNEL_FUNCTION_LOCALS(name, type) \ extern "C" __global__ void \ - CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS) \ + CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_SPLIT_MAX_REGISTERS) \ kernel_cuda_##name() \ { \ ccl_local type locals; \ diff --git a/intern/cycles/kernel/kernels/opencl/filter.cl b/intern/cycles/kernel/kernels/opencl/filter.cl index ba53ba4b26f..f015ac47d8a 100644 --- a/intern/cycles/kernel/kernels/opencl/filter.cl +++ b/intern/cycles/kernel/kernels/opencl/filter.cl @@ -235,7 +235,7 @@ __kernel void kernel_ocl_filter_nlm_construct_gramian(int dx, } __kernel void kernel_ocl_filter_finalize(int w, - int h, + int h, ccl_global float *buffer, ccl_global int *rank, ccl_global float *XtWX, diff --git a/intern/cycles/kernel/kernels/opencl/kernel.cl b/intern/cycles/kernel/kernels/opencl/kernel.cl index 078acc1631e..b7108f3d0f8 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel.cl @@ -52,9 +52,7 @@ __kernel void kernel_ocl_path_trace( ccl_global float *buffer, ccl_global uint *rng_state, -#define KERNEL_TEX(type, ttype, name) \ - ccl_global type *name, -#include "kernel/kernel_textures.h" + KERNEL_BUFFER_PARAMS, int sample, int sx, int sy, int sw, int sh, int offset, int stride) @@ -63,9 +61,8 @@ __kernel void kernel_ocl_path_trace( kg->data = data; -#define KERNEL_TEX(type, ttype, name) \ - kg->name = name; -#include "kernel/kernel_textures.h" + kernel_set_buffer_pointers(kg, KERNEL_BUFFER_ARGS); + kernel_set_buffer_info(kg); int x = sx + ccl_global_id(0); int y = sy + ccl_global_id(1); @@ -82,9 +79,7 @@ __kernel void kernel_ocl_shader( ccl_global float4 *output, ccl_global float *output_luma, -#define KERNEL_TEX(type, ttype, name) \ - ccl_global type *name, -#include "kernel/kernel_textures.h" + KERNEL_BUFFER_PARAMS, int type, int sx, int sw, int offset, int sample) { @@ -92,9 +87,8 @@ __kernel void kernel_ocl_shader( kg->data = data; -#define KERNEL_TEX(type, ttype, name) \ - kg->name = name; -#include "kernel/kernel_textures.h" + kernel_set_buffer_pointers(kg, KERNEL_BUFFER_ARGS); + kernel_set_buffer_info(kg); int x = sx + ccl_global_id(0); @@ -114,9 +108,7 @@ __kernel void kernel_ocl_bake( ccl_global uint4 *input, ccl_global float4 *output, -#define KERNEL_TEX(type, ttype, name) \ - ccl_global type *name, -#include "kernel/kernel_textures.h" + KERNEL_BUFFER_PARAMS, int type, int filter, int sx, int sw, int offset, int sample) { @@ -124,9 +116,8 @@ __kernel void kernel_ocl_bake( kg->data = data; -#define KERNEL_TEX(type, ttype, name) \ - kg->name = name; -#include "kernel/kernel_textures.h" + kernel_set_buffer_pointers(kg, KERNEL_BUFFER_ARGS); + kernel_set_buffer_info(kg); int x = sx + ccl_global_id(0); @@ -144,9 +135,7 @@ __kernel void kernel_ocl_convert_to_byte( ccl_global uchar4 *rgba, ccl_global float *buffer, -#define KERNEL_TEX(type, ttype, name) \ - ccl_global type *name, -#include "kernel/kernel_textures.h" + KERNEL_BUFFER_PARAMS, float sample_scale, int sx, int sy, int sw, int sh, int offset, int stride) @@ -155,9 +144,8 @@ __kernel void kernel_ocl_convert_to_byte( kg->data = data; -#define KERNEL_TEX(type, ttype, name) \ - kg->name = name; -#include "kernel/kernel_textures.h" + kernel_set_buffer_pointers(kg, KERNEL_BUFFER_ARGS); + kernel_set_buffer_info(kg); int x = sx + ccl_global_id(0); int y = sy + ccl_global_id(1); @@ -171,9 +159,7 @@ __kernel void kernel_ocl_convert_to_half_float( ccl_global uchar4 *rgba, ccl_global float *buffer, -#define KERNEL_TEX(type, ttype, name) \ - ccl_global type *name, -#include "kernel/kernel_textures.h" + KERNEL_BUFFER_PARAMS, float sample_scale, int sx, int sy, int sw, int sh, int offset, int stride) @@ -182,9 +168,8 @@ __kernel void kernel_ocl_convert_to_half_float( kg->data = data; -#define KERNEL_TEX(type, ttype, name) \ - kg->name = name; -#include "kernel/kernel_textures.h" + kernel_set_buffer_pointers(kg, KERNEL_BUFFER_ARGS); + kernel_set_buffer_info(kg); int x = sx + ccl_global_id(0); int y = sy + ccl_global_id(1); @@ -193,7 +178,7 @@ __kernel void kernel_ocl_convert_to_half_float( kernel_film_convert_to_half_float(kg, rgba, buffer, sample_scale, x, y, offset, stride); } -__kernel void kernel_ocl_zero_buffer(ccl_global float4 *buffer, ulong size, ulong offset) +__kernel void kernel_ocl_zero_buffer(ccl_global float4 *buffer, uint64_t size, uint64_t offset) { size_t i = ccl_global_id(0) + ccl_global_id(1) * ccl_global_size(0); diff --git a/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl b/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl index 8b85d362f8a..95b35e40a45 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl @@ -25,11 +25,7 @@ __kernel void kernel_ocl_path_trace_data_init( int num_elements, ccl_global char *ray_state, ccl_global uint *rng_state, - -#define KERNEL_TEX(type, ttype, name) \ - ccl_global type *name, -#include "kernel/kernel_textures.h" - + KERNEL_BUFFER_PARAMS, int start_sample, int end_sample, int sx, int sy, int sw, int sh, int offset, int stride, @@ -46,10 +42,7 @@ __kernel void kernel_ocl_path_trace_data_init( num_elements, ray_state, rng_state, - -#define KERNEL_TEX(type, ttype, name) name, -#include "kernel/kernel_textures.h" - + KERNEL_BUFFER_ARGS, start_sample, end_sample, sx, sy, sw, sh, offset, stride, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_split.cl b/intern/cycles/kernel/kernels/opencl/kernel_split.cl index 651addb02f4..4cbda1bc2e7 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_split.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_split.cl @@ -14,6 +14,9 @@ * limitations under the License. */ +#include "kernel/kernel_compat_opencl.h" // PRECOMPILED +#include "kernel/split/kernel_split_common.h" // PRECOMPILED + #include "kernel/kernels/opencl/kernel_state_buffer_size.cl" #include "kernel/kernels/opencl/kernel_data_init.cl" #include "kernel/kernels/opencl/kernel_path_init.cl" diff --git a/intern/cycles/kernel/kernels/opencl/kernel_split_function.h b/intern/cycles/kernel/kernels/opencl/kernel_split_function.h index f1e914a70d4..591c3846ef2 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_split_function.h +++ b/intern/cycles/kernel/kernels/opencl/kernel_split_function.h @@ -25,9 +25,7 @@ __kernel void KERNEL_NAME_EVAL(kernel_ocl_path_trace, KERNEL_NAME)( ccl_global char *ray_state, ccl_global uint *rng_state, -#define KERNEL_TEX(type, ttype, name) \ - ccl_global type *name, -#include "kernel/kernel_textures.h" + KERNEL_BUFFER_PARAMS, ccl_global int *queue_index, ccl_global char *use_queues_flag, @@ -52,12 +50,9 @@ __kernel void KERNEL_NAME_EVAL(kernel_ocl_path_trace, KERNEL_NAME)( split_data_init(kg, &kernel_split_state, ccl_global_size(0)*ccl_global_size(1), split_data_buffer, ray_state); -#define KERNEL_TEX(type, ttype, name) \ - kg->name = name; -#include "kernel/kernel_textures.h" } - ccl_barrier(CCL_LOCAL_MEM_FENCE); + kernel_set_buffer_pointers(kg, KERNEL_BUFFER_ARGS); KERNEL_NAME_EVAL(kernel, KERNEL_NAME)( kg diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h index 02c083a83f8..9585d9f4825 100644 --- a/intern/cycles/kernel/osl/osl_globals.h +++ b/intern/cycles/kernel/osl/osl_globals.h @@ -86,7 +86,7 @@ struct OSLThreadData { OSL::ShaderGlobals globals; OSL::PerThreadInfo *osl_thread_info; OSLTraceData tracedata; - OSL::ShadingContext *context[SHADER_CONTEXT_NUM]; + OSL::ShadingContext *context; OIIO::TextureSystem::Perthread *oiio_thread_info; }; diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 1535496c73d..8ad2e12b067 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -1197,8 +1197,9 @@ bool OSLRenderServices::trace(TraceOpt &options, OSL::ShaderGlobals *sg, tracedata->init = true; tracedata->sd.osl_globals = sd->osl_globals; - /* raytrace */ - return scene_intersect(sd->osl_globals, ray, PATH_RAY_ALL_VISIBILITY, &tracedata->isect, NULL, 0.0f, 0.0f); + /* Raytrace, leaving out shadow opaque to avoid early exit. */ + uint visibility = PATH_RAY_ALL_VISIBILITY - PATH_RAY_SHADOW_OPAQUE; + return scene_intersect(sd->osl_globals, ray, visibility, &tracedata->isect, NULL, 0.0f, 0.0f); } diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index 13b19d86eca..9a37e0987aa 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -57,9 +57,7 @@ void OSLShader::thread_init(KernelGlobals *kg, KernelGlobals *kernel_globals, OS tdata->globals.tracedata = &tdata->tracedata; tdata->globals.flipHandedness = false; tdata->osl_thread_info = ss->create_thread_info(); - - for(int i = 0; i < SHADER_CONTEXT_NUM; i++) - tdata->context[i] = ss->get_context(tdata->osl_thread_info); + tdata->context = ss->get_context(tdata->osl_thread_info); tdata->oiio_thread_info = osl_globals->ts->get_perthread_info(); @@ -74,9 +72,7 @@ void OSLShader::thread_free(KernelGlobals *kg) OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss; OSLThreadData *tdata = kg->osl_tdata; - - for(int i = 0; i < SHADER_CONTEXT_NUM; i++) - ss->release_context(tdata->context[i]); + ss->release_context(tdata->context); ss->destroy_thread_info(tdata->osl_thread_info); @@ -173,7 +169,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, } } -void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx) +void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag) { /* setup shader globals from shader data */ OSLThreadData *tdata = kg->osl_tdata; @@ -182,7 +178,7 @@ void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state /* execute shader for this point */ OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss; OSL::ShaderGlobals *globals = &tdata->globals; - OSL::ShadingContext *octx = tdata->context[(int)ctx]; + OSL::ShadingContext *octx = tdata->context; int shader = sd->shader & SHADER_MASK; /* automatic bump shader */ @@ -274,7 +270,7 @@ static void flatten_background_closure_tree(ShaderData *sd, } } -void OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx) +void OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag) { /* setup shader globals from shader data */ OSLThreadData *tdata = kg->osl_tdata; @@ -283,7 +279,7 @@ void OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, PathState *st /* execute shader for this point */ OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss; OSL::ShaderGlobals *globals = &tdata->globals; - OSL::ShadingContext *octx = tdata->context[(int)ctx]; + OSL::ShadingContext *octx = tdata->context; if(kg->osl->background_state) { ss->execute(octx, *(kg->osl->background_state), *globals); @@ -329,7 +325,7 @@ static void flatten_volume_closure_tree(ShaderData *sd, } } -void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx) +void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag) { /* setup shader globals from shader data */ OSLThreadData *tdata = kg->osl_tdata; @@ -338,7 +334,7 @@ void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, PathState *state, /* execute shader */ OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss; OSL::ShaderGlobals *globals = &tdata->globals; - OSL::ShadingContext *octx = tdata->context[(int)ctx]; + OSL::ShadingContext *octx = tdata->context; int shader = sd->shader & SHADER_MASK; if(kg->osl->volume_state[shader]) { @@ -352,7 +348,7 @@ void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, PathState *state, /* Displacement */ -void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx) +void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd) { /* setup shader globals from shader data */ OSLThreadData *tdata = kg->osl_tdata; @@ -364,7 +360,7 @@ void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderConte /* execute shader */ OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss; OSL::ShaderGlobals *globals = &tdata->globals; - OSL::ShadingContext *octx = tdata->context[(int)ctx]; + OSL::ShadingContext *octx = tdata->context; int shader = sd->shader & SHADER_MASK; if(kg->osl->displacement_state[shader]) { diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h index 32121e940b4..f7020d1223d 100644 --- a/intern/cycles/kernel/osl/osl_shader.h +++ b/intern/cycles/kernel/osl/osl_shader.h @@ -53,10 +53,10 @@ public: static void thread_free(KernelGlobals *kg); /* eval */ - static void eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx); - static void eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx); - static void eval_volume(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx); - static void eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx); + static void eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag); + static void eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag); + static void eval_volume(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag); + static void eval_displacement(KernelGlobals *kg, ShaderData *sd); /* attributes */ static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeDescriptor *desc); diff --git a/intern/cycles/kernel/shaders/node_principled_bsdf.osl b/intern/cycles/kernel/shaders/node_principled_bsdf.osl index 2bb981c3918..6870d479af3 100644 --- a/intern/cycles/kernel/shaders/node_principled_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_principled_bsdf.osl @@ -76,8 +76,8 @@ shader node_principled_bsdf( float aspect = sqrt(1.0 - Anisotropic * 0.9); float r2 = Roughness * Roughness; - float alpha_x = max(0.001, r2 / aspect); - float alpha_y = max(0.001, r2 * aspect); + float alpha_x = r2 / aspect; + float alpha_y = r2 * aspect; color tmp_col = color(1.0, 1.0, 1.0) * (1.0 - SpecularTint) + m_ctint * SpecularTint; diff --git a/intern/cycles/kernel/split/kernel_branched.h b/intern/cycles/kernel/split/kernel_branched.h index e2762a85fc8..2313feac089 100644 --- a/intern/cycles/kernel/split/kernel_branched.h +++ b/intern/cycles/kernel/split/kernel_branched.h @@ -87,7 +87,6 @@ ccl_device_inline bool kernel_split_branched_indirect_start_shared(KernelGlobals PathRadiance *inactive_L = &kernel_split_state.path_radiance[inactive_ray]; path_radiance_init(inactive_L, kernel_data.film.use_light_pass); - inactive_L->direct_throughput = L->direct_throughput; path_radiance_copy_indirect(inactive_L, L); ray_state[inactive_ray] = RAY_REGENERATED; @@ -110,7 +109,6 @@ ccl_device_noinline bool kernel_split_branched_path_surface_indirect_light_iter( SplitBranchedState *branched_state = &kernel_split_state.branched_state[ray_index]; ShaderData *sd = saved_sd; - RNG rng = kernel_split_state.rng[ray_index]; PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; float3 throughput = branched_state->throughput; ccl_global PathState *ps = &kernel_split_state.path_state[ray_index]; @@ -157,37 +155,38 @@ ccl_device_noinline bool kernel_split_branched_path_surface_indirect_light_iter( num_samples = ceil_to_int(num_samples_adjust*num_samples); float num_samples_inv = num_samples_adjust/num_samples; - RNG bsdf_rng = cmj_hash(rng, i); for(int j = branched_state->next_sample; j < num_samples; j++) { if(reset_path_state) { *ps = branched_state->path_state; } + ps->rng_hash = cmj_hash(branched_state->path_state.rng_hash, i); + ccl_global float3 *tp = &kernel_split_state.throughput[ray_index]; *tp = throughput; ccl_global Ray *bsdf_ray = &kernel_split_state.ray[ray_index]; if(!kernel_branched_path_surface_bounce(kg, - &bsdf_rng, sd, sc, j, num_samples, tp, ps, - L, + &L->state, bsdf_ray, sum_sample_weight)) { continue; } + ps->rng_hash = branched_state->path_state.rng_hash; + /* update state for next iteration */ branched_state->next_closure = i; branched_state->next_sample = j+1; - branched_state->num_samples = num_samples; /* start the indirect path */ *tp *= num_samples_inv; diff --git a/intern/cycles/kernel/split/kernel_buffer_update.h b/intern/cycles/kernel/split/kernel_buffer_update.h index 4c1fdd2d69c..c9e7deddafa 100644 --- a/intern/cycles/kernel/split/kernel_buffer_update.h +++ b/intern/cycles/kernel/split/kernel_buffer_update.h @@ -75,92 +75,59 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, if(ray_index != QUEUE_EMPTY_SLOT) { #endif - ccl_global uint *rng_state = kernel_split_params.rng_state; int stride = kernel_split_params.stride; ccl_global char *ray_state = kernel_split_state.ray_state; -#ifdef __KERNEL_DEBUG__ - DebugData *debug_data = &kernel_split_state.debug_data[ray_index]; -#endif ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index]; - ccl_global float *L_transparent = &kernel_split_state.L_transparent[ray_index]; - RNG rng = kernel_split_state.rng[ray_index]; - ccl_global float *buffer = kernel_split_params.buffer; - - unsigned int work_index; - ccl_global uint *initial_rng; - - unsigned int sample; - unsigned int tile_x; - unsigned int tile_y; - unsigned int pixel_x; - unsigned int pixel_y; - - work_index = kernel_split_state.work_array[ray_index]; - sample = get_work_sample(kg, work_index, ray_index) + kernel_split_params.start_sample; - get_work_pixel_tile_position(kg, &pixel_x, &pixel_y, - &tile_x, &tile_y, - work_index, - ray_index); - initial_rng = rng_state; - - rng_state += kernel_split_params.offset + pixel_x + pixel_y*stride; - buffer += (kernel_split_params.offset + pixel_x + pixel_y*stride) * kernel_data.film.pass_stride; if(IS_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER)) { -#ifdef __KERNEL_DEBUG__ - kernel_write_debug_passes(kg, buffer, state, debug_data, sample); -#endif + uint sample = state->sample; + uint buffer_offset = kernel_split_state.buffer_offset[ray_index]; + ccl_global float *buffer = kernel_split_params.buffer + buffer_offset; /* accumulate result in output buffer */ - bool is_shadow_catcher = (state->flag & PATH_RAY_SHADOW_CATCHER); - kernel_write_result(kg, buffer, sample, L, 1.0f - (*L_transparent), is_shadow_catcher); - - path_rng_end(kg, rng_state, rng); + kernel_write_result(kg, buffer, sample, L); ASSIGN_RAY_STATE(ray_state, ray_index, RAY_TO_REGENERATE); } if(IS_STATE(ray_state, ray_index, RAY_TO_REGENERATE)) { /* We have completed current work; So get next work */ - int valid_work = get_next_work(kg, &work_index, ray_index); - if(!valid_work) { + uint work_index; + if(!get_next_work(kg, ray_index, &work_index)) { /* If work is invalid, this means no more work is available and the thread may exit */ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_INACTIVE); } if(IS_STATE(ray_state, ray_index, RAY_TO_REGENERATE)) { - kernel_split_state.work_array[ray_index] = work_index; - /* Get the sample associated with the current work */ - sample = get_work_sample(kg, work_index, ray_index) + kernel_split_params.start_sample; - /* Get pixel and tile position associated with current work */ - get_work_pixel_tile_position(kg, &pixel_x, &pixel_y, &tile_x, &tile_y, work_index, ray_index); + uint x, y, sample; + get_work_pixel(kg, work_index, &x, &y, &sample); - /* Remap rng_state according to the current work */ - rng_state = initial_rng + kernel_split_params.offset + pixel_x + pixel_y*stride; - /* Remap buffer according to the current work */ - buffer += (kernel_split_params.offset + pixel_x + pixel_y*stride) * kernel_data.film.pass_stride; + /* Remap rng_state to current pixel. */ + ccl_global uint *rng_state = kernel_split_params.rng_state; + rng_state += kernel_split_params.offset + x + y*stride; + + /* Store buffer offset for writing to passes. */ + uint buffer_offset = (kernel_split_params.offset + x + y*stride) * kernel_data.film.pass_stride; + kernel_split_state.buffer_offset[ray_index] = buffer_offset; /* Initialize random numbers and ray. */ - kernel_path_trace_setup(kg, rng_state, sample, pixel_x, pixel_y, &rng, ray); + uint rng_hash; + kernel_path_trace_setup(kg, rng_state, sample, x, y, &rng_hash, ray); if(ray->t != 0.0f) { - /* Initialize throughput, L_transparent, Ray, PathState; + /* Initialize throughput, path radiance, Ray, PathState; * These rays proceed with path-iteration. */ *throughput = make_float3(1.0f, 1.0f, 1.0f); - *L_transparent = 0.0f; path_radiance_init(L, kernel_data.film.use_light_pass); - path_state_init(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, &rng, sample, ray); + path_state_init(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, rng_hash, sample, ray); #ifdef __SUBSURFACE__ kernel_path_subsurface_init_indirect(&kernel_split_state.ss_rays[ray_index]); #endif -#ifdef __KERNEL_DEBUG__ - debug_data_init(debug_data); -#endif ASSIGN_RAY_STATE(ray_state, ray_index, RAY_REGENERATED); enqueue_flag = 1; } @@ -168,14 +135,13 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, /* These rays do not participate in path-iteration. */ float4 L_rad = make_float4(0.0f, 0.0f, 0.0f, 0.0f); /* Accumulate result in output buffer. */ + ccl_global float *buffer = kernel_split_params.buffer + buffer_offset; kernel_write_pass_float4(buffer, sample, L_rad); - path_rng_end(kg, rng_state, rng); ASSIGN_RAY_STATE(ray_state, ray_index, RAY_TO_REGENERATE); } } } - kernel_split_state.rng[ray_index] = rng; #ifndef __COMPUTE_DEVICE_GPU__ } diff --git a/intern/cycles/kernel/split/kernel_data_init.h b/intern/cycles/kernel/split/kernel_data_init.h index e4545d66eff..2c042dfde6f 100644 --- a/intern/cycles/kernel/split/kernel_data_init.h +++ b/intern/cycles/kernel/split/kernel_data_init.h @@ -52,9 +52,7 @@ void KERNEL_FUNCTION_FULL_NAME(data_init)( ccl_global uint *rng_state, #ifdef __KERNEL_OPENCL__ -#define KERNEL_TEX(type, ttype, name) \ - ccl_global type *name, -#include "kernel/kernel_textures.h" + KERNEL_BUFFER_PARAMS, #endif int start_sample, @@ -100,9 +98,8 @@ void KERNEL_FUNCTION_FULL_NAME(data_init)( split_data_init(kg, &kernel_split_state, num_elements, split_data_buffer, ray_state); #ifdef __KERNEL_OPENCL__ -#define KERNEL_TEX(type, ttype, name) \ - kg->name = name; -#include "kernel/kernel_textures.h" + kernel_set_buffer_pointers(kg, KERNEL_BUFFER_ARGS); + kernel_set_buffer_info(kg); #endif int thread_index = ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0); @@ -127,14 +124,25 @@ void KERNEL_FUNCTION_FULL_NAME(data_init)( /* zero the tiles pixels and initialize rng_state if this is the first sample */ if(start_sample == 0) { - parallel_for(kg, i, sw * sh * kernel_data.film.pass_stride) { - int pixel = i / kernel_data.film.pass_stride; - int pass = i % kernel_data.film.pass_stride; + int pass_stride = kernel_data.film.pass_stride; + +#ifdef __KERNEL_CPU__ + for(int y = sy; y < sy + sh; y++) { + int index = offset + y * stride; + memset(buffer + (sx + index) * pass_stride, 0, sizeof(float) * pass_stride * sw); + for(int x = sx; x < sx + sw; x++) { + rng_state[index + x] = hash_int_2d(x, y); + } + } +#else + parallel_for(kg, i, sw * sh * pass_stride) { + int pixel = i / pass_stride; + int pass = i % pass_stride; int x = sx + pixel % sw; int y = sy + pixel / sw; - int index = (offset + x + y*stride) * kernel_data.film.pass_stride + pass; + int index = (offset + x + y*stride) * pass_stride + pass; *(buffer + index) = 0.0f; } @@ -146,6 +154,7 @@ void KERNEL_FUNCTION_FULL_NAME(data_init)( int index = (offset + x + y*stride); *(rng_state + index) = hash_int_2d(x, y); } +#endif } #endif /* KERENL_STUB */ diff --git a/intern/cycles/kernel/split/kernel_direct_lighting.h b/intern/cycles/kernel/split/kernel_direct_lighting.h index 3336c968a44..2aac66ecb84 100644 --- a/intern/cycles/kernel/split/kernel_direct_lighting.h +++ b/intern/cycles/kernel/split/kernel_direct_lighting.h @@ -62,8 +62,6 @@ ccl_device void kernel_direct_lighting(KernelGlobals *kg, /* direct lighting */ #ifdef __EMISSION__ - RNG rng = kernel_split_state.rng[ray_index]; - bool flag = (kernel_data.integrator.use_direct_light && (sd->flag & SD_BSDF_HAS_EVAL)); @@ -83,23 +81,20 @@ ccl_device void kernel_direct_lighting(KernelGlobals *kg, if(flag) { /* Sample illumination from lights to find path contribution. */ - float light_t = path_state_rng_1D(kg, &rng, state, PRNG_LIGHT); float light_u, light_v; - path_state_rng_2D(kg, &rng, state, PRNG_LIGHT_U, &light_u, &light_v); - float terminate = path_state_rng_light_termination(kg, &rng, state); + path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v); + float terminate = path_state_rng_light_termination(kg, state); LightSample ls; if(light_sample(kg, - light_t, light_u, light_v, + light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { Ray light_ray; -# ifdef __OBJECT_MOTION__ light_ray.time = sd->time; -# endif BsdfEval L_light; bool is_lamp; @@ -115,7 +110,6 @@ ccl_device void kernel_direct_lighting(KernelGlobals *kg, } } } - kernel_split_state.rng[ray_index] = rng; #endif /* __EMISSION__ */ } diff --git a/intern/cycles/kernel/split/kernel_do_volume.h b/intern/cycles/kernel/split/kernel_do_volume.h index 9f8dd2392d9..491487f1230 100644 --- a/intern/cycles/kernel/split/kernel_do_volume.h +++ b/intern/cycles/kernel/split/kernel_do_volume.h @@ -30,7 +30,6 @@ ccl_device_noinline bool kernel_split_branched_path_volume_indirect_light_iter(K SplitBranchedState *branched_state = &kernel_split_state.branched_state[ray_index]; ShaderData *sd = &kernel_split_state.sd[ray_index]; - RNG rng = kernel_split_state.rng[ray_index]; PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index]; @@ -58,22 +57,21 @@ ccl_device_noinline bool kernel_split_branched_path_volume_indirect_light_iter(K /* integrate along volume segment with distance sampling */ VolumeIntegrateResult result = kernel_volume_integrate( - kg, ps, sd, &volume_ray, L, tp, &rng, heterogeneous); + kg, ps, sd, &volume_ray, L, tp, heterogeneous); # ifdef __VOLUME_SCATTER__ if(result == VOLUME_PATH_SCATTERED) { /* direct lighting */ - kernel_path_volume_connect_light(kg, &rng, sd, emission_sd, *tp, &branched_state->path_state, L); + kernel_path_volume_connect_light(kg, sd, emission_sd, *tp, &branched_state->path_state, L); /* indirect light bounce */ - if(!kernel_path_volume_bounce(kg, &rng, sd, tp, ps, L, pray)) { + if(!kernel_path_volume_bounce(kg, sd, tp, ps, &L->state, pray)) { continue; } /* start the indirect path */ branched_state->next_closure = 0; branched_state->next_sample = j+1; - branched_state->num_samples = num_samples; /* Attempting to share too many samples is slow for volumes as it causes us to * loop here more and have many calls to kernel_volume_integrate which evaluates @@ -141,7 +139,6 @@ ccl_device void kernel_do_volume(KernelGlobals *kg) IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND)) { ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index]; ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; - RNG rng = kernel_split_state.rng[ray_index]; ccl_global Intersection *isect = &kernel_split_state.isect[ray_index]; ShaderData *sd = &kernel_split_state.sd[ray_index]; ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index]; @@ -165,15 +162,15 @@ ccl_device void kernel_do_volume(KernelGlobals *kg) { /* integrate along volume segment with distance sampling */ VolumeIntegrateResult result = kernel_volume_integrate( - kg, state, sd, &volume_ray, L, throughput, &rng, heterogeneous); + kg, state, sd, &volume_ray, L, throughput, heterogeneous); # ifdef __VOLUME_SCATTER__ if(result == VOLUME_PATH_SCATTERED) { /* direct lighting */ - kernel_path_volume_connect_light(kg, &rng, sd, emission_sd, *throughput, state, L); + kernel_path_volume_connect_light(kg, sd, emission_sd, *throughput, state, L); /* indirect light bounce */ - if(kernel_path_volume_bounce(kg, &rng, sd, throughput, state, L, ray)) { + if(kernel_path_volume_bounce(kg, sd, throughput, state, &L->state, ray)) { ASSIGN_RAY_STATE(ray_state, ray_index, RAY_REGENERATED); } else { @@ -194,8 +191,6 @@ ccl_device void kernel_do_volume(KernelGlobals *kg) } # endif /* __BRANCHED_PATH__ */ } - - kernel_split_state.rng[ray_index] = rng; } # ifdef __BRANCHED_PATH__ diff --git a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h index 670a557f084..dffd291012d 100644 --- a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h +++ b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h @@ -90,163 +90,58 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( if(ray_index != QUEUE_EMPTY_SLOT) { #endif - int stride = kernel_split_params.stride; - - unsigned int work_index; - unsigned int pixel_x; - unsigned int pixel_y; - - unsigned int tile_x; - unsigned int tile_y; - unsigned int sample; - - RNG rng = kernel_split_state.rng[ray_index]; ccl_global PathState *state = 0x0; float3 throughput; ccl_global char *ray_state = kernel_split_state.ray_state; ShaderData *sd = &kernel_split_state.sd[ray_index]; - ccl_global float *buffer = kernel_split_params.buffer; if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) { + uint buffer_offset = kernel_split_state.buffer_offset[ray_index]; + ccl_global float *buffer = kernel_split_params.buffer + buffer_offset; + + ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; + ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index]; + PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; throughput = kernel_split_state.throughput[ray_index]; state = &kernel_split_state.path_state[ray_index]; - work_index = kernel_split_state.work_array[ray_index]; - sample = get_work_sample(kg, work_index, ray_index) + kernel_split_params.start_sample; - get_work_pixel_tile_position(kg, &pixel_x, &pixel_y, - &tile_x, &tile_y, - work_index, - ray_index); - - buffer += (kernel_split_params.offset + pixel_x + pixel_y * stride) * kernel_data.film.pass_stride; - -#ifdef __SHADOW_TRICKS__ - if((sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) { - if(state->flag & PATH_RAY_CAMERA) { - state->flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_SHADOW_CATCHER_ONLY | PATH_RAY_STORE_SHADOW_INFO); - state->catcher_object = sd->object; - if(!kernel_data.background.transparent) { - PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; - ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; - L->shadow_color = indirect_background(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, ray); - } - } - } - else { - state->flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; - } -#endif /* __SHADOW_TRICKS__ */ - - /* holdout */ -#ifdef __HOLDOUT__ - if(((sd->flag & SD_HOLDOUT) || - (sd->object_flag & SD_OBJECT_HOLDOUT_MASK)) && - (state->flag & PATH_RAY_CAMERA)) + if(!kernel_path_shader_apply(kg, + sd, + state, + ray, + throughput, + emission_sd, + L, + buffer)) { - if(kernel_data.background.transparent) { - float3 holdout_weight; - if(sd->object_flag & SD_OBJECT_HOLDOUT_MASK) { - holdout_weight = make_float3(1.0f, 1.0f, 1.0f); - } - else { - holdout_weight = shader_holdout_eval(kg, sd); - } - /* any throughput is ok, should all be identical here */ - kernel_split_state.L_transparent[ray_index] += average(holdout_weight*throughput); - } - if(sd->object_flag & SD_OBJECT_HOLDOUT_MASK) { - kernel_split_path_end(kg, ray_index); - } + kernel_split_path_end(kg, ray_index); } -#endif /* __HOLDOUT__ */ } if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) { - PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; - -#ifdef __BRANCHED_PATH__ - if(!IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)) -#endif /* __BRANCHED_PATH__ */ - { - /* Holdout mask objects do not write data passes. */ - kernel_write_data_passes(kg, - buffer, - L, - sd, - sample, - state, - throughput); - } - - /* Blurring of bsdf after bounces, for rays that have a small likelihood - * of following this particular path (diffuse, rough glossy. - */ -#ifndef __BRANCHED_PATH__ - if(kernel_data.integrator.filter_glossy != FLT_MAX) -#else - if(kernel_data.integrator.filter_glossy != FLT_MAX && - (!kernel_data.integrator.branched || IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT))) -#endif /* __BRANCHED_PATH__ */ - { - float blur_pdf = kernel_data.integrator.filter_glossy*state->min_ray_pdf; - if(blur_pdf < 1.0f) { - float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f; - shader_bsdf_blur(kg, sd, blur_roughness); - } - } - -#ifdef __EMISSION__ - /* emission */ - if(sd->flag & SD_EMISSION) { - /* TODO(sergey): is isect.t wrong here for transparent surfaces? */ - float3 emission = indirect_primitive_emission( - kg, - sd, - kernel_split_state.isect[ray_index].t, - state->flag, - state->ray_pdf); - path_radiance_accum_emission(L, throughput, emission, state->bounce); - } -#endif /* __EMISSION__ */ - /* Path termination. this is a strange place to put the termination, it's * mainly due to the mixed in MIS that we use. gives too many unneeded * shader evaluations, only need emission if we are going to terminate. */ -#ifndef __BRANCHED_PATH__ - float probability = path_state_terminate_probability(kg, state, throughput); -#else - float probability = 1.0f; - - if(!kernel_data.integrator.branched) { - probability = path_state_terminate_probability(kg, state, throughput); - } - else if(IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)) { - int num_samples = kernel_split_state.branched_state[ray_index].num_samples; - probability = path_state_terminate_probability(kg, state, throughput*num_samples); - } - else if(state->flag & PATH_RAY_TRANSPARENT) { - probability = path_state_terminate_probability(kg, state, throughput); - } -#endif + float probability = path_state_continuation_probability(kg, state, throughput); if(probability == 0.0f) { kernel_split_path_end(kg, ray_index); } - - if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) { - if(probability != 1.0f) { - float terminate = path_state_rng_1D_for_decision(kg, &rng, state, PRNG_TERMINATE); - if(terminate >= probability) { - kernel_split_path_end(kg, ray_index); - } - else { - kernel_split_state.throughput[ray_index] = throughput/probability; - } + else if(probability < 1.0f) { + float terminate = path_state_rng_1D(kg, state, PRNG_TERMINATE); + if(terminate >= probability) { + kernel_split_path_end(kg, ray_index); } + else { + kernel_split_state.throughput[ray_index] = throughput/probability; + } + } + if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) { + PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; kernel_update_denoising_features(kg, sd, state, L); } } @@ -260,8 +155,6 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( } #endif /* __AO__ */ - kernel_split_state.rng[ray_index] = rng; - #ifndef __COMPUTE_DEVICE_GPU__ } #endif diff --git a/intern/cycles/kernel/split/kernel_indirect_background.h b/intern/cycles/kernel/split/kernel_indirect_background.h index f0ebb90f60a..437043a5971 100644 --- a/intern/cycles/kernel/split/kernel_indirect_background.h +++ b/intern/cycles/kernel/split/kernel_indirect_background.h @@ -33,7 +33,7 @@ ccl_device void kernel_indirect_background(KernelGlobals *kg) if(ray_index != QUEUE_EMPTY_SLOT) { if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) { ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; - if(state->bounce > kernel_data.integrator.ao_bounces) { + if(path_state_ao_bounce(kg, state)) { kernel_split_path_end(kg, ray_index); } } @@ -50,33 +50,16 @@ ccl_device void kernel_indirect_background(KernelGlobals *kg) return; } - ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; - PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; - ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; - ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index]; - ccl_global float *L_transparent = &kernel_split_state.L_transparent[ray_index]; - if(IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND)) { - /* eval background shader if nothing hit */ - if(kernel_data.background.transparent && (state->flag & PATH_RAY_CAMERA)) { - *L_transparent = (*L_transparent) + average((*throughput)); -#ifdef __PASSES__ - if(!(kernel_data.film.pass_flag & PASS_BACKGROUND)) -#endif - kernel_split_path_end(kg, ray_index); - } + ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; + PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; + ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; + float3 throughput = kernel_split_state.throughput[ray_index]; + ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index]; - if(IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND)) { -#ifdef __BACKGROUND__ - /* sample background shader */ - float3 L_background = indirect_background(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, ray); - path_radiance_accum_background(L, state, (*throughput), L_background); -#endif - kernel_split_path_end(kg, ray_index); - } + kernel_path_background(kg, state, ray, throughput, emission_sd, L); + kernel_split_path_end(kg, ray_index); } - - } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/split/kernel_indirect_subsurface.h b/intern/cycles/kernel/split/kernel_indirect_subsurface.h index 82bc2f01fd7..e9fe5552e8c 100644 --- a/intern/cycles/kernel/split/kernel_indirect_subsurface.h +++ b/intern/cycles/kernel/split/kernel_indirect_subsurface.h @@ -54,7 +54,6 @@ ccl_device void kernel_indirect_subsurface(KernelGlobals *kg) #endif if(IS_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER)) { ccl_addr_space SubsurfaceIndirectRays *ss_indirect = &kernel_split_state.ss_rays[ray_index]; - kernel_path_subsurface_accum_indirect(ss_indirect, L); /* Trace indirect subsurface rays by restarting the loop. this uses less * stack memory than invoking kernel_path_indirect. diff --git a/intern/cycles/kernel/split/kernel_lamp_emission.h b/intern/cycles/kernel/split/kernel_lamp_emission.h index c669d79ddcd..448456d167d 100644 --- a/intern/cycles/kernel/split/kernel_lamp_emission.h +++ b/intern/cycles/kernel/split/kernel_lamp_emission.h @@ -57,27 +57,10 @@ ccl_device void kernel_lamp_emission(KernelGlobals *kg) float3 throughput = kernel_split_state.throughput[ray_index]; Ray ray = kernel_split_state.ray[ray_index]; + ccl_global Intersection *isect = &kernel_split_state.isect[ray_index]; + ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index]; -#ifdef __LAMP_MIS__ - if(kernel_data.integrator.use_lamp_mis && !(state->flag & PATH_RAY_CAMERA)) { - /* ray starting from previous non-transparent bounce */ - Ray light_ray; - - light_ray.P = ray.P - state->ray_t*ray.D; - state->ray_t += kernel_split_state.isect[ray_index].t; - light_ray.D = ray.D; - light_ray.t = state->ray_t; - light_ray.time = ray.time; - light_ray.dD = ray.dD; - light_ray.dP = ray.dP; - /* intersect with lamp */ - float3 emission; - - if(indirect_lamp_emission(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, &light_ray, &emission)) { - path_radiance_accum_emission(L, throughput, emission, state->bounce); - } - } -#endif /* __LAMP_MIS__ */ + kernel_path_lamp_emission(kg, state, &ray, throughput, isect, emission_sd, L); } } diff --git a/intern/cycles/kernel/split/kernel_next_iteration_setup.h b/intern/cycles/kernel/split/kernel_next_iteration_setup.h index 7758e35fd32..c3373174582 100644 --- a/intern/cycles/kernel/split/kernel_next_iteration_setup.h +++ b/intern/cycles/kernel/split/kernel_next_iteration_setup.h @@ -126,7 +126,6 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg, if(active) { ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index]; ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; - RNG rng = kernel_split_state.rng[ray_index]; ShaderData *sd = &kernel_split_state.sd[ray_index]; ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; @@ -135,7 +134,7 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg, if(!kernel_data.integrator.branched || IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)) { #endif /* Compute direct lighting and next bounce. */ - if(!kernel_path_surface_bounce(kg, &rng, sd, throughput, state, L, ray)) { + if(!kernel_path_surface_bounce(kg, sd, throughput, state, &L->state, ray)) { kernel_split_path_end(kg, ray_index); } #ifdef __BRANCHED_PATH__ @@ -157,8 +156,6 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg, } } #endif /* __BRANCHED_PATH__ */ - - kernel_split_state.rng[ray_index] = rng; } /* Enqueue RAY_UPDATE_BUFFER rays. */ diff --git a/intern/cycles/kernel/split/kernel_path_init.h b/intern/cycles/kernel/split/kernel_path_init.h index a7ecde7c80d..0ab2289348b 100644 --- a/intern/cycles/kernel/split/kernel_path_init.h +++ b/intern/cycles/kernel/split/kernel_path_init.h @@ -29,77 +29,59 @@ ccl_device void kernel_path_init(KernelGlobals *kg) { */ kernel_split_state.ray_state[ray_index] = RAY_ACTIVE; - unsigned int my_sample; - unsigned int pixel_x; - unsigned int pixel_y; - unsigned int tile_x; - unsigned int tile_y; - - unsigned int work_index = 0; /* Get work. */ - if(!get_next_work(kg, &work_index, ray_index)) { + uint work_index; + if(!get_next_work(kg, ray_index, &work_index)) { /* No more work, mark ray as inactive */ kernel_split_state.ray_state[ray_index] = RAY_INACTIVE; return; } - /* Get the sample associated with the work. */ - my_sample = get_work_sample(kg, work_index, ray_index) + kernel_split_params.start_sample; - - /* Get pixel and tile position associated with the work. */ - get_work_pixel_tile_position(kg, &pixel_x, &pixel_y, - &tile_x, &tile_y, - work_index, - ray_index); - kernel_split_state.work_array[ray_index] = work_index; + uint x, y, sample; + get_work_pixel(kg, work_index, &x, &y, &sample); + /* Remap rng_state and buffer to current pixel. */ ccl_global uint *rng_state = kernel_split_params.rng_state; - rng_state += kernel_split_params.offset + pixel_x + pixel_y*kernel_split_params.stride; - - ccl_global float *buffer = kernel_split_params.buffer; - buffer += (kernel_split_params.offset + pixel_x + pixel_y * kernel_split_params.stride) * kernel_data.film.pass_stride; + rng_state += kernel_split_params.offset + x + y*kernel_split_params.stride; - RNG rng = kernel_split_state.rng[ray_index]; + /* Store buffer offset for writing to passes. */ + uint buffer_offset = (kernel_split_params.offset + x + y*kernel_split_params.stride) * kernel_data.film.pass_stride; + kernel_split_state.buffer_offset[ray_index] = buffer_offset; /* Initialize random numbers and ray. */ + uint rng_hash; kernel_path_trace_setup(kg, rng_state, - my_sample, - pixel_x, pixel_y, - &rng, + sample, + x, y, + &rng_hash, &kernel_split_state.ray[ray_index]); if(kernel_split_state.ray[ray_index].t != 0.0f) { - /* Initialize throughput, L_transparent, Ray, PathState; + /* Initialize throughput, path radiance, Ray, PathState; * These rays proceed with path-iteration. */ kernel_split_state.throughput[ray_index] = make_float3(1.0f, 1.0f, 1.0f); - kernel_split_state.L_transparent[ray_index] = 0.0f; path_radiance_init(&kernel_split_state.path_radiance[ray_index], kernel_data.film.use_light_pass); path_state_init(kg, &kernel_split_state.sd_DL_shadow[ray_index], &kernel_split_state.path_state[ray_index], - &rng, - my_sample, + rng_hash, + sample, &kernel_split_state.ray[ray_index]); #ifdef __SUBSURFACE__ kernel_path_subsurface_init_indirect(&kernel_split_state.ss_rays[ray_index]); #endif - -#ifdef __KERNEL_DEBUG__ - debug_data_init(&kernel_split_state.debug_data[ray_index]); -#endif } else { /* These rays do not participate in path-iteration. */ float4 L_rad = make_float4(0.0f, 0.0f, 0.0f, 0.0f); /* Accumulate result in output buffer. */ - kernel_write_pass_float4(buffer, my_sample, L_rad); - path_rng_end(kg, rng_state, kernel_split_state.rng[ray_index]); + ccl_global float *buffer = kernel_split_params.buffer + buffer_offset; + kernel_write_pass_float4(buffer, sample, L_rad); ASSIGN_RAY_STATE(kernel_split_state.ray_state, ray_index, RAY_TO_REGENERATE); } - kernel_split_state.rng[ray_index] = rng; } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/split/kernel_scene_intersect.h b/intern/cycles/kernel/split/kernel_scene_intersect.h index 45984ca509b..f5378bc172b 100644 --- a/intern/cycles/kernel/split/kernel_scene_intersect.h +++ b/intern/cycles/kernel/split/kernel_scene_intersect.h @@ -59,52 +59,14 @@ ccl_device void kernel_scene_intersect(KernelGlobals *kg) return; } -#ifdef __KERNEL_DEBUG__ - DebugData *debug_data = &kernel_split_state.debug_data[ray_index]; -#endif - Intersection isect; - PathState state = kernel_split_state.path_state[ray_index]; + ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; Ray ray = kernel_split_state.ray[ray_index]; + PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; - /* intersect scene */ - uint visibility = path_state_ray_visibility(kg, &state); - - if(state.bounce > kernel_data.integrator.ao_bounces) { - visibility = PATH_RAY_SHADOW; - ray.t = kernel_data.background.ao_distance; - } - -#ifdef __HAIR__ - float difl = 0.0f, extmax = 0.0f; - uint lcg_state = 0; - RNG rng = kernel_split_state.rng[ray_index]; - - if(kernel_data.bvh.have_curves) { - if((kernel_data.cam.resolution == 1) && (state.flag & PATH_RAY_CAMERA)) { - float3 pixdiff = ray.dD.dx + ray.dD.dy; - /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/ - difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f; - } - - extmax = kernel_data.curve.maximum_width; - lcg_state = lcg_state_init(&rng, state.rng_offset, state.sample, 0x51633e2d); - } - - bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax); -#else - bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f); -#endif + Intersection isect; + bool hit = kernel_path_scene_intersect(kg, state, &ray, &isect, L); kernel_split_state.isect[ray_index] = isect; -#ifdef __KERNEL_DEBUG__ - if(state.flag & PATH_RAY_CAMERA) { - debug_data->num_bvh_traversed_nodes += isect.num_traversed_nodes; - debug_data->num_bvh_traversed_instances += isect.num_traversed_instances; - debug_data->num_bvh_intersections += isect.num_intersections; - } - debug_data->num_ray_bounces++; -#endif - if(!hit) { /* Change the state of rays that hit the background; * These rays undergo special processing in the diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h index 2801b32f285..7032461b04a 100644 --- a/intern/cycles/kernel/split/kernel_shader_eval.h +++ b/intern/cycles/kernel/split/kernel_shader_eval.h @@ -48,30 +48,18 @@ ccl_device void kernel_shader_eval(KernelGlobals *kg) ccl_global char *ray_state = kernel_split_state.ray_state; if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) { - RNG rng = kernel_split_state.rng[ray_index]; ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; -#ifndef __BRANCHED_PATH__ - float rbsdf = path_state_rng_1D_for_decision(kg, &rng, state, PRNG_BSDF); - shader_eval_surface(kg, &kernel_split_state.sd[ray_index], &rng, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN); -#else - ShaderContext ctx = SHADER_CONTEXT_MAIN; - float rbsdf = 0.0f; - - if(!kernel_data.integrator.branched || IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)) { - rbsdf = path_state_rng_1D_for_decision(kg, &rng, state, PRNG_BSDF); - + shader_eval_surface(kg, &kernel_split_state.sd[ray_index], state, state->flag); +#ifdef __BRANCHED_PATH__ + if(kernel_data.integrator.branched) { + shader_merge_closures(&kernel_split_state.sd[ray_index]); } - - if(IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)) { - ctx = SHADER_CONTEXT_INDIRECT; + else +#endif + { + shader_prepare_closures(&kernel_split_state.sd[ray_index], state); } - - shader_eval_surface(kg, &kernel_split_state.sd[ray_index], &rng, state, rbsdf, state->flag, ctx); - shader_merge_closures(&kernel_split_state.sd[ray_index]); -#endif /* __BRANCHED_PATH__ */ - - kernel_split_state.rng[ray_index] = rng; } } diff --git a/intern/cycles/kernel/split/kernel_shader_sort.h b/intern/cycles/kernel/split/kernel_shader_sort.h index 297decb0bc2..5a55b680695 100644 --- a/intern/cycles/kernel/split/kernel_shader_sort.h +++ b/intern/cycles/kernel/split/kernel_shader_sort.h @@ -39,7 +39,7 @@ ccl_device void kernel_shader_sort(KernelGlobals *kg, ccl_local ushort *local_index = &locals->local_index[0]; /* copy to local memory */ - for (uint i = 0; i < SHADER_SORT_BLOCK_SIZE; i += SHADER_SORT_LOCAL_SIZE) { + for(uint i = 0; i < SHADER_SORT_BLOCK_SIZE; i += SHADER_SORT_LOCAL_SIZE) { uint idx = offset + i + lid; uint add = input + idx; uint value = (~0); @@ -59,9 +59,9 @@ ccl_device void kernel_shader_sort(KernelGlobals *kg, # ifdef __KERNEL_OPENCL__ /* bitonic sort */ - for (uint length = 1; length < SHADER_SORT_BLOCK_SIZE; length <<= 1) { - for (uint inc = length; inc > 0; inc >>= 1) { - for (uint ii = 0; ii < SHADER_SORT_BLOCK_SIZE; ii += SHADER_SORT_LOCAL_SIZE) { + for(uint length = 1; length < SHADER_SORT_BLOCK_SIZE; length <<= 1) { + for(uint inc = length; inc > 0; inc >>= 1) { + for(uint ii = 0; ii < SHADER_SORT_BLOCK_SIZE; ii += SHADER_SORT_LOCAL_SIZE) { uint i = lid + ii; bool direction = ((i & (length << 1)) != 0); uint j = i ^ inc; @@ -81,7 +81,7 @@ ccl_device void kernel_shader_sort(KernelGlobals *kg, # endif /* __KERNEL_OPENCL__ */ /* copy to destination */ - for (uint i = 0; i < SHADER_SORT_BLOCK_SIZE; i += SHADER_SORT_LOCAL_SIZE) { + for(uint i = 0; i < SHADER_SORT_BLOCK_SIZE; i += SHADER_SORT_LOCAL_SIZE) { uint idx = offset + i + lid; uint lidx = local_index[i + lid]; uint outi = output + idx; diff --git a/intern/cycles/kernel/split/kernel_shadow_blocked_ao.h b/intern/cycles/kernel/split/kernel_shadow_blocked_ao.h index 474286285a9..79aa2c9435b 100644 --- a/intern/cycles/kernel/split/kernel_shadow_blocked_ao.h +++ b/intern/cycles/kernel/split/kernel_shadow_blocked_ao.h @@ -37,21 +37,18 @@ ccl_device void kernel_shadow_blocked_ao(KernelGlobals *kg) ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index]; PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; - RNG rng = kernel_split_state.rng[ray_index]; float3 throughput = kernel_split_state.throughput[ray_index]; #ifdef __BRANCHED_PATH__ if(!kernel_data.integrator.branched || IS_FLAG(kernel_split_state.ray_state, ray_index, RAY_BRANCHED_INDIRECT)) { #endif - kernel_path_ao(kg, sd, emission_sd, L, state, &rng, throughput, shader_bsdf_alpha(kg, sd)); + kernel_path_ao(kg, sd, emission_sd, L, state, throughput, shader_bsdf_alpha(kg, sd)); #ifdef __BRANCHED_PATH__ } else { - kernel_branched_path_ao(kg, sd, emission_sd, L, state, &rng, throughput); + kernel_branched_path_ao(kg, sd, emission_sd, L, state, throughput); } #endif - - kernel_split_state.rng[ray_index] = rng; } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/split/kernel_shadow_blocked_dl.h b/intern/cycles/kernel/split/kernel_shadow_blocked_dl.h index 78e61709b01..b52f9a5eb81 100644 --- a/intern/cycles/kernel/split/kernel_shadow_blocked_dl.h +++ b/intern/cycles/kernel/split/kernel_shadow_blocked_dl.h @@ -45,7 +45,6 @@ ccl_device void kernel_shadow_blocked_dl(KernelGlobals *kg) PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; ShaderData *sd = &kernel_split_state.sd[ray_index]; float3 throughput = kernel_split_state.throughput[ray_index]; - RNG rng = kernel_split_state.rng[ray_index]; BsdfEval L_light = kernel_split_state.bsdf_eval[ray_index]; ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index]; @@ -75,7 +74,6 @@ ccl_device void kernel_shadow_blocked_dl(KernelGlobals *kg) if(use_branched) { kernel_branched_path_surface_connect_light(kg, - &rng, sd, emission_sd, state, @@ -91,10 +89,11 @@ ccl_device void kernel_shadow_blocked_dl(KernelGlobals *kg) float3 shadow; if(!shadow_blocked(kg, - emission_sd, - state, - &ray, - &shadow)) + sd, + emission_sd, + state, + &ray, + &shadow)) { /* accumulate */ path_radiance_accum_light(L, state, throughput, &L_light, shadow, 1.0f, is_lamp); @@ -103,8 +102,6 @@ ccl_device void kernel_shadow_blocked_dl(KernelGlobals *kg) path_radiance_accum_total_light(L, state, throughput, &L_light); } } - - kernel_split_state.rng[ray_index] = rng; } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/split/kernel_split_common.h b/intern/cycles/kernel/split/kernel_split_common.h index 08f0124b529..558d327bc76 100644 --- a/intern/cycles/kernel/split/kernel_split_common.h +++ b/intern/cycles/kernel/split/kernel_split_common.h @@ -63,7 +63,7 @@ ccl_device_inline void kernel_split_path_end(KernelGlobals *kg, int ray_index) PathRadiance *orig_ray_L = &kernel_split_state.path_radiance[orig_ray]; path_radiance_sum_indirect(L); - path_radiance_accum_sample(orig_ray_L, L, 1); + path_radiance_accum_sample(orig_ray_L, L); atomic_fetch_and_dec_uint32((ccl_global uint*)&kernel_split_state.branched_state[orig_ray].shared_sample_count); diff --git a/intern/cycles/kernel/split/kernel_split_data_types.h b/intern/cycles/kernel/split/kernel_split_data_types.h index 4bb2f0d3d80..c58c8463f5c 100644 --- a/intern/cycles/kernel/split/kernel_split_data_types.h +++ b/intern/cycles/kernel/split/kernel_split_data_types.h @@ -56,14 +56,6 @@ typedef struct SplitParams { /* SPLIT_DATA_ENTRY(type, name, num) */ -#if defined(WITH_CYCLES_DEBUG) || defined(__KERNEL_DEBUG__) -/* DebugData memory */ -# define SPLIT_DATA_DEBUG_ENTRIES \ - SPLIT_DATA_ENTRY(DebugData, debug_data, 1) -#else -# define SPLIT_DATA_DEBUG_ENTRIES -#endif /* DEBUG */ - #ifdef __BRANCHED_PATH__ typedef ccl_global struct SplitBranchedState { @@ -80,7 +72,6 @@ typedef ccl_global struct SplitBranchedState { /* indirect loop state */ int next_closure; int next_sample; - int num_samples; #ifdef __SUBSURFACE__ int ss_next_closure; @@ -122,9 +113,7 @@ typedef ccl_global struct SplitBranchedState { #endif /* __VOLUME__ */ #define SPLIT_DATA_ENTRIES \ - SPLIT_DATA_ENTRY(ccl_global RNG, rng, 1) \ SPLIT_DATA_ENTRY(ccl_global float3, throughput, 1) \ - SPLIT_DATA_ENTRY(ccl_global float, L_transparent, 1) \ SPLIT_DATA_ENTRY(PathRadiance, path_radiance, 1) \ SPLIT_DATA_ENTRY(ccl_global Ray, ray, 1) \ SPLIT_DATA_ENTRY(ccl_global PathState, path_state, 1) \ @@ -133,19 +122,16 @@ typedef ccl_global struct SplitBranchedState { SPLIT_DATA_ENTRY(ccl_global int, is_lamp, 1) \ SPLIT_DATA_ENTRY(ccl_global Ray, light_ray, 1) \ SPLIT_DATA_ENTRY(ccl_global int, queue_data, (NUM_QUEUES*2)) /* TODO(mai): this is too large? */ \ - SPLIT_DATA_ENTRY(ccl_global uint, work_array, 1) \ + SPLIT_DATA_ENTRY(ccl_global uint, buffer_offset, 1) \ SPLIT_DATA_ENTRY(ShaderData, sd, 1) \ SPLIT_DATA_ENTRY(ShaderData, sd_DL_shadow, 1) \ SPLIT_DATA_SUBSURFACE_ENTRIES \ SPLIT_DATA_VOLUME_ENTRIES \ SPLIT_DATA_BRANCHED_ENTRIES \ - SPLIT_DATA_DEBUG_ENTRIES \ /* entries to be copied to inactive rays when sharing branched samples (TODO: which are actually needed?) */ #define SPLIT_DATA_ENTRIES_BRANCHED_SHARED \ - SPLIT_DATA_ENTRY(ccl_global RNG, rng, 1) \ SPLIT_DATA_ENTRY(ccl_global float3, throughput, 1) \ - SPLIT_DATA_ENTRY(ccl_global float, L_transparent, 1) \ SPLIT_DATA_ENTRY(PathRadiance, path_radiance, 1) \ SPLIT_DATA_ENTRY(ccl_global Ray, ray, 1) \ SPLIT_DATA_ENTRY(ccl_global PathState, path_state, 1) \ @@ -158,7 +144,6 @@ typedef ccl_global struct SplitBranchedState { SPLIT_DATA_SUBSURFACE_ENTRIES \ SPLIT_DATA_VOLUME_ENTRIES \ SPLIT_DATA_BRANCHED_ENTRIES \ - SPLIT_DATA_DEBUG_ENTRIES \ /* struct that holds pointers to data in the shared state buffer */ typedef struct SplitData { diff --git a/intern/cycles/kernel/split/kernel_subsurface_scatter.h b/intern/cycles/kernel/split/kernel_subsurface_scatter.h index d5083b23f80..3b957856aea 100644 --- a/intern/cycles/kernel/split/kernel_subsurface_scatter.h +++ b/intern/cycles/kernel/split/kernel_subsurface_scatter.h @@ -38,7 +38,6 @@ ccl_device_noinline bool kernel_split_branched_path_subsurface_indirect_light_it SplitBranchedState *branched_state = &kernel_split_state.branched_state[ray_index]; ShaderData *sd = &branched_state->sd; - RNG rng = kernel_split_state.rng[ray_index]; PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index]; @@ -52,14 +51,12 @@ ccl_device_noinline bool kernel_split_branched_path_subsurface_indirect_light_it if(branched_state->ss_next_sample == 0 && branched_state->next_hit == 0 && branched_state->next_closure == 0 && branched_state->next_sample == 0) { - branched_state->lcg_state = lcg_state_init(&rng, - branched_state->path_state.rng_offset, - branched_state->path_state.sample, - 0x68bc21eb); + branched_state->lcg_state = lcg_state_init_addrspace(&branched_state->path_state, + 0x68bc21eb); } int num_samples = kernel_data.integrator.subsurface_samples; float num_samples_inv = 1.0f/num_samples; - RNG bssrdf_rng = cmj_hash(rng, i); + uint bssrdf_rng_hash = cmj_hash(branched_state->path_state.rng_hash, i); /* do subsurface scatter step with copy of shader data, this will * replace the BSSRDF with a diffuse BSDF closure */ @@ -67,7 +64,7 @@ ccl_device_noinline bool kernel_split_branched_path_subsurface_indirect_light_it ccl_global SubsurfaceIntersection *ss_isect = &branched_state->ss_isect; float bssrdf_u, bssrdf_v; path_branched_rng_2D(kg, - &bssrdf_rng, + bssrdf_rng_hash, &branched_state->path_state, j, num_samples, @@ -77,7 +74,7 @@ ccl_device_noinline bool kernel_split_branched_path_subsurface_indirect_light_it /* intersection is expensive so avoid doing multiple times for the same input */ if(branched_state->next_hit == 0 && branched_state->next_closure == 0 && branched_state->next_sample == 0) { - RNG lcg_state = branched_state->lcg_state; + uint lcg_state = branched_state->lcg_state; SubsurfaceIntersection ss_isect_private; branched_state->num_hits = subsurface_scatter_multi_intersect(kg, @@ -152,7 +149,6 @@ ccl_device_noinline bool kernel_split_branched_path_subsurface_indirect_light_it int all = (kernel_data.integrator.sample_all_lights_direct) || (branched_state->path_state.flag & PATH_RAY_SHADOW_CATCHER); kernel_branched_path_surface_connect_light(kg, - &rng, bssrdf_sd, emission_sd, hit_state, @@ -229,7 +225,6 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg) if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) { ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; - RNG rng = kernel_split_state.rng[ray_index]; ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index]; ccl_global SubsurfaceIndirectRays *ss_indirect = &kernel_split_state.ss_rays[ray_index]; @@ -246,7 +241,6 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg) emission_sd, L, state, - &rng, ray, throughput, ss_indirect)) @@ -256,21 +250,17 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg) #ifdef __BRANCHED_PATH__ } else if(IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)) { - float bssrdf_probability; - ShaderClosure *sc = subsurface_scatter_pick_closure(kg, sd, &bssrdf_probability); + float bssrdf_u, bssrdf_v; + path_state_rng_2D(kg, + state, + PRNG_BSDF_U, + &bssrdf_u, &bssrdf_v); - /* modify throughput for picking bssrdf or bsdf */ - *throughput *= bssrdf_probability; + const ShaderClosure *sc = shader_bssrdf_pick(sd, throughput, &bssrdf_u); /* do bssrdf scatter step if we picked a bssrdf closure */ if(sc) { - uint lcg_state = lcg_state_init(&rng, state->rng_offset, state->sample, 0x68bc21eb); - float bssrdf_u, bssrdf_v; - path_state_rng_2D(kg, - &rng, - state, - PRNG_BSDF_U, - &bssrdf_u, &bssrdf_v); + uint lcg_state = lcg_state_init_addrspace(state, 0x68bc21eb); subsurface_scatter_step(kg, sd, state, @@ -290,7 +280,6 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg) } #endif } - kernel_split_state.rng[ray_index] = rng; } # ifdef __BRANCHED_PATH__ diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index 7704aa545c8..4268813b263 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -280,8 +280,8 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * float aspect = safe_sqrtf(1.0f - anisotropic * 0.9f); float r2 = roughness * roughness; - bsdf->alpha_x = fmaxf(0.001f, r2 / aspect); - bsdf->alpha_y = fmaxf(0.001f, r2 * aspect); + bsdf->alpha_x = r2 / aspect; + bsdf->alpha_y = r2 * aspect; float m_cdlum = 0.3f * base_color.x + 0.6f * base_color.y + 0.1f * base_color.z; // luminance approx. float3 m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum : make_float3(0.0f, 0.0f, 0.0f); // normalize lum. to isolate hue+sat diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index 8e45dbfa5ff..6d6e92e73f6 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -16,19 +16,6 @@ CCL_NAMESPACE_BEGIN -/* Float4 textures on various devices. */ -#if defined(__KERNEL_CPU__) -# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CPU -#elif defined(__KERNEL_CUDA__) -# if __CUDA_ARCH__ < 300 -# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CUDA -# else -# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CUDA_KEPLER -# endif -#else -# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_OPENCL -#endif - ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb, uint use_alpha) { #ifdef __KERNEL_CPU__ @@ -50,94 +37,94 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, switch(id) { case 0: r = kernel_tex_image_interp(__tex_image_float4_000, x, y); break; - case 1: r = kernel_tex_image_interp(__tex_image_float4_001, x, y); break; - case 2: r = kernel_tex_image_interp(__tex_image_float4_002, x, y); break; - case 3: r = kernel_tex_image_interp(__tex_image_float4_003, x, y); break; - case 4: r = kernel_tex_image_interp(__tex_image_float4_004, x, y); break; - case 5: r = kernel_tex_image_interp(__tex_image_byte4_005, x, y); break; - case 6: r = kernel_tex_image_interp(__tex_image_byte4_006, x, y); break; - case 7: r = kernel_tex_image_interp(__tex_image_byte4_007, x, y); break; - case 8: r = kernel_tex_image_interp(__tex_image_byte4_008, x, y); break; + case 8: r = kernel_tex_image_interp(__tex_image_float4_008, x, y); break; + case 16: r = kernel_tex_image_interp(__tex_image_float4_016, x, y); break; + case 24: r = kernel_tex_image_interp(__tex_image_float4_024, x, y); break; + case 32: r = kernel_tex_image_interp(__tex_image_float4_032, x, y); break; + case 1: r = kernel_tex_image_interp(__tex_image_byte4_001, x, y); break; case 9: r = kernel_tex_image_interp(__tex_image_byte4_009, x, y); break; - case 10: r = kernel_tex_image_interp(__tex_image_byte4_010, x, y); break; - case 11: r = kernel_tex_image_interp(__tex_image_byte4_011, x, y); break; - case 12: r = kernel_tex_image_interp(__tex_image_byte4_012, x, y); break; - case 13: r = kernel_tex_image_interp(__tex_image_byte4_013, x, y); break; - case 14: r = kernel_tex_image_interp(__tex_image_byte4_014, x, y); break; - case 15: r = kernel_tex_image_interp(__tex_image_byte4_015, x, y); break; - case 16: r = kernel_tex_image_interp(__tex_image_byte4_016, x, y); break; case 17: r = kernel_tex_image_interp(__tex_image_byte4_017, x, y); break; - case 18: r = kernel_tex_image_interp(__tex_image_byte4_018, x, y); break; - case 19: r = kernel_tex_image_interp(__tex_image_byte4_019, x, y); break; - case 20: r = kernel_tex_image_interp(__tex_image_byte4_020, x, y); break; - case 21: r = kernel_tex_image_interp(__tex_image_byte4_021, x, y); break; - case 22: r = kernel_tex_image_interp(__tex_image_byte4_022, x, y); break; - case 23: r = kernel_tex_image_interp(__tex_image_byte4_023, x, y); break; - case 24: r = kernel_tex_image_interp(__tex_image_byte4_024, x, y); break; case 25: r = kernel_tex_image_interp(__tex_image_byte4_025, x, y); break; - case 26: r = kernel_tex_image_interp(__tex_image_byte4_026, x, y); break; - case 27: r = kernel_tex_image_interp(__tex_image_byte4_027, x, y); break; - case 28: r = kernel_tex_image_interp(__tex_image_byte4_028, x, y); break; - case 29: r = kernel_tex_image_interp(__tex_image_byte4_029, x, y); break; - case 30: r = kernel_tex_image_interp(__tex_image_byte4_030, x, y); break; - case 31: r = kernel_tex_image_interp(__tex_image_byte4_031, x, y); break; - case 32: r = kernel_tex_image_interp(__tex_image_byte4_032, x, y); break; case 33: r = kernel_tex_image_interp(__tex_image_byte4_033, x, y); break; - case 34: r = kernel_tex_image_interp(__tex_image_byte4_034, x, y); break; - case 35: r = kernel_tex_image_interp(__tex_image_byte4_035, x, y); break; - case 36: r = kernel_tex_image_interp(__tex_image_byte4_036, x, y); break; - case 37: r = kernel_tex_image_interp(__tex_image_byte4_037, x, y); break; - case 38: r = kernel_tex_image_interp(__tex_image_byte4_038, x, y); break; - case 39: r = kernel_tex_image_interp(__tex_image_byte4_039, x, y); break; - case 40: r = kernel_tex_image_interp(__tex_image_byte4_040, x, y); break; case 41: r = kernel_tex_image_interp(__tex_image_byte4_041, x, y); break; - case 42: r = kernel_tex_image_interp(__tex_image_byte4_042, x, y); break; - case 43: r = kernel_tex_image_interp(__tex_image_byte4_043, x, y); break; - case 44: r = kernel_tex_image_interp(__tex_image_byte4_044, x, y); break; - case 45: r = kernel_tex_image_interp(__tex_image_byte4_045, x, y); break; - case 46: r = kernel_tex_image_interp(__tex_image_byte4_046, x, y); break; - case 47: r = kernel_tex_image_interp(__tex_image_byte4_047, x, y); break; - case 48: r = kernel_tex_image_interp(__tex_image_byte4_048, x, y); break; case 49: r = kernel_tex_image_interp(__tex_image_byte4_049, x, y); break; - case 50: r = kernel_tex_image_interp(__tex_image_byte4_050, x, y); break; - case 51: r = kernel_tex_image_interp(__tex_image_byte4_051, x, y); break; - case 52: r = kernel_tex_image_interp(__tex_image_byte4_052, x, y); break; - case 53: r = kernel_tex_image_interp(__tex_image_byte4_053, x, y); break; - case 54: r = kernel_tex_image_interp(__tex_image_byte4_054, x, y); break; - case 55: r = kernel_tex_image_interp(__tex_image_byte4_055, x, y); break; - case 56: r = kernel_tex_image_interp(__tex_image_byte4_056, x, y); break; case 57: r = kernel_tex_image_interp(__tex_image_byte4_057, x, y); break; - case 58: r = kernel_tex_image_interp(__tex_image_byte4_058, x, y); break; - case 59: r = kernel_tex_image_interp(__tex_image_byte4_059, x, y); break; - case 60: r = kernel_tex_image_interp(__tex_image_byte4_060, x, y); break; - case 61: r = kernel_tex_image_interp(__tex_image_byte4_061, x, y); break; - case 62: r = kernel_tex_image_interp(__tex_image_byte4_062, x, y); break; - case 63: r = kernel_tex_image_interp(__tex_image_byte4_063, x, y); break; - case 64: r = kernel_tex_image_interp(__tex_image_byte4_064, x, y); break; case 65: r = kernel_tex_image_interp(__tex_image_byte4_065, x, y); break; - case 66: r = kernel_tex_image_interp(__tex_image_byte4_066, x, y); break; - case 67: r = kernel_tex_image_interp(__tex_image_byte4_067, x, y); break; - case 68: r = kernel_tex_image_interp(__tex_image_byte4_068, x, y); break; - case 69: r = kernel_tex_image_interp(__tex_image_byte4_069, x, y); break; - case 70: r = kernel_tex_image_interp(__tex_image_byte4_070, x, y); break; - case 71: r = kernel_tex_image_interp(__tex_image_byte4_071, x, y); break; - case 72: r = kernel_tex_image_interp(__tex_image_byte4_072, x, y); break; case 73: r = kernel_tex_image_interp(__tex_image_byte4_073, x, y); break; - case 74: r = kernel_tex_image_interp(__tex_image_byte4_074, x, y); break; - case 75: r = kernel_tex_image_interp(__tex_image_byte4_075, x, y); break; - case 76: r = kernel_tex_image_interp(__tex_image_byte4_076, x, y); break; - case 77: r = kernel_tex_image_interp(__tex_image_byte4_077, x, y); break; - case 78: r = kernel_tex_image_interp(__tex_image_byte4_078, x, y); break; - case 79: r = kernel_tex_image_interp(__tex_image_byte4_079, x, y); break; - case 80: r = kernel_tex_image_interp(__tex_image_byte4_080, x, y); break; case 81: r = kernel_tex_image_interp(__tex_image_byte4_081, x, y); break; - case 82: r = kernel_tex_image_interp(__tex_image_byte4_082, x, y); break; - case 83: r = kernel_tex_image_interp(__tex_image_byte4_083, x, y); break; - case 84: r = kernel_tex_image_interp(__tex_image_byte4_084, x, y); break; - case 85: r = kernel_tex_image_interp(__tex_image_byte4_085, x, y); break; - case 86: r = kernel_tex_image_interp(__tex_image_byte4_086, x, y); break; - case 87: r = kernel_tex_image_interp(__tex_image_byte4_087, x, y); break; - case 88: r = kernel_tex_image_interp(__tex_image_byte4_088, x, y); break; + case 89: r = kernel_tex_image_interp(__tex_image_byte4_089, x, y); break; + case 97: r = kernel_tex_image_interp(__tex_image_byte4_097, x, y); break; + case 105: r = kernel_tex_image_interp(__tex_image_byte4_105, x, y); break; + case 113: r = kernel_tex_image_interp(__tex_image_byte4_113, x, y); break; + case 121: r = kernel_tex_image_interp(__tex_image_byte4_121, x, y); break; + case 129: r = kernel_tex_image_interp(__tex_image_byte4_129, x, y); break; + case 137: r = kernel_tex_image_interp(__tex_image_byte4_137, x, y); break; + case 145: r = kernel_tex_image_interp(__tex_image_byte4_145, x, y); break; + case 153: r = kernel_tex_image_interp(__tex_image_byte4_153, x, y); break; + case 161: r = kernel_tex_image_interp(__tex_image_byte4_161, x, y); break; + case 169: r = kernel_tex_image_interp(__tex_image_byte4_169, x, y); break; + case 177: r = kernel_tex_image_interp(__tex_image_byte4_177, x, y); break; + case 185: r = kernel_tex_image_interp(__tex_image_byte4_185, x, y); break; + case 193: r = kernel_tex_image_interp(__tex_image_byte4_193, x, y); break; + case 201: r = kernel_tex_image_interp(__tex_image_byte4_201, x, y); break; + case 209: r = kernel_tex_image_interp(__tex_image_byte4_209, x, y); break; + case 217: r = kernel_tex_image_interp(__tex_image_byte4_217, x, y); break; + case 225: r = kernel_tex_image_interp(__tex_image_byte4_225, x, y); break; + case 233: r = kernel_tex_image_interp(__tex_image_byte4_233, x, y); break; + case 241: r = kernel_tex_image_interp(__tex_image_byte4_241, x, y); break; + case 249: r = kernel_tex_image_interp(__tex_image_byte4_249, x, y); break; + case 257: r = kernel_tex_image_interp(__tex_image_byte4_257, x, y); break; + case 265: r = kernel_tex_image_interp(__tex_image_byte4_265, x, y); break; + case 273: r = kernel_tex_image_interp(__tex_image_byte4_273, x, y); break; + case 281: r = kernel_tex_image_interp(__tex_image_byte4_281, x, y); break; + case 289: r = kernel_tex_image_interp(__tex_image_byte4_289, x, y); break; + case 297: r = kernel_tex_image_interp(__tex_image_byte4_297, x, y); break; + case 305: r = kernel_tex_image_interp(__tex_image_byte4_305, x, y); break; + case 313: r = kernel_tex_image_interp(__tex_image_byte4_313, x, y); break; + case 321: r = kernel_tex_image_interp(__tex_image_byte4_321, x, y); break; + case 329: r = kernel_tex_image_interp(__tex_image_byte4_329, x, y); break; + case 337: r = kernel_tex_image_interp(__tex_image_byte4_337, x, y); break; + case 345: r = kernel_tex_image_interp(__tex_image_byte4_345, x, y); break; + case 353: r = kernel_tex_image_interp(__tex_image_byte4_353, x, y); break; + case 361: r = kernel_tex_image_interp(__tex_image_byte4_361, x, y); break; + case 369: r = kernel_tex_image_interp(__tex_image_byte4_369, x, y); break; + case 377: r = kernel_tex_image_interp(__tex_image_byte4_377, x, y); break; + case 385: r = kernel_tex_image_interp(__tex_image_byte4_385, x, y); break; + case 393: r = kernel_tex_image_interp(__tex_image_byte4_393, x, y); break; + case 401: r = kernel_tex_image_interp(__tex_image_byte4_401, x, y); break; + case 409: r = kernel_tex_image_interp(__tex_image_byte4_409, x, y); break; + case 417: r = kernel_tex_image_interp(__tex_image_byte4_417, x, y); break; + case 425: r = kernel_tex_image_interp(__tex_image_byte4_425, x, y); break; + case 433: r = kernel_tex_image_interp(__tex_image_byte4_433, x, y); break; + case 441: r = kernel_tex_image_interp(__tex_image_byte4_441, x, y); break; + case 449: r = kernel_tex_image_interp(__tex_image_byte4_449, x, y); break; + case 457: r = kernel_tex_image_interp(__tex_image_byte4_457, x, y); break; + case 465: r = kernel_tex_image_interp(__tex_image_byte4_465, x, y); break; + case 473: r = kernel_tex_image_interp(__tex_image_byte4_473, x, y); break; + case 481: r = kernel_tex_image_interp(__tex_image_byte4_481, x, y); break; + case 489: r = kernel_tex_image_interp(__tex_image_byte4_489, x, y); break; + case 497: r = kernel_tex_image_interp(__tex_image_byte4_497, x, y); break; + case 505: r = kernel_tex_image_interp(__tex_image_byte4_505, x, y); break; + case 513: r = kernel_tex_image_interp(__tex_image_byte4_513, x, y); break; + case 521: r = kernel_tex_image_interp(__tex_image_byte4_521, x, y); break; + case 529: r = kernel_tex_image_interp(__tex_image_byte4_529, x, y); break; + case 537: r = kernel_tex_image_interp(__tex_image_byte4_537, x, y); break; + case 545: r = kernel_tex_image_interp(__tex_image_byte4_545, x, y); break; + case 553: r = kernel_tex_image_interp(__tex_image_byte4_553, x, y); break; + case 561: r = kernel_tex_image_interp(__tex_image_byte4_561, x, y); break; + case 569: r = kernel_tex_image_interp(__tex_image_byte4_569, x, y); break; + case 577: r = kernel_tex_image_interp(__tex_image_byte4_577, x, y); break; + case 585: r = kernel_tex_image_interp(__tex_image_byte4_585, x, y); break; + case 593: r = kernel_tex_image_interp(__tex_image_byte4_593, x, y); break; + case 601: r = kernel_tex_image_interp(__tex_image_byte4_601, x, y); break; + case 609: r = kernel_tex_image_interp(__tex_image_byte4_609, x, y); break; + case 617: r = kernel_tex_image_interp(__tex_image_byte4_617, x, y); break; + case 625: r = kernel_tex_image_interp(__tex_image_byte4_625, x, y); break; + case 633: r = kernel_tex_image_interp(__tex_image_byte4_633, x, y); break; + case 641: r = kernel_tex_image_interp(__tex_image_byte4_641, x, y); break; + case 649: r = kernel_tex_image_interp(__tex_image_byte4_649, x, y); break; + case 657: r = kernel_tex_image_interp(__tex_image_byte4_657, x, y); break; + case 665: r = kernel_tex_image_interp(__tex_image_byte4_665, x, y); break; default: kernel_assert(0); return make_float4(0.0f, 0.0f, 0.0f, 0.0f); @@ -224,6 +211,8 @@ ccl_device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float object_inverse_normal_transform(kg, sd, &N); /* project from direction vector to barycentric coordinates in triangles */ + float3 signed_N = N; + N.x = fabsf(N.x); N.y = fabsf(N.y); N.z = fabsf(N.z); @@ -293,12 +282,19 @@ ccl_device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float float4 f = make_float4(0.0f, 0.0f, 0.0f, 0.0f); uint use_alpha = stack_valid(alpha_offset); - if(weight.x > 0.0f) - f += weight.x*svm_image_texture(kg, id, co.y, co.z, srgb, use_alpha); - if(weight.y > 0.0f) - f += weight.y*svm_image_texture(kg, id, co.x, co.z, srgb, use_alpha); - if(weight.z > 0.0f) - f += weight.z*svm_image_texture(kg, id, co.y, co.x, srgb, use_alpha); + /* Map so that no textures are flipped, rotation is somewhat arbitrary. */ + if(weight.x > 0.0f) { + float2 uv = make_float2((signed_N.x < 0.0f)? 1.0f - co.y: co.y, co.z); + f += weight.x*svm_image_texture(kg, id, uv.x, uv.y, srgb, use_alpha); + } + if(weight.y > 0.0f) { + float2 uv = make_float2((signed_N.y > 0.0f)? 1.0f - co.x: co.x, co.z); + f += weight.y*svm_image_texture(kg, id, uv.x, uv.y, srgb, use_alpha); + } + if(weight.z > 0.0f) { + float2 uv = make_float2((signed_N.z > 0.0f)? 1.0f - co.y: co.y, co.x); + f += weight.z*svm_image_texture(kg, id, uv.x, uv.y, srgb, use_alpha); + } if(stack_valid(out_offset)) stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z)); diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index 2d810ff664f..08203163d1a 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -221,28 +221,6 @@ OutputNode *ShaderGraph::output() return (OutputNode*)nodes.front(); } -ShaderGraph *ShaderGraph::copy() -{ - ShaderGraph *newgraph = new ShaderGraph(); - - /* copy nodes */ - ShaderNodeSet nodes_all; - foreach(ShaderNode *node, nodes) - nodes_all.insert(node); - - ShaderNodeMap nodes_copy; - copy_nodes(nodes_all, nodes_copy); - - /* add nodes (in same order, so output is still first) */ - newgraph->clear_nodes(); - foreach(ShaderNode *node, nodes) - newgraph->add(nodes_copy[node]); - - newgraph->simplified = simplified; - - return newgraph; -} - void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to) { assert(!finalized); @@ -1040,6 +1018,9 @@ int ShaderGraph::get_num_closures() else if(CLOSURE_IS_PRINCIPLED(closure_type)) { num_closures += 8; } + else if(CLOSURE_IS_VOLUME(closure_type)) { + num_closures += VOLUME_STACK_SIZE; + } else { ++num_closures; } diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index 72e391991a7..f0fd789c6bd 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -151,6 +151,7 @@ public: virtual bool has_surface_emission() { return false; } virtual bool has_surface_transparent() { return false; } virtual bool has_surface_bssrdf() { return false; } + virtual bool has_bump() { return false; } virtual bool has_bssrdf_bump() { return false; } virtual bool has_spatial_varying() { return false; } virtual bool has_object_dependency() { return false; } @@ -245,8 +246,6 @@ public: ShaderGraph(); ~ShaderGraph(); - ShaderGraph *copy(); - ShaderNode *add(ShaderNode *node); OutputNode *output(); diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index f4482e0bb25..bb94b9bb82a 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -43,7 +43,6 @@ static bool isfinite(half /*value*/) ImageManager::ImageManager(const DeviceInfo& info) { need_update = true; - pack_images = false; osl_texture_system = NULL; animation_frame = 0; @@ -87,11 +86,6 @@ ImageManager::~ImageManager() } } -void ImageManager::set_pack_images(bool pack_images_) -{ - pack_images = pack_images_; -} - void ImageManager::set_osl_texture_system(void *texture_system) { osl_texture_system = texture_system; @@ -115,16 +109,18 @@ bool ImageManager::set_animation_frame_update(int frame) ImageDataType ImageManager::get_image_metadata(const string& filename, void *builtin_data, - bool& is_linear) + bool& is_linear, + bool& builtin_free_cache) { bool is_float = false, is_half = false; is_linear = false; + builtin_free_cache = false; int channels = 4; if(builtin_data) { if(builtin_image_info_cb) { int width, height, depth; - builtin_image_info_cb(filename, builtin_data, is_float, width, height, depth, channels); + builtin_image_info_cb(filename, builtin_data, is_float, width, height, depth, channels, builtin_free_cache); } if(is_float) { @@ -218,37 +214,14 @@ int ImageManager::max_flattened_slot(ImageDataType type) /* The lower three bits of a device texture slot number indicate its type. * These functions convert the slot ids from ImageManager "images" ones * to device ones and vice verse. - * - * There are special cases for CUDA Fermi, since there we have only 90 image texture - * slots available and should keep the flattended numbers in the 0-89 range. */ int ImageManager::type_index_to_flattened_slot(int slot, ImageDataType type) { - if(cuda_fermi_limits) { - if(type == IMAGE_DATA_TYPE_BYTE4) { - return slot + TEX_START_BYTE4_CUDA; - } - else { - return slot; - } - } - return (slot << IMAGE_DATA_TYPE_SHIFT) | (type); } int ImageManager::flattened_slot_to_type_index(int flat_slot, ImageDataType *type) { - if(cuda_fermi_limits) { - if(flat_slot >= 4) { - *type = IMAGE_DATA_TYPE_BYTE4; - return flat_slot - TEX_START_BYTE4_CUDA; - } - else { - *type = IMAGE_DATA_TYPE_FLOAT4; - return flat_slot; - } - } - *type = (ImageDataType)(flat_slot & IMAGE_DATA_TYPE_MASK); return flat_slot >> IMAGE_DATA_TYPE_SHIFT; } @@ -295,8 +268,9 @@ int ImageManager::add_image(const string& filename, { Image *img; size_t slot; + bool builtin_free_cache; - ImageDataType type = get_image_metadata(filename, builtin_data, is_linear); + ImageDataType type = get_image_metadata(filename, builtin_data, is_linear, builtin_free_cache); thread_scoped_lock device_lock(device_mutex); @@ -364,7 +338,7 @@ int ImageManager::add_image(const string& filename, else { /* Very unlikely, since max_num_images is insanely big. But better safe than sorry. */ int tex_count = 0; - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { tex_count += tex_num_images[type]; } if(tex_count > max_num_images) { @@ -382,6 +356,7 @@ int ImageManager::add_image(const string& filename, img = new Image(); img->filename = filename; img->builtin_data = builtin_data; + img->builtin_free_cache = builtin_free_cache; img->need_load = true; img->animated = animated; img->frame = frame; @@ -467,7 +442,12 @@ void ImageManager::tag_reload_image(const string& filename, } } -bool ImageManager::file_load_image_generic(Image *img, ImageInput **in, int &width, int &height, int &depth, int &components) +bool ImageManager::file_load_image_generic(Image *img, + ImageInput **in, + int &width, + int &height, + int &depth, + int &components) { if(img->filename == "") return false; @@ -506,8 +486,8 @@ bool ImageManager::file_load_image_generic(Image *img, ImageInput **in, int &wid if(!builtin_image_info_cb || !builtin_image_pixels_cb) return false; - bool is_float; - builtin_image_info_cb(img->filename, img->builtin_data, is_float, width, height, depth, components); + bool is_float, free_cache; + builtin_image_info_cb(img->filename, img->builtin_data, is_float, width, height, depth, components, free_cache); } /* we only handle certain number of components */ @@ -542,6 +522,10 @@ bool ImageManager::file_load_image(Image *img, vector<StorageType> pixels_storage; StorageType *pixels; const size_t max_size = max(max(width, height), depth); + if(max_size == 0) { + /* Don't bother with invalid images. */ + return false; + } if(texture_limit > 0 && max_size > texture_limit) { pixels_storage.resize(((size_t)width)*height*depth*4); pixels = &pixels_storage[0]; @@ -549,6 +533,10 @@ bool ImageManager::file_load_image(Image *img, else { pixels = (StorageType*)tex_img.resize(width, height, depth); } + if(pixels == NULL) { + /* Could be that we've run out of memory. */ + return false; + } bool cmyk = false; const size_t num_pixels = ((size_t)width) * height * depth; if(in) { @@ -588,13 +576,15 @@ bool ImageManager::file_load_image(Image *img, builtin_image_float_pixels_cb(img->filename, img->builtin_data, (float*)&pixels[0], - num_pixels * components); + num_pixels * components, + img->builtin_free_cache); } else if(FileFormat == TypeDesc::UINT8) { builtin_image_pixels_cb(img->filename, img->builtin_data, (uchar*)&pixels[0], - num_pixels * components); + num_pixels * components, + img->builtin_free_cache); } else { /* TODO(dingto): Support half for ImBuf. */ @@ -754,7 +744,7 @@ void ImageManager::device_load_image(Device *device, pixels[3] = TEX_IMAGE_MISSING_A; } - if(!pack_images) { + { thread_scoped_lock device_lock(device_mutex); device->tex_alloc(name.c_str(), tex_img, @@ -783,7 +773,7 @@ void ImageManager::device_load_image(Device *device, pixels[0] = TEX_IMAGE_MISSING_R; } - if(!pack_images) { + { thread_scoped_lock device_lock(device_mutex); device->tex_alloc(name.c_str(), tex_img, @@ -815,7 +805,7 @@ void ImageManager::device_load_image(Device *device, pixels[3] = (TEX_IMAGE_MISSING_A * 255); } - if(!pack_images) { + { thread_scoped_lock device_lock(device_mutex); device->tex_alloc(name.c_str(), tex_img, @@ -843,7 +833,7 @@ void ImageManager::device_load_image(Device *device, pixels[0] = (TEX_IMAGE_MISSING_R * 255); } - if(!pack_images) { + { thread_scoped_lock device_lock(device_mutex); device->tex_alloc(name.c_str(), tex_img, @@ -874,7 +864,7 @@ void ImageManager::device_load_image(Device *device, pixels[3] = TEX_IMAGE_MISSING_A; } - if(!pack_images) { + { thread_scoped_lock device_lock(device_mutex); device->tex_alloc(name.c_str(), tex_img, @@ -902,7 +892,7 @@ void ImageManager::device_load_image(Device *device, pixels[0] = TEX_IMAGE_MISSING_R; } - if(!pack_images) { + { thread_scoped_lock device_lock(device_mutex); device->tex_alloc(name.c_str(), tex_img, @@ -1059,9 +1049,6 @@ void ImageManager::device_update(Device *device, pool.wait_work(); - if(pack_images) - device_pack_images(device, dscene, progress); - need_update = false; } @@ -1091,141 +1078,6 @@ void ImageManager::device_update_slot(Device *device, } } -uint8_t ImageManager::pack_image_options(ImageDataType type, size_t slot) -{ - uint8_t options = 0; - /* Image Options are packed into one uint: - * bit 0 -> Interpolation - * bit 1 + 2 + 3 -> Extension - */ - if(images[type][slot]->interpolation == INTERPOLATION_CLOSEST) { - options |= (1 << 0); - } - if(images[type][slot]->extension == EXTENSION_REPEAT) { - options |= (1 << 1); - } - else if(images[type][slot]->extension == EXTENSION_EXTEND) { - options |= (1 << 2); - } - else /* EXTENSION_CLIP */ { - options |= (1 << 3); - } - return options; -} - -template<typename T> -void ImageManager::device_pack_images_type( - ImageDataType type, - const vector<device_vector<T>*>& cpu_textures, - device_vector<T> *device_image, - uint4 *info) -{ - size_t size = 0, offset = 0; - /* First step is to calculate size of the texture we need. */ - for(size_t slot = 0; slot < images[type].size(); slot++) { - if(images[type][slot] == NULL) { - continue; - } - device_vector<T>& tex_img = *cpu_textures[slot]; - size += tex_img.size(); - } - /* Now we know how much memory we need, so we can allocate and fill. */ - T *pixels = device_image->resize(size); - for(size_t slot = 0; slot < images[type].size(); slot++) { - if(images[type][slot] == NULL) { - continue; - } - device_vector<T>& tex_img = *cpu_textures[slot]; - uint8_t options = pack_image_options(type, slot); - const int index = type_index_to_flattened_slot(slot, type) * 2; - info[index] = make_uint4(tex_img.data_width, - tex_img.data_height, - offset, - options); - info[index+1] = make_uint4(tex_img.data_depth, 0, 0, 0); - memcpy(pixels + offset, - (void*)tex_img.data_pointer, - tex_img.memory_size()); - offset += tex_img.size(); - } -} - -void ImageManager::device_pack_images(Device *device, - DeviceScene *dscene, - Progress& /*progess*/) -{ - /* For OpenCL, we pack all image textures into a single large texture, and - * do our own interpolation in the kernel. - */ - - /* TODO(sergey): This will over-allocate a bit, but this is constant memory - * so should be fine for a short term. - */ - const size_t info_size = max4(max_flattened_slot(IMAGE_DATA_TYPE_FLOAT4), - max_flattened_slot(IMAGE_DATA_TYPE_BYTE4), - max_flattened_slot(IMAGE_DATA_TYPE_FLOAT), - max_flattened_slot(IMAGE_DATA_TYPE_BYTE)); - uint4 *info = dscene->tex_image_packed_info.resize(info_size*2); - - /* Pack byte4 textures. */ - device_pack_images_type(IMAGE_DATA_TYPE_BYTE4, - dscene->tex_byte4_image, - &dscene->tex_image_byte4_packed, - info); - /* Pack float4 textures. */ - device_pack_images_type(IMAGE_DATA_TYPE_FLOAT4, - dscene->tex_float4_image, - &dscene->tex_image_float4_packed, - info); - /* Pack byte textures. */ - device_pack_images_type(IMAGE_DATA_TYPE_BYTE, - dscene->tex_byte_image, - &dscene->tex_image_byte_packed, - info); - /* Pack float textures. */ - device_pack_images_type(IMAGE_DATA_TYPE_FLOAT, - dscene->tex_float_image, - &dscene->tex_image_float_packed, - info); - - /* Push textures to the device. */ - if(dscene->tex_image_byte4_packed.size()) { - if(dscene->tex_image_byte4_packed.device_pointer) { - thread_scoped_lock device_lock(device_mutex); - device->tex_free(dscene->tex_image_byte4_packed); - } - device->tex_alloc("__tex_image_byte4_packed", dscene->tex_image_byte4_packed); - } - if(dscene->tex_image_float4_packed.size()) { - if(dscene->tex_image_float4_packed.device_pointer) { - thread_scoped_lock device_lock(device_mutex); - device->tex_free(dscene->tex_image_float4_packed); - } - device->tex_alloc("__tex_image_float4_packed", dscene->tex_image_float4_packed); - } - if(dscene->tex_image_byte_packed.size()) { - if(dscene->tex_image_byte_packed.device_pointer) { - thread_scoped_lock device_lock(device_mutex); - device->tex_free(dscene->tex_image_byte_packed); - } - device->tex_alloc("__tex_image_byte_packed", dscene->tex_image_byte_packed); - } - if(dscene->tex_image_float_packed.size()) { - if(dscene->tex_image_float_packed.device_pointer) { - thread_scoped_lock device_lock(device_mutex); - device->tex_free(dscene->tex_image_float_packed); - } - device->tex_alloc("__tex_image_float_packed", dscene->tex_image_float_packed); - } - if(dscene->tex_image_packed_info.size()) { - if(dscene->tex_image_packed_info.device_pointer) { - thread_scoped_lock device_lock(device_mutex); - device->tex_free(dscene->tex_image_packed_info); - } - device->tex_alloc("__tex_image_packed_info", dscene->tex_image_packed_info); - } -} - void ImageManager::device_free_builtin(Device *device, DeviceScene *dscene) { for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { @@ -1251,18 +1103,6 @@ void ImageManager::device_free(Device *device, DeviceScene *dscene) dscene->tex_float_image.clear(); dscene->tex_byte_image.clear(); dscene->tex_half_image.clear(); - - device->tex_free(dscene->tex_image_float4_packed); - device->tex_free(dscene->tex_image_byte4_packed); - device->tex_free(dscene->tex_image_float_packed); - device->tex_free(dscene->tex_image_byte_packed); - device->tex_free(dscene->tex_image_packed_info); - - dscene->tex_image_float4_packed.clear(); - dscene->tex_image_byte4_packed.clear(); - dscene->tex_image_float_packed.clear(); - dscene->tex_image_byte_packed.clear(); - dscene->tex_image_packed_info.clear(); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 77214bf25bc..c86d1cbedbf 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -57,7 +57,10 @@ public: InterpolationType interpolation, ExtensionType extension, bool use_alpha); - ImageDataType get_image_metadata(const string& filename, void *builtin_data, bool& is_linear); + ImageDataType get_image_metadata(const string& filename, + void *builtin_data, + bool& is_linear, + bool& builtin_free_cache); void device_prepare_update(DeviceScene *dscene); void device_update(Device *device, @@ -73,7 +76,6 @@ public: void device_free_builtin(Device *device, DeviceScene *dscene); void set_osl_texture_system(void *texture_system); - void set_pack_images(bool pack_images_); bool set_animation_frame_update(int frame); bool need_update; @@ -88,19 +90,23 @@ public: int &width, int &height, int &depth, - int &channels)> builtin_image_info_cb; + int &channels, + bool &free_cache)> builtin_image_info_cb; function<bool(const string &filename, void *data, unsigned char *pixels, - const size_t pixels_size)> builtin_image_pixels_cb; + const size_t pixels_size, + const bool free_cache)> builtin_image_pixels_cb; function<bool(const string &filename, void *data, float *pixels, - const size_t pixels_size)> builtin_image_float_pixels_cb; + const size_t pixels_size, + const bool free_cache)> builtin_image_float_pixels_cb; struct Image { string filename; void *builtin_data; + bool builtin_free_cache; bool use_alpha; bool need_load; @@ -123,9 +129,13 @@ private: vector<Image*> images[IMAGE_DATA_NUM_TYPES]; void *osl_texture_system; - bool pack_images; - bool file_load_image_generic(Image *img, ImageInput **in, int &width, int &height, int &depth, int &components); + bool file_load_image_generic(Image *img, + ImageInput **in, + int &width, + int &height, + int &depth, + int &components); template<TypeDesc::BASETYPE FileFormat, typename StorageType, @@ -140,8 +150,6 @@ private: int flattened_slot_to_type_index(int flat_slot, ImageDataType *type); string name_from_type(int type); - uint8_t pack_image_options(ImageDataType type, size_t slot); - void device_load_image(Device *device, DeviceScene *dscene, Scene *scene, @@ -152,17 +160,6 @@ private: DeviceScene *dscene, ImageDataType type, int slot); - - template<typename T> - void device_pack_images_type( - ImageDataType type, - const vector<device_vector<T>*>& cpu_textures, - device_vector<T> *device_image, - uint4 *info); - - void device_pack_images(Device *device, - DeviceScene *dscene, - Progress& progess); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index a004bb5b856..15b728d6e02 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -31,7 +31,6 @@ NODE_DEFINE(Integrator) { NodeType *type = NodeType::add("integrator", create); - SOCKET_INT(min_bounce, "Min Bounce", 2); SOCKET_INT(max_bounce, "Max Bounce", 7); SOCKET_INT(max_diffuse_bounce, "Max Diffuse Bounce", 7); @@ -39,9 +38,7 @@ NODE_DEFINE(Integrator) SOCKET_INT(max_transmission_bounce, "Max Transmission Bounce", 7); SOCKET_INT(max_volume_bounce, "Max Volume Bounce", 7); - SOCKET_INT(transparent_min_bounce, "Transparent Min Bounce", 2); SOCKET_INT(transparent_max_bounce, "Transparent Max Bounce", 7); - SOCKET_BOOLEAN(transparent_shadows, "Transparent Shadows", false); SOCKET_INT(ao_bounces, "AO Bounces", 0); @@ -104,7 +101,6 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene /* integrator parameters */ kintegrator->max_bounce = max_bounce + 1; - kintegrator->min_bounce = min_bounce + 1; kintegrator->max_diffuse_bounce = max_diffuse_bounce + 1; kintegrator->max_glossy_bounce = max_glossy_bounce + 1; @@ -112,7 +108,6 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene kintegrator->max_volume_bounce = max_volume_bounce + 1; kintegrator->transparent_max_bounce = transparent_max_bounce + 1; - kintegrator->transparent_min_bounce = transparent_min_bounce + 1; if(ao_bounces == 0) { kintegrator->ao_bounces = INT_MAX; @@ -125,19 +120,14 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene * We only need to enable transparent shadows, if we actually have * transparent shaders in the scene. Otherwise we can disable it * to improve performance a bit. */ - if(transparent_shadows) { - kintegrator->transparent_shadows = false; - foreach(Shader *shader, scene->shaders) { - /* keep this in sync with SD_HAS_TRANSPARENT_SHADOW in shader.cpp */ - if((shader->has_surface_transparent && shader->use_transparent_shadow) || shader->has_volume) { - kintegrator->transparent_shadows = true; - break; - } + kintegrator->transparent_shadows = false; + foreach(Shader *shader, scene->shaders) { + /* keep this in sync with SD_HAS_TRANSPARENT_SHADOW in shader.cpp */ + if((shader->has_surface_transparent && shader->use_transparent_shadow) || shader->has_volume) { + kintegrator->transparent_shadows = true; + break; } } - else { - kintegrator->transparent_shadows = false; - } kintegrator->volume_max_steps = volume_max_steps; kintegrator->volume_step_size = volume_step_size; diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h index 9501d7f8416..3cb430d72b4 100644 --- a/intern/cycles/render/integrator.h +++ b/intern/cycles/render/integrator.h @@ -31,7 +31,6 @@ class Integrator : public Node { public: NODE_DECLARE - int min_bounce; int max_bounce; int max_diffuse_bounce; @@ -39,9 +38,7 @@ public: int max_transmission_bounce; int max_volume_bounce; - int transparent_min_bounce; int transparent_max_bounce; - bool transparent_shadows; int ao_bounces; diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 93d88c5642c..4adc00bc839 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -225,17 +225,13 @@ void LightManager::disable_ineffective_light(Device *device, Scene *scene) bool LightManager::object_usable_as_light(Object *object) { Mesh *mesh = object->mesh; /* Skip objects with NaNs */ - if (!object->bounds.valid()) { + if(!object->bounds.valid()) { return false; } /* Skip if we are not visible for BSDFs. */ if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) { return false; } - /* Skip motion blurred deforming meshes, not supported yet. */ - if(mesh->has_motion_blur()) { - return false; - } /* Skip if we have no emission shaders. */ /* TODO(sergey): Ideally we want to avoid such duplicated loop, since it'll * iterate all mesh shaders twice (when counting and when calculating diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 03825f780e0..84537bf5993 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -1925,16 +1925,7 @@ void MeshManager::device_update_displacement_images(Device *device, if(node->special_type != SHADER_SPECIAL_TYPE_IMAGE_SLOT) { continue; } - if(device->info.pack_images) { - /* If device requires packed images we need to update all - * images now, even if they're not used for displacement. - */ - image_manager->device_update(device, - dscene, - scene, - progress); - return; - } + ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode*>(node); int slot = image_node->slot; if(slot != -1) { diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 86e25df1da3..2b682756c6a 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -365,7 +365,8 @@ void ImageTextureNode::compile(OSLCompiler& compiler) if(is_float == -1) { if(builtin_data == NULL) { ImageDataType type; - type = image_manager->get_image_metadata(filename.string(), NULL, is_linear); + bool builtin_free_cache; + type = image_manager->get_image_metadata(filename.string(), NULL, is_linear, builtin_free_cache); if(type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4) is_float = 1; } @@ -554,7 +555,8 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) if(is_float == -1) { if(builtin_data == NULL) { ImageDataType type; - type = image_manager->get_image_metadata(filename.string(), NULL, is_linear); + bool builtin_free_cache; + type = image_manager->get_image_metadata(filename.string(), NULL, is_linear, builtin_free_cache); if(type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4) is_float = 1; } @@ -1799,6 +1801,14 @@ BsdfBaseNode::BsdfBaseNode(const NodeType *node_type) special_type = SHADER_SPECIAL_TYPE_CLOSURE; } +bool BsdfBaseNode::has_bump() +{ + /* detect if anything is plugged into the normal input besides the default */ + ShaderInput *normal_in = input("Normal"); + return (normal_in && normal_in->link && + normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY); +} + /* BSDF Closure */ BsdfNode::BsdfNode(const NodeType *node_type) @@ -2437,9 +2447,7 @@ void PrincipledBsdfNode::compile(OSLCompiler& compiler) bool PrincipledBsdfNode::has_bssrdf_bump() { - /* detect if anything is plugged into the normal input besides the default */ - ShaderInput *normal_in = input("Normal"); - return (normal_in->link && normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY); + return has_surface_bssrdf() && has_bump(); } /* Translucent BSDF Closure */ diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index c0271a3c8eb..ec4c7c7c50d 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -326,6 +326,16 @@ class BsdfBaseNode : public ShaderNode { public: BsdfBaseNode(const NodeType *node_type); + bool has_spatial_varying() { return true; } + virtual ClosureType get_closure_type() { return closure; } + virtual bool has_bump(); + + virtual bool equals(const ShaderNode& /*other*/) + { + /* TODO(sergey): With some care BSDF nodes can be de-duplicated. */ + return false; + } + ClosureType closure; }; @@ -334,19 +344,11 @@ public: explicit BsdfNode(const NodeType *node_type); SHADER_NODE_BASE_CLASS(BsdfNode) - bool has_spatial_varying() { return true; } void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3 = NULL, ShaderInput *param4 = NULL); - virtual ClosureType get_closure_type() { return closure; } float3 color; float3 normal; float surface_mix_weight; - - virtual bool equals(const ShaderNode& /*other*/) - { - /* TODO(sergey): With some care BSDF nodes can be de-duplicated. */ - return false; - } }; class AnisotropicBsdfNode : public BsdfNode { @@ -373,7 +375,6 @@ class PrincipledBsdfNode : public BsdfBaseNode { public: SHADER_NODE_CLASS(PrincipledBsdfNode) - bool has_spatial_varying() { return true; } bool has_surface_bssrdf(); bool has_bssrdf_bump(); void compile(SVMCompiler& compiler, ShaderInput *metallic, ShaderInput *subsurface, ShaderInput *subsurface_radius, @@ -390,13 +391,6 @@ public: float surface_mix_weight; ClosureType distribution, distribution_orig; - virtual bool equals(const ShaderNode * /*other*/) - { - /* TODO(sergey): With some care BSDF nodes can be de-duplicated. */ - return false; - } - - ClosureType get_closure_type() { return closure; } bool has_integrator_dependency(); void attributes(Shader *shader, AttributeRequestSet *attributes); }; diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 375abfeb27a..12690090066 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -262,6 +262,17 @@ bool Object::is_traceable() return true; } +uint Object::visibility_for_tracing() const { + uint trace_visibility = visibility; + if (is_shadow_catcher) { + trace_visibility &= ~PATH_RAY_SHADOW_NON_CATCHER; + } + else { + trace_visibility &= ~PATH_RAY_SHADOW_CATCHER; + } + return trace_visibility; +} + /* Object Manager */ ObjectManager::ObjectManager() @@ -356,6 +367,13 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s /* OBJECT_PROPERTIES */ objects[offset+8] = make_float4(surface_area, pass_id, random_number, __int_as_float(particle_index)); + if(mesh->use_motion_blur) { + state->have_motion = true; + } + if(mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) { + flag |= SD_OBJECT_HAS_VERTEX_MOTION; + } + if(state->need_motion == Scene::MOTION_PASS) { /* Motion transformations, is world/object space depending if mesh * comes with deformed position in object space, or if we transform @@ -376,9 +394,6 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s mtfm.pre = mtfm.pre * itfm; mtfm.post = mtfm.post * itfm; } - else { - flag |= SD_OBJECT_HAS_VERTEX_MOTION; - } memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+0], &mtfm.pre, sizeof(float4)*3); memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+3], &mtfm.post, sizeof(float4)*3); @@ -397,10 +412,6 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s } #endif - if(mesh->use_motion_blur) { - state->have_motion = true; - } - /* Dupli object coords and motion info. */ int totalsteps = mesh->motion_steps; int numsteps = (totalsteps - 1)/2; diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 12d7b2c81cf..6927bbfe4c7 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -60,7 +60,7 @@ public: ParticleSystem *particle_system; int particle_index; - + Object(); ~Object(); @@ -75,6 +75,11 @@ public: * kernel scene. */ bool is_traceable(); + + /* Combine object's visibility with all possible internal run-time + * determined flags which denotes trace-time visibility. + */ + uint visibility_for_tracing() const; }; /* Object Manager */ diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index a794f233718..5c5ac6e2be9 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -233,8 +233,10 @@ void OSLShaderManager::shading_system_init() "glossy", /* PATH_RAY_GLOSSY */ "singular", /* PATH_RAY_SINGULAR */ "transparent", /* PATH_RAY_TRANSPARENT */ - "shadow", /* PATH_RAY_SHADOW_OPAQUE */ - "shadow", /* PATH_RAY_SHADOW_TRANSPARENT */ + "shadow", /* PATH_RAY_SHADOW_OPAQUE_NON_CATCHER */ + "shadow", /* PATH_RAY_SHADOW_OPAQUE_CATCHER */ + "shadow", /* PATH_RAY_SHADOW_TRANSPARENT_NON_CATCHER */ + "shadow", /* PATH_RAY_SHADOW_TRANSPARENT_CATCHER */ "__unused__", "__unused__", @@ -719,6 +721,7 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath) current_shader->has_surface_bssrdf = true; current_shader->has_bssrdf_bump = true; /* can't detect yet */ } + current_shader->has_bump = true; /* can't detect yet */ } if(node->has_spatial_varying()) { @@ -1027,6 +1030,9 @@ void OSLCompiler::generate_nodes(const ShaderNodeSet& nodes) if(node->has_bssrdf_bump()) current_shader->has_bssrdf_bump = true; } + if(node->has_bump()) { + current_shader->has_bump = true; + } } else if(current_type == SHADER_TYPE_VOLUME) { if(node->has_spatial_varying()) @@ -1089,21 +1095,14 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader) ShaderGraph *graph = shader->graph; ShaderNode *output = (graph)? graph->output(): NULL; - /* copy graph for shader with bump mapping */ - if(output->input("Surface")->link && output->input("Displacement")->link) - if(!shader->graph_bump) - shader->graph_bump = shader->graph->copy(); + bool has_bump = (shader->displacement_method != DISPLACE_TRUE) && + output->input("Surface")->link && output->input("Displacement")->link; /* finalize */ shader->graph->finalize(scene, - false, - shader->has_integrator_dependency); - if(shader->graph_bump) { - shader->graph_bump->finalize(scene, - true, - shader->has_integrator_dependency, - shader->displacement_method == DISPLACE_BOTH); - } + has_bump, + shader->has_integrator_dependency, + shader->displacement_method == DISPLACE_BOTH); current_shader = shader; @@ -1111,7 +1110,8 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader) shader->has_surface_emission = false; shader->has_surface_transparent = false; shader->has_surface_bssrdf = false; - shader->has_bssrdf_bump = false; + shader->has_bump = has_bump; + shader->has_bssrdf_bump = has_bump; shader->has_volume = false; shader->has_displacement = false; shader->has_surface_spatial_varying = false; @@ -1123,8 +1123,8 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader) if(shader->used && graph && output->input("Surface")->link) { shader->osl_surface_ref = compile_type(shader, shader->graph, SHADER_TYPE_SURFACE); - if(shader->graph_bump && shader->displacement_method != DISPLACE_TRUE) - shader->osl_surface_bump_ref = compile_type(shader, shader->graph_bump, SHADER_TYPE_BUMP); + if(has_bump) + shader->osl_surface_bump_ref = compile_type(shader, shader->graph, SHADER_TYPE_BUMP); else shader->osl_surface_bump_ref = OSL::ShaderGroupRef(); diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 4db20338744..c59a5d97df5 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -148,8 +148,6 @@ void Scene::device_update(Device *device_, Progress& progress) * - Film needs light manager to run for use_light_visibility * - Lookup tables are done a second time to handle film tables */ - - image_manager->set_pack_images(device->info.pack_images); progress.set_status("Updating Shaders"); shader_manager->device_update(device, &dscene, this, progress); diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 4c2c4f5fcc3..0194327f567 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -121,13 +121,6 @@ public: vector<device_vector<uchar>* > tex_byte_image; vector<device_vector<half>* > tex_half_image; - /* opencl images */ - device_vector<float4> tex_image_float4_packed; - device_vector<uchar4> tex_image_byte4_packed; - device_vector<float> tex_image_float_packed; - device_vector<uchar> tex_image_byte_packed; - device_vector<uint4> tex_image_packed_info; - KernelData data; }; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index ae462a1084a..f68efe38add 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -46,7 +46,7 @@ Session::Session(const SessionParams& params_) : params(params_), tile_manager(params.progressive, params.samples, params.tile_size, params.start_resolution, params.background == false || params.progressive_refine, params.background, params.tile_order, - max(params.device.multi_devices.size(), 1)), + max(params.device.multi_devices.size(), 1), params.pixel_size), stats() { device_use_gl = ((params.device.type != DEVICE_CPU) && !params.background); @@ -721,7 +721,6 @@ DeviceRequestedFeatures Session::get_requested_device_features() BakeManager *bake_manager = scene->bake_manager; requested_features.use_baking = bake_manager->get_baking(); requested_features.use_integrator_branched = (scene->integrator->method == Integrator::BRANCHED_PATH); - requested_features.use_transparent &= scene->integrator->transparent_shadows; requested_features.use_denoising = params.use_denoising; return requested_features; @@ -931,7 +930,7 @@ void Session::update_status_time(bool show_pause, bool show_done) const bool rendering_finished = (tile == num_tiles); const bool is_last_tile = (tile + 1) == num_tiles; - substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles); + substatus = string_printf("Rendered %d/%d Tiles", tile, num_tiles); if(!rendering_finished && (device->show_samples() || (is_cpu && is_last_tile))) { /* Some devices automatically support showing the sample number: @@ -961,6 +960,7 @@ void Session::update_status_time(bool show_pause, bool show_done) } else if(show_done) { status = "Done"; + progress.set_end_time(); /* Save end time so that further calls to get_time are accurate. */ } else { status = substatus; diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 9f8bb8c42fa..980eda0876d 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -53,6 +53,7 @@ public: int2 tile_size; TileOrder tile_order; int start_resolution; + int pixel_size; int threads; bool display_buffer_linear; @@ -81,6 +82,7 @@ public: samples = INT_MAX; tile_size = make_int2(64, 64); start_resolution = INT_MAX; + pixel_size = 1; threads = 0; use_denoising = false; @@ -110,6 +112,7 @@ public: && experimental == params.experimental && tile_size == params.tile_size && start_resolution == params.start_resolution + && pixel_size == params.pixel_size && threads == params.threads && display_buffer_linear == params.display_buffer_linear && cancel_timeout == params.cancel_timeout diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 50400edd5ca..86378dfb495 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -177,7 +177,6 @@ Shader::Shader() pass_id = 0; graph = NULL; - graph_bump = NULL; has_surface = false; has_surface_transparent = false; @@ -185,11 +184,13 @@ Shader::Shader() has_surface_bssrdf = false; has_volume = false; has_displacement = false; + has_bump = false; has_bssrdf_bump = false; has_surface_spatial_varying = false; has_volume_spatial_varying = false; has_object_dependency = false; has_integrator_dependency = false; + has_volume_connected = false; displacement_method = DISPLACE_BUMP; @@ -203,7 +204,6 @@ Shader::Shader() Shader::~Shader() { delete graph; - delete graph_bump; } bool Shader::is_constant_emission(float3 *emission) @@ -238,9 +238,7 @@ void Shader::set_graph(ShaderGraph *graph_) /* assign graph */ delete graph; - delete graph_bump; graph = graph_; - graph_bump = NULL; /* Store info here before graph optimization to make sure that * nodes that get optimized away still count. */ @@ -457,15 +455,11 @@ void ShaderManager::device_update_common(Device *device, flag |= SD_VOLUME_MIS; if(shader->volume_interpolation_method == VOLUME_INTERPOLATION_CUBIC) flag |= SD_VOLUME_CUBIC; - if(shader->graph_bump) + if(shader->has_bump) flag |= SD_HAS_BUMP; if(shader->displacement_method != DISPLACE_BUMP) flag |= SD_HAS_DISPLACEMENT; - /* shader with bump mapping */ - if(shader->displacement_method != DISPLACE_TRUE && shader->graph_bump) - flag |= SD_HAS_BSSRDF_BUMP; - /* constant emission check */ float3 constant_emission = make_float3(0.0f, 0.0f, 0.0f); if(shader->is_constant_emission(&constant_emission)) @@ -502,9 +496,7 @@ void ShaderManager::device_update_common(Device *device, KernelIntegrator *kintegrator = &dscene->data.integrator; kintegrator->use_volumes = has_volumes; /* TODO(sergey): De-duplicate with flags set in integrator.cpp. */ - if(scene->integrator->transparent_shadows) { - kintegrator->transparent_shadows = has_transparent_shadow; - } + kintegrator->transparent_shadows = has_transparent_shadow; } void ShaderManager::device_free_common(Device *device, DeviceScene *dscene, Scene *scene) @@ -609,11 +601,6 @@ void ShaderManager::get_requested_features(Scene *scene, Shader *shader = scene->shaders[i]; /* Gather requested features from all the nodes from the graph nodes. */ get_requested_graph_features(shader->graph, requested_features); - /* Gather requested features from the graph itself. */ - if(shader->graph_bump) { - get_requested_graph_features(shader->graph_bump, - requested_features); - } ShaderNode *output_node = shader->graph->output(); if(output_node->input("Displacement")->link != NULL) { requested_features->nodes_features |= NODE_FEATURE_BUMP; diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h index b6714b13247..79a67d6756a 100644 --- a/intern/cycles/render/shader.h +++ b/intern/cycles/render/shader.h @@ -89,11 +89,6 @@ public: /* shader graph */ ShaderGraph *graph; - /* shader graph with auto bump mapping included, we compile two shaders, - * with and without bump, because the displacement method is a mesh - * level setting, so we need to handle both */ - ShaderGraph *graph_bump; - /* sampling */ bool use_mis; bool use_transparent_shadow; @@ -121,6 +116,7 @@ public: bool has_volume; bool has_displacement; bool has_surface_bssrdf; + bool has_bump; bool has_bssrdf_bump; bool has_surface_spatial_varying; bool has_volume_spatial_varying; diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 48287d872d4..32f89897970 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -521,6 +521,9 @@ void SVMCompiler::generate_closure_node(ShaderNode *node, if(node->has_bssrdf_bump()) current_shader->has_bssrdf_bump = true; } + if(node->has_bump()) { + current_shader->has_bump = true; + } } } @@ -799,29 +802,21 @@ void SVMCompiler::compile(Scene *scene, Summary *summary) { /* copy graph for shader with bump mapping */ - ShaderNode *node = shader->graph->output(); + ShaderNode *output = shader->graph->output(); int start_num_svm_nodes = svm_nodes.size(); const double time_start = time_dt(); - if(node->input("Surface")->link && node->input("Displacement")->link) - if(!shader->graph_bump) - shader->graph_bump = shader->graph->copy(); + bool has_bump = (shader->displacement_method != DISPLACE_TRUE) && + output->input("Surface")->link && output->input("Displacement")->link; /* finalize */ { scoped_timer timer((summary != NULL)? &summary->time_finalize: NULL); shader->graph->finalize(scene, - false, - shader->has_integrator_dependency); - } - - if(shader->graph_bump) { - scoped_timer timer((summary != NULL)? &summary->time_finalize_bump: NULL); - shader->graph_bump->finalize(scene, - true, - shader->has_integrator_dependency, - shader->displacement_method == DISPLACE_BOTH); + has_bump, + shader->has_integrator_dependency, + shader->displacement_method == DISPLACE_BOTH); } current_shader = shader; @@ -830,7 +825,8 @@ void SVMCompiler::compile(Scene *scene, shader->has_surface_emission = false; shader->has_surface_transparent = false; shader->has_surface_bssrdf = false; - shader->has_bssrdf_bump = false; + shader->has_bump = has_bump; + shader->has_bssrdf_bump = has_bump; shader->has_volume = false; shader->has_displacement = false; shader->has_surface_spatial_varying = false; @@ -839,9 +835,9 @@ void SVMCompiler::compile(Scene *scene, shader->has_integrator_dependency = false; /* generate bump shader */ - if(shader->displacement_method != DISPLACE_TRUE && shader->graph_bump) { + if(has_bump) { scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL); - compile_type(shader, shader->graph_bump, SHADER_TYPE_BUMP); + compile_type(shader, shader->graph, SHADER_TYPE_BUMP); svm_nodes[index].y = svm_nodes.size(); svm_nodes.insert(svm_nodes.end(), current_svm_nodes.begin(), @@ -853,7 +849,7 @@ void SVMCompiler::compile(Scene *scene, scoped_timer timer((summary != NULL)? &summary->time_generate_surface: NULL); compile_type(shader, shader->graph, SHADER_TYPE_SURFACE); /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this one if it exists */ - if(shader->displacement_method == DISPLACE_TRUE || !shader->graph_bump) { + if(!has_bump) { svm_nodes[index].y = svm_nodes.size(); } svm_nodes.insert(svm_nodes.end(), @@ -895,7 +891,6 @@ SVMCompiler::Summary::Summary() : num_svm_nodes(0), peak_stack_usage(0), time_finalize(0.0), - time_finalize_bump(0.0), time_generate_surface(0.0), time_generate_bump(0.0), time_generate_volume(0.0), @@ -911,10 +906,7 @@ string SVMCompiler::Summary::full_report() const report += string_printf("Peak stack usage: %d\n", peak_stack_usage); report += string_printf("Time (in seconds):\n"); - report += string_printf(" Finalize: %f\n", time_finalize); - report += string_printf(" Bump finalize: %f\n", time_finalize_bump); - report += string_printf("Finalize: %f\n", time_finalize + - time_finalize_bump); + report += string_printf("Finalize: %f\n", time_finalize); report += string_printf(" Surface: %f\n", time_generate_surface); report += string_printf(" Bump: %f\n", time_generate_bump); report += string_printf(" Volume: %f\n", time_generate_volume); diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h index abbd9e50610..98ef5fa05d8 100644 --- a/intern/cycles/render/svm.h +++ b/intern/cycles/render/svm.h @@ -74,9 +74,6 @@ public: /* Time spent on surface graph finalization. */ double time_finalize; - /* Time spent on bump graph finalization. */ - double time_finalize_bump; - /* Time spent on generating SVM nodes for surface shader. */ double time_generate_surface; diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp index 176a1f4f0f3..a9620f79fa0 100644 --- a/intern/cycles/render/tile.cpp +++ b/intern/cycles/render/tile.cpp @@ -88,12 +88,14 @@ enum SpiralDirection { } /* namespace */ TileManager::TileManager(bool progressive_, int num_samples_, int2 tile_size_, int start_resolution_, - bool preserve_tile_device_, bool background_, TileOrder tile_order_, int num_devices_) + bool preserve_tile_device_, bool background_, TileOrder tile_order_, + int num_devices_, int pixel_size_) { progressive = progressive_; tile_size = tile_size_; tile_order = tile_order_; start_resolution = start_resolution_; + pixel_size = pixel_size_; num_samples = num_samples_; num_devices = num_devices_; preserve_tile_device = preserve_tile_device_; @@ -163,15 +165,17 @@ void TileManager::set_samples(int num_samples_) uint64_t pixel_samples = 0; /* While rendering in the viewport, the initial preview resolution is increased to the native resolution * before the actual rendering begins. Therefore, additional pixel samples will be rendered. */ - int divider = get_divider(params.width, params.height, start_resolution) / 2; - while(divider > 1) { + int divider = max(get_divider(params.width, params.height, start_resolution) / 2, pixel_size); + while(divider > pixel_size) { int image_w = max(1, params.width/divider); int image_h = max(1, params.height/divider); pixel_samples += image_w * image_h; divider >>= 1; } - state.total_pixel_samples = pixel_samples + (uint64_t)get_num_effective_samples() * params.width*params.height; + int image_w = max(1, params.width/divider); + int image_h = max(1, params.height/divider); + state.total_pixel_samples = pixel_samples + (uint64_t)get_num_effective_samples() * image_w*image_h; if(schedule_denoising) { state.total_pixel_samples += params.width*params.height; } @@ -471,7 +475,7 @@ bool TileManager::done() int end_sample = (range_num_samples == -1) ? num_samples : range_start_sample + range_num_samples; - return (state.resolution_divider == 1) && + return (state.resolution_divider == pixel_size) && (state.sample+state.num_samples >= end_sample); } @@ -480,9 +484,9 @@ bool TileManager::next() if(done()) return false; - if(progressive && state.resolution_divider > 1) { + if(progressive && state.resolution_divider > pixel_size) { state.sample = 0; - state.resolution_divider /= 2; + state.resolution_divider = max(state.resolution_divider/2, pixel_size); state.num_samples = 1; set_tiles(); } @@ -496,7 +500,7 @@ bool TileManager::next() else state.num_samples = range_num_samples; - state.resolution_divider = 1; + state.resolution_divider = pixel_size; set_tiles(); } diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h index e39a8f0627a..4cd57b7b30c 100644 --- a/intern/cycles/render/tile.h +++ b/intern/cycles/render/tile.h @@ -88,7 +88,7 @@ public: int num_samples; TileManager(bool progressive, int num_samples, int2 tile_size, int start_resolution, - bool preserve_tile_device, bool background, TileOrder tile_order, int num_devices = 1); + bool preserve_tile_device, bool background, TileOrder tile_order, int num_devices = 1, int pixel_size = 1); ~TileManager(); void free_device(); @@ -122,6 +122,7 @@ protected: int2 tile_size; TileOrder tile_order; int start_resolution; + int pixel_size; int num_devices; /* in some cases it is important that the same tile will be returned for the same diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index 43f9a57d099..7f3747a0f58 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -38,6 +38,7 @@ set(SRC_HEADERS util_atomic.h util_boundbox.h util_debug.h + util_defines.h util_guarded_allocator.cpp util_foreach.h util_function.h diff --git a/intern/cycles/util/util_atomic.h b/intern/cycles/util/util_atomic.h index 643af87a65f..f3c7ae546a0 100644 --- a/intern/cycles/util/util_atomic.h +++ b/intern/cycles/util/util_atomic.h @@ -22,16 +22,6 @@ /* Using atomic ops header from Blender. */ #include "atomic_ops.h" -ATOMIC_INLINE void atomic_update_max_z(size_t *maximum_value, size_t value) -{ - size_t prev_value = *maximum_value; - while(prev_value < value) { - if(atomic_cas_z(maximum_value, prev_value, value) != prev_value) { - break; - } - } -} - #define atomic_add_and_fetch_float(p, x) atomic_add_and_fetch_fl((p), (x)) #define atomic_fetch_and_inc_uint32(p) atomic_fetch_and_add_uint32((p), 1) diff --git a/intern/cycles/util/util_debug.cpp b/intern/cycles/util/util_debug.cpp index 10895f2e918..eb078d69252 100644 --- a/intern/cycles/util/util_debug.cpp +++ b/intern/cycles/util/util_debug.cpp @@ -122,13 +122,16 @@ void DebugFlags::OpenCL::reset() } DebugFlags::DebugFlags() +: viewport_static_bvh(false) { /* Nothing for now. */ } void DebugFlags::reset() { + viewport_static_bvh = false; cpu.reset(); + cuda.reset(); opencl.reset(); } diff --git a/intern/cycles/util/util_debug.h b/intern/cycles/util/util_debug.h index 450cd900a9f..9255279c5ab 100644 --- a/intern/cycles/util/util_debug.h +++ b/intern/cycles/util/util_debug.h @@ -30,6 +30,9 @@ CCL_NAMESPACE_BEGIN */ class DebugFlags { public: + /* Use static BVH in viewport, to match final render exactly. */ + bool viewport_static_bvh; + /* Descriptor of CPU feature-set to be used. */ struct CPU { CPU(); diff --git a/intern/cycles/util/util_defines.h b/intern/cycles/util/util_defines.h new file mode 100644 index 00000000000..ae654092c87 --- /dev/null +++ b/intern/cycles/util/util_defines.h @@ -0,0 +1,135 @@ + +/* + * Copyright 2011-2017 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UTIL_DEFINES_H__ +#define __UTIL_DEFINES_H__ + +/* Bitness */ + +#if defined(__ppc64__) || defined(__PPC64__) || defined(__x86_64__) || defined(__ia64__) || defined(_M_X64) +# define __KERNEL_64_BIT__ +#endif + +/* Qualifiers for kernel code shared by CPU and GPU */ + +#ifndef __KERNEL_GPU__ +# define ccl_device static inline +# define ccl_device_noinline static +# define ccl_global +# define ccl_constant +# define ccl_local +# define ccl_local_param +# define ccl_private +# define ccl_restrict __restrict +# define ccl_ref & +# define __KERNEL_WITH_SSE_ALIGN__ + +# if defined(_WIN32) && !defined(FREE_WINDOWS) +# define ccl_device_inline static __forceinline +# define ccl_device_forceinline static __forceinline +# define ccl_align(...) __declspec(align(__VA_ARGS__)) +# ifdef __KERNEL_64_BIT__ +# define ccl_try_align(...) __declspec(align(__VA_ARGS__)) +# else /* __KERNEL_64_BIT__ */ +# undef __KERNEL_WITH_SSE_ALIGN__ +/* No support for function arguments (error C2719). */ +# define ccl_try_align(...) +# endif /* __KERNEL_64_BIT__ */ +# define ccl_may_alias +# define ccl_always_inline __forceinline +# define ccl_never_inline __declspec(noinline) +# define ccl_maybe_unused +# else /* _WIN32 && !FREE_WINDOWS */ +# define ccl_device_inline static inline __attribute__((always_inline)) +# define ccl_device_forceinline static inline __attribute__((always_inline)) +# define ccl_align(...) __attribute__((aligned(__VA_ARGS__))) +# ifndef FREE_WINDOWS64 +# define __forceinline inline __attribute__((always_inline)) +# endif +# define ccl_try_align(...) __attribute__((aligned(__VA_ARGS__))) +# define ccl_may_alias __attribute__((__may_alias__)) +# define ccl_always_inline __attribute__((always_inline)) +# define ccl_never_inline __attribute__((noinline)) +# define ccl_maybe_unused __attribute__((used)) +# endif /* _WIN32 && !FREE_WINDOWS */ + +/* Use to suppress '-Wimplicit-fallthrough' (in place of 'break'). */ +# if defined(__GNUC__) && (__GNUC__ >= 7) /* gcc7.0+ only */ +# define ATTR_FALLTHROUGH __attribute__((fallthrough)) +# else +# define ATTR_FALLTHROUGH ((void)0) +# endif +#endif /* __KERNEL_GPU__ */ + +/* macros */ + +/* hints for branch prediction, only use in code that runs a _lot_ */ +#if defined(__GNUC__) && defined(__KERNEL_CPU__) +# define LIKELY(x) __builtin_expect(!!(x), 1) +# define UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +# define LIKELY(x) (x) +# define UNLIKELY(x) (x) +#endif + +#if defined(__cplusplus) && ((__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1800)) +# define HAS_CPP11_FEATURES +#endif + +#if defined(__GNUC__) || defined(__clang__) +# if defined(HAS_CPP11_FEATURES) +/* Some magic to be sure we don't have reference in the type. */ +template<typename T> static inline T decltype_helper(T x) { return x; } +# define TYPEOF(x) decltype(decltype_helper(x)) +# else +# define TYPEOF(x) typeof(x) +# endif +#endif + +/* Causes warning: + * incompatible types when assigning to type 'Foo' from type 'Bar' + * ... the compiler optimizes away the temp var */ +#ifdef __GNUC__ +#define CHECK_TYPE(var, type) { \ + TYPEOF(var) *__tmp; \ + __tmp = (type *)NULL; \ + (void)__tmp; \ +} (void)0 + +#define CHECK_TYPE_PAIR(var_a, var_b) { \ + TYPEOF(var_a) *__tmp; \ + __tmp = (typeof(var_b) *)NULL; \ + (void)__tmp; \ +} (void)0 +#else +# define CHECK_TYPE(var, type) +# define CHECK_TYPE_PAIR(var_a, var_b) +#endif + +/* can be used in simple macros */ +#define CHECK_TYPE_INLINE(val, type) \ + ((void)(((type)0) != (val))) + +#ifndef __KERNEL_GPU__ +# include <cassert> +# define util_assert(statement) assert(statement) +#else +# define util_assert(statement) +#endif + +#endif /* __UTIL_DEFINES_H__ */ + diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index b719640b19c..fb04d49bcd9 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -94,6 +94,7 @@ ccl_device_inline float fminf(float a, float b) #ifndef __KERNEL_GPU__ using std::isfinite; using std::isnan; +using std::sqrt; ccl_device_inline int abs(int x) { @@ -223,7 +224,7 @@ ccl_device_inline bool isfinite_safe(float f) { /* By IEEE 754 rule, 2*Inf equals Inf */ unsigned int x = __float_as_uint(f); - return (f == f) && (x == 0 || (f != 2.0f*f)) && !((x << 1) > 0xff000000u); + return (f == f) && (x == 0 || x == (1u << 31) || (f != 2.0f*f)) && !((x << 1) > 0xff000000u); } ccl_device_inline float ensure_finite(float v) @@ -329,15 +330,22 @@ template<class A, class B> A lerp(const A& a, const A& b, const B& t) return (A)(a * ((B)1 - t) + b * t); } +#endif /* __KERNEL_OPENCL__ */ + /* Triangle */ +#ifndef __KERNEL_OPENCL__ ccl_device_inline float triangle_area(const float3& v1, const float3& v2, const float3& v3) +#else +ccl_device_inline float triangle_area(const float3 v1, + const float3 v2, + const float3 v3) +#endif { return len(cross(v3 - v2, v1 - v2))*0.5f; } -#endif /* __KERNEL_OPENCL__ */ /* Orthonormal vectors */ diff --git a/intern/cycles/util/util_math_float3.h b/intern/cycles/util/util_math_float3.h index bb04c4aa2d9..e73e5bc17a2 100644 --- a/intern/cycles/util/util_math_float3.h +++ b/intern/cycles/util/util_math_float3.h @@ -108,8 +108,7 @@ ccl_device_inline float3 operator*(const float3& a, const float f) ccl_device_inline float3 operator*(const float f, const float3& a) { - /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */ -#if defined(__KERNEL_SSE__) && 0 +#if defined(__KERNEL_SSE__) return float3(_mm_mul_ps(_mm_set1_ps(f), a.m128)); #else return make_float3(a.x*f, a.y*f, a.z*f); @@ -118,10 +117,8 @@ ccl_device_inline float3 operator*(const float f, const float3& a) ccl_device_inline float3 operator/(const float f, const float3& a) { - /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */ -#if defined(__KERNEL_SSE__) && 0 - __m128 rc = _mm_rcp_ps(a.m128); - return float3(_mm_mul_ps(_mm_set1_ps(f),rc)); +#if defined(__KERNEL_SSE__) + return float3(_mm_div_ps(_mm_set1_ps(f), a.m128)); #else return make_float3(f / a.x, f / a.y, f / a.z); #endif @@ -135,10 +132,8 @@ ccl_device_inline float3 operator/(const float3& a, const float f) ccl_device_inline float3 operator/(const float3& a, const float3& b) { - /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */ -#if defined(__KERNEL_SSE__) && 0 - __m128 rc = _mm_rcp_ps(b.m128); - return float3(_mm_mul_ps(a, rc)); +#if defined(__KERNEL_SSE__) + return float3(_mm_div_ps(a.m128, b.m128)); #else return make_float3(a.x / b.x, a.y / b.y, a.z / b.z); #endif @@ -282,9 +277,8 @@ ccl_device_inline float3 mix(const float3& a, const float3& b, float t) ccl_device_inline float3 rcp(const float3& a) { #ifdef __KERNEL_SSE__ - const float4 r(_mm_rcp_ps(a.m128)); - return float3(_mm_sub_ps(_mm_add_ps(r, r), - _mm_mul_ps(_mm_mul_ps(r, r), a))); + /* Don't use _mm_rcp_ps due to poor precision. */ + return float3(_mm_div_ps(_mm_set_ps1(1.0f), a.m128)); #else return make_float3(1.0f/a.x, 1.0f/a.y, 1.0f/a.z); #endif diff --git a/intern/cycles/util/util_math_float4.h b/intern/cycles/util/util_math_float4.h index d89121b3a1d..aa7e56fefe9 100644 --- a/intern/cycles/util/util_math_float4.h +++ b/intern/cycles/util/util_math_float4.h @@ -48,23 +48,30 @@ ccl_device_inline bool operator==(const float4& a, const float4& b); ccl_device_inline float dot(const float4& a, const float4& b); ccl_device_inline float len_squared(const float4& a); ccl_device_inline float4 rcp(const float4& a); +ccl_device_inline float4 sqrt(const float4& a); +ccl_device_inline float4 sqr(const float4& a); ccl_device_inline float4 cross(const float4& a, const float4& b); ccl_device_inline bool is_zero(const float4& a); -ccl_device_inline float reduce_add(const float4& a); ccl_device_inline float average(const float4& a); ccl_device_inline float len(const float4& a); ccl_device_inline float4 normalize(const float4& a); ccl_device_inline float4 safe_normalize(const float4& a); ccl_device_inline float4 min(const float4& a, const float4& b); ccl_device_inline float4 max(const float4& a, const float4& b); +ccl_device_inline float4 fabs(const float4& a); #endif /* !__KERNEL_OPENCL__*/ #ifdef __KERNEL_SSE__ template<size_t index_0, size_t index_1, size_t index_2, size_t index_3> __forceinline const float4 shuffle(const float4& b); +template<size_t index_0, size_t index_1, size_t index_2, size_t index_3> +__forceinline const float4 shuffle(const float4& a, const float4& b); template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4& b); +template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4& a, const float4& b); +template<> __forceinline const float4 shuffle<2, 3, 2, 3>(const float4& a, const float4& b); + # ifdef __KERNEL_SSE3__ template<> __forceinline const float4 shuffle<0, 0, 2, 2>(const float4& b); template<> __forceinline const float4 shuffle<1, 1, 3, 3>(const float4& b); @@ -77,9 +84,7 @@ ccl_device_inline float4 select(const int4& mask, const float4& b); ccl_device_inline float4 reduce_min(const float4& a); ccl_device_inline float4 reduce_max(const float4& a); -# if 0 ccl_device_inline float4 reduce_add(const float4& a); -# endif #endif /* !__KERNEL_GPU__ */ /******************************************************************************* @@ -128,7 +133,7 @@ ccl_device_inline float4 operator/(const float4& a, float f) ccl_device_inline float4 operator/(const float4& a, const float4& b) { #ifdef __KERNEL_SSE__ - return a * rcp(b); + return float4(_mm_div_ps(a.m128, b.m128)); #else return make_float4(a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w); #endif @@ -171,8 +176,7 @@ ccl_device_inline float4 operator/=(float4& a, float f) ccl_device_inline int4 operator<(const float4& a, const float4& b) { #ifdef __KERNEL_SSE__ - /* TODO(sergey): avoid cvt. */ - return int4(_mm_cvtps_epi32(_mm_cmplt_ps(a.m128, b.m128))); + return int4(_mm_castps_si128(_mm_cmplt_ps(a.m128, b.m128))); #else return make_int4(a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w); #endif @@ -181,8 +185,7 @@ ccl_device_inline int4 operator<(const float4& a, const float4& b) ccl_device_inline int4 operator>=(const float4& a, const float4& b) { #ifdef __KERNEL_SSE__ - /* TODO(sergey): avoid cvt. */ - return int4(_mm_cvtps_epi32(_mm_cmpge_ps(a.m128, b.m128))); + return int4(_mm_castps_si128(_mm_cmpge_ps(a.m128, b.m128))); #else return make_int4(a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w); #endif @@ -191,8 +194,7 @@ ccl_device_inline int4 operator>=(const float4& a, const float4& b) ccl_device_inline int4 operator<=(const float4& a, const float4& b) { #ifdef __KERNEL_SSE__ - /* TODO(sergey): avoid cvt. */ - return int4(_mm_cvtps_epi32(_mm_cmple_ps(a.m128, b.m128))); + return int4(_mm_castps_si128(_mm_cmple_ps(a.m128, b.m128))); #else return make_int4(a.x <= b.x, a.y <= b.y, a.z <= b.z, a.w <= b.w); #endif @@ -224,14 +226,30 @@ ccl_device_inline float len_squared(const float4& a) ccl_device_inline float4 rcp(const float4& a) { #ifdef __KERNEL_SSE__ - float4 r(_mm_rcp_ps(a.m128)); - return float4(_mm_sub_ps(_mm_add_ps(r, r), - _mm_mul_ps(_mm_mul_ps(r, r), a))); + /* Don't use _mm_rcp_ps due to poor precision. */ + return float4(_mm_div_ps(_mm_set_ps1(1.0f), a.m128)); #else return make_float4(1.0f/a.x, 1.0f/a.y, 1.0f/a.z, 1.0f/a.w); #endif } +ccl_device_inline float4 sqrt(const float4& a) +{ +#ifdef __KERNEL_SSE__ + return float4(_mm_sqrt_ps(a.m128)); +#else + return make_float4(sqrtf(a.x), + sqrtf(a.y), + sqrtf(a.z), + sqrtf(a.w)); +#endif +} + +ccl_device_inline float4 sqr(const float4& a) +{ + return a * a; +} + ccl_device_inline float4 cross(const float4& a, const float4& b) { #ifdef __KERNEL_SSE__ @@ -254,20 +272,25 @@ ccl_device_inline bool is_zero(const float4& a) #endif } -ccl_device_inline float reduce_add(const float4& a) +ccl_device_inline float4 reduce_add(const float4& a) { #ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE3__ + float4 h(_mm_hadd_ps(a.m128, a.m128)); + return float4( _mm_hadd_ps(h.m128, h.m128)); +# else float4 h(shuffle<1,0,3,2>(a) + a); - /* TODO(sergey): Investigate efficiency. */ - return _mm_cvtss_f32(shuffle<2,3,0,1>(h) + h); + return shuffle<2,3,0,1>(h) + h; +# endif #else - return ((a.x + a.y) + (a.z + a.w)); + float sum = (a.x + a.y) + (a.z + a.w); + return make_float4(sum, sum, sum, sum); #endif } ccl_device_inline float average(const float4& a) { - return reduce_add(a) * 0.25f; + return reduce_add(a).x * 0.25f; } ccl_device_inline float len(const float4& a) @@ -309,6 +332,18 @@ ccl_device_inline float4 max(const float4& a, const float4& b) max(a.w, b.w)); #endif } + +ccl_device_inline float4 fabs(const float4& a) +{ +#ifdef __KERNEL_SSE__ + return float4(_mm_and_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)))); +#else + return make_float4(fabsf(a.x), + fabsf(a.y), + fabsf(a.z), + fabsf(a.w)); +#endif +} #endif /* !__KERNEL_OPENCL__*/ #ifdef __KERNEL_SSE__ @@ -320,11 +355,28 @@ __forceinline const float4 shuffle(const float4& b) _MM_SHUFFLE(index_3, index_2, index_1, index_0)))); } +template<size_t index_0, size_t index_1, size_t index_2, size_t index_3> +__forceinline const float4 shuffle(const float4& a, const float4& b) +{ + return float4(_mm_shuffle_ps(a.m128, b.m128, + _MM_SHUFFLE(index_3, index_2, index_1, index_0))); +} + template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4& b) { return float4(_mm_castpd_ps(_mm_movedup_pd(_mm_castps_pd(b)))); } +template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4& a, const float4& b) +{ + return float4(_mm_movelh_ps(a.m128, b.m128)); +} + +template<> __forceinline const float4 shuffle<2, 3, 2, 3>(const float4& a, const float4& b) +{ + return float4(_mm_movehl_ps(b.m128, a.m128)); +} + # ifdef __KERNEL_SSE3__ template<> __forceinline const float4 shuffle<0, 0, 2, 2>(const float4& b) { @@ -344,9 +396,7 @@ ccl_device_inline float4 select(const int4& mask, const float4& b) { #ifdef __KERNEL_SSE__ - /* TODO(sergey): avoid cvt. */ - return float4(_mm_or_ps(_mm_and_ps(_mm_cvtepi32_ps(mask), a), - _mm_andnot_ps(_mm_cvtepi32_ps(mask), b))); + return float4(_mm_blendv_ps(b.m128, a.m128, _mm_castsi128_ps(mask.m128))); #else return make_float4((mask.x)? a.x: b.x, (mask.y)? a.y: b.y, @@ -355,6 +405,13 @@ ccl_device_inline float4 select(const int4& mask, #endif } +ccl_device_inline float4 mask(const int4& mask, + const float4& a) +{ + /* Replace elements of x with zero where mask isn't set. */ + return select(mask, a, make_float4(0.0f)); +} + ccl_device_inline float4 reduce_min(const float4& a) { #ifdef __KERNEL_SSE__ @@ -375,17 +432,15 @@ ccl_device_inline float4 reduce_max(const float4& a) #endif } -#if 0 -ccl_device_inline float4 reduce_add(const float4& a) +ccl_device_inline float4 load_float4(const float *v) { #ifdef __KERNEL_SSE__ - float4 h = shuffle<1,0,3,2>(a) + a; - return shuffle<2,3,0,1>(h) + h; + return float4(_mm_loadu_ps(v)); #else - return make_float4((a.x + a.y) + (a.z + a.w)); + return make_float4(v[0], v[1], v[2], v[3]); #endif } -#endif + #endif /* !__KERNEL_GPU__ */ CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_math_matrix.h b/intern/cycles/util/util_math_matrix.h index c7511f8306e..b31dbe4fc67 100644 --- a/intern/cycles/util/util_math_matrix.h +++ b/intern/cycles/util/util_math_matrix.h @@ -223,20 +223,20 @@ ccl_device void math_matrix_jacobi_eigendecomposition(float *A, ccl_global float { const float singular_epsilon = 1e-9f; - for (int row = 0; row < n; row++) { - for (int col = 0; col < n; col++) { + for(int row = 0; row < n; row++) { + for(int col = 0; col < n; col++) { MATS(V, n, row, col, v_stride) = (col == row) ? 1.0f : 0.0f; } } - for (int sweep = 0; sweep < 8; sweep++) { + for(int sweep = 0; sweep < 8; sweep++) { float off_diagonal = 0.0f; - for (int row = 1; row < n; row++) { - for (int col = 0; col < row; col++) { + for(int row = 1; row < n; row++) { + for(int col = 0; col < row; col++) { off_diagonal += fabsf(MAT(A, n, row, col)); } } - if (off_diagonal < 1e-7f) { + if(off_diagonal < 1e-7f) { /* The matrix has nearly reached diagonal form. * Since the eigenvalues are only used to determine truncation, their exact values aren't required - a relative error of a few ULPs won't matter at all. */ break; @@ -253,7 +253,7 @@ ccl_device void math_matrix_jacobi_eigendecomposition(float *A, ccl_global float float abs_element = fabsf(element); /* If we're in a later sweep and the element already is very small, just set it to zero and skip the rotation. */ - if (sweep > 3 && abs_element <= singular_epsilon*fabsf(MAT(A, n, row, row)) && abs_element <= singular_epsilon*fabsf(MAT(A, n, col, col))) { + if(sweep > 3 && abs_element <= singular_epsilon*fabsf(MAT(A, n, row, row)) && abs_element <= singular_epsilon*fabsf(MAT(A, n, col, col))) { MAT(A, n, row, col) = 0.0f; continue; } @@ -272,10 +272,10 @@ ccl_device void math_matrix_jacobi_eigendecomposition(float *A, ccl_global float * Then, we compute sin(phi) and cos(phi) themselves. */ float singular_diff = MAT(A, n, row, row) - MAT(A, n, col, col); float ratio; - if (abs_element > singular_epsilon*fabsf(singular_diff)) { + if(abs_element > singular_epsilon*fabsf(singular_diff)) { float cot_2phi = 0.5f*singular_diff / element; ratio = 1.0f / (fabsf(cot_2phi) + sqrtf(1.0f + cot_2phi*cot_2phi)); - if (cot_2phi < 0.0f) ratio = -ratio; /* Copy sign. */ + if(cot_2phi < 0.0f) ratio = -ratio; /* Copy sign. */ } else { ratio = element / singular_diff; @@ -315,21 +315,21 @@ ccl_device void math_matrix_jacobi_eigendecomposition(float *A, ccl_global float } /* Sort eigenvalues and the associated eigenvectors. */ - for (int i = 0; i < n - 1; i++) { + for(int i = 0; i < n - 1; i++) { float v = MAT(A, n, i, i); int k = i; - for (int j = i; j < n; j++) { - if (MAT(A, n, j, j) >= v) { + for(int j = i; j < n; j++) { + if(MAT(A, n, j, j) >= v) { v = MAT(A, n, j, j); k = j; } } - if (k != i) { + if(k != i) { /* Swap eigenvalues. */ MAT(A, n, k, k) = MAT(A, n, i, i); MAT(A, n, i, i) = v; /* Swap eigenvectors. */ - for (int j = 0; j < n; j++) { + for(int j = 0; j < n; j++) { float v = MATS(V, n, i, j, v_stride); MATS(V, n, i, j, v_stride) = MATS(V, n, k, j, v_stride); MATS(V, n, k, j, v_stride) = v; @@ -339,59 +339,59 @@ ccl_device void math_matrix_jacobi_eigendecomposition(float *A, ccl_global float } #ifdef __KERNEL_SSE3__ -ccl_device_inline void math_vector_zero_sse(__m128 *A, int n) +ccl_device_inline void math_vector_zero_sse(float4 *A, int n) { for(int i = 0; i < n; i++) { - A[i] = _mm_setzero_ps(); + A[i] = make_float4(0.0f); } } -ccl_device_inline void math_matrix_zero_sse(__m128 *A, int n) +ccl_device_inline void math_matrix_zero_sse(float4 *A, int n) { for(int row = 0; row < n; row++) { for(int col = 0; col <= row; col++) { - MAT(A, n, row, col) = _mm_setzero_ps(); + MAT(A, n, row, col) = make_float4(0.0f); } } } /* Add Gramian matrix of v to A. * The Gramian matrix of v is v^T*v, so element (i,j) is v[i]*v[j]. */ -ccl_device_inline void math_matrix_add_gramian_sse(__m128 *A, int n, const __m128 *ccl_restrict v, __m128 weight) +ccl_device_inline void math_matrix_add_gramian_sse(float4 *A, int n, const float4 *ccl_restrict v, float4 weight) { for(int row = 0; row < n; row++) { for(int col = 0; col <= row; col++) { - MAT(A, n, row, col) = _mm_add_ps(MAT(A, n, row, col), _mm_mul_ps(_mm_mul_ps(v[row], v[col]), weight)); + MAT(A, n, row, col) = MAT(A, n, row, col) + v[row] * v[col] * weight; } } } -ccl_device_inline void math_vector_add_sse(__m128 *V, int n, const __m128 *ccl_restrict a) +ccl_device_inline void math_vector_add_sse(float4 *V, int n, const float4 *ccl_restrict a) { for(int i = 0; i < n; i++) { - V[i] = _mm_add_ps(V[i], a[i]); + V[i] += a[i]; } } -ccl_device_inline void math_vector_mul_sse(__m128 *V, int n, const __m128 *ccl_restrict a) +ccl_device_inline void math_vector_mul_sse(float4 *V, int n, const float4 *ccl_restrict a) { for(int i = 0; i < n; i++) { - V[i] = _mm_mul_ps(V[i], a[i]); + V[i] *= a[i]; } } -ccl_device_inline void math_vector_max_sse(__m128 *a, const __m128 *ccl_restrict b, int n) +ccl_device_inline void math_vector_max_sse(float4 *a, const float4 *ccl_restrict b, int n) { for(int i = 0; i < n; i++) { - a[i] = _mm_max_ps(a[i], b[i]); + a[i] = max(a[i], b[i]); } } -ccl_device_inline void math_matrix_hsum(float *A, int n, const __m128 *ccl_restrict B) +ccl_device_inline void math_matrix_hsum(float *A, int n, const float4 *ccl_restrict B) { for(int row = 0; row < n; row++) { for(int col = 0; col <= row; col++) { - MAT(A, n, row, col) = _mm_hsum_ss(MAT(B, n, row, col)); + MAT(A, n, row, col) = reduce_add(MAT(B, n, row, col))[0]; } } } diff --git a/intern/cycles/util/util_optimization.h b/intern/cycles/util/util_optimization.h index 6f70a474fe7..3c5785c4807 100644 --- a/intern/cycles/util/util_optimization.h +++ b/intern/cycles/util/util_optimization.h @@ -19,22 +19,15 @@ #ifndef __KERNEL_GPU__ -/* quiet unused define warnings */ -#if defined(__KERNEL_SSE2__) || \ - defined(__KERNEL_SSE3__) || \ - defined(__KERNEL_SSSE3__) || \ - defined(__KERNEL_SSE41__) || \ - defined(__KERNEL_AVX__) || \ - defined(__KERNEL_AVX2__) - /* do nothing */ -#endif - /* x86 * * Compile a regular, SSE2 and SSE3 kernel. */ #if defined(i386) || defined(_M_IX86) +/* We require minimum SSE2 support on x86, so auto enable. */ +# define __KERNEL_SSE2__ + # ifdef WITH_KERNEL_SSE2 # define WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 # endif @@ -73,48 +66,6 @@ #endif /* defined(__x86_64__) || defined(_M_X64) */ -/* SSE Experiment - * - * This is disabled code for an experiment to use SSE types globally for types - * such as float3 and float4. Currently this gives an overall slowdown. */ - -#if 0 -# define __KERNEL_SSE__ -# ifndef __KERNEL_SSE2__ -# define __KERNEL_SSE2__ -# endif -# ifndef __KERNEL_SSE3__ -# define __KERNEL_SSE3__ -# endif -# ifndef __KERNEL_SSSE3__ -# define __KERNEL_SSSE3__ -# endif -# ifndef __KERNEL_SSE4__ -# define __KERNEL_SSE4__ -# endif -#endif - -/* SSE Intrinsics includes - * - * We assume __KERNEL_SSEX__ flags to have been defined at this point */ - -/* SSE intrinsics headers */ -#ifndef FREE_WINDOWS64 - -#ifdef _MSC_VER -# include <intrin.h> -#elif (defined(__x86_64__) || defined(__i386__)) -# include <x86intrin.h> -#endif - -#else - -/* MinGW64 has conflicting declarations for these SSE headers in <windows.h>. - * Since we can't avoid including <windows.h>, better only include that */ -#include "util/util_windows.h" - -#endif - #endif #endif /* __UTIL_OPTIMIZATION_H__ */ diff --git a/intern/cycles/util/util_path.cpp b/intern/cycles/util/util_path.cpp index f9c3b4bb139..bae5d5bd6d1 100644 --- a/intern/cycles/util/util_path.cpp +++ b/intern/cycles/util/util_path.cpp @@ -45,6 +45,7 @@ OIIO_NAMESPACE_USING # include <shlwapi.h> #endif +#include "util/util_map.h" #include "util/util_windows.h" CCL_NAMESPACE_BEGIN @@ -768,68 +769,180 @@ bool path_remove(const string& path) return remove(path.c_str()) == 0; } -static string line_directive(const string& base, const string& path, int line) +struct SourceReplaceState { + typedef map<string, string> ProcessedMapping; + /* Base director for all relative include headers. */ + string base; + /* Result of processed files. */ + ProcessedMapping processed_files; + /* Set of files which are considered "precompiled" and which are replaced + * with and empty string on a subsequent occurrence in include statement. + */ + set<string> precompiled_headers; +}; + +static string path_source_replace_includes_recursive( + const string& source, + const string& source_filepath, + SourceReplaceState *state); + +static string line_directive(const SourceReplaceState& state, + const string& path, + const int line) { - string escaped_path = path; + string unescaped_path = path; /* First we make path relative. */ - if(string_startswith(escaped_path, base.c_str())) { - const string base_file = path_filename(base); - const size_t base_len = base.length(); - escaped_path = base_file + escaped_path.substr(base_len, - escaped_path.length() - base_len); + if(string_startswith(unescaped_path, state.base.c_str())) { + const string base_file = path_filename(state.base); + const size_t base_len = state.base.length(); + unescaped_path = base_file + + unescaped_path.substr(base_len, + unescaped_path.length() - base_len); } /* Second, we replace all unsafe characters. */ - string_replace(escaped_path, "\"", "\\\""); - string_replace(escaped_path, "\'", "\\\'"); - string_replace(escaped_path, "\?", "\\\?"); - string_replace(escaped_path, "\\", "\\\\"); + const size_t length = unescaped_path.length(); + string escaped_path = ""; + for(size_t i = 0; i < length; ++i) { + const char ch = unescaped_path[i]; + if(strchr("\"\'\?\\", ch) != NULL) { + escaped_path += "\\"; + } + escaped_path += ch; + } + /* TODO(sergey): Check whether using std::to_string combined with several + * concatenation operations is any faster. + */ return string_printf("#line %d \"%s\"", line, escaped_path.c_str()); } +static string path_source_handle_preprocessor( + const string& preprocessor_line, + const string& source_filepath, + const size_t line_number, + SourceReplaceState *state) +{ + string result = preprocessor_line; + string token = string_strip( + preprocessor_line.substr(1, preprocessor_line.size() - 1)); + if(string_startswith(token, "include")) { + token = string_strip(token.substr(7, token.size() - 7)); + if(token[0] == '"') { + const size_t n_start = 1; + const size_t n_end = token.find("\"", n_start); + const string filename = token.substr(n_start, n_end - n_start); + const bool is_precompiled = string_endswith(token, "// PRECOMPILED"); + string filepath = path_join(state->base, filename); + if(!path_exists(filepath)) { + filepath = path_join(path_dirname(source_filepath), + filename); + } + if(is_precompiled) { + state->precompiled_headers.insert(filepath); + } + string text; + if(path_read_text(filepath, text)) { + text = path_source_replace_includes_recursive( + text, filepath, state); + /* Use line directives for better error messages. */ + result = line_directive(*state, filepath, 1) + "\n" + + text + "\n" + + line_directive(*state, source_filepath, line_number + 1); + } + } + } + return result; +} + +/* Our own little c preprocessor that replaces #includes with the file + * contents, to work around issue of OpenCL drivers not supporting + * include paths with spaces in them. + */ static string path_source_replace_includes_recursive( - const string& base, const string& source, - const string& source_filepath) + const string& source_filepath, + SourceReplaceState *state) { - /* Our own little c preprocessor that replaces #includes with the file - * contents, to work around issue of OpenCL drivers not supporting - * include paths with spaces in them. + /* Try to re-use processed file without spending time on replacing all + * include directives again. */ - + SourceReplaceState::ProcessedMapping::iterator replaced_file = + state->processed_files.find(source_filepath); + if(replaced_file != state->processed_files.end()) { + if(state->precompiled_headers.find(source_filepath) != + state->precompiled_headers.end()) { + return ""; + } + return replaced_file->second; + } + /* Perform full file processing. */ string result = ""; - vector<string> lines; - string_split(lines, source, "\n", false); - - for(size_t i = 0; i < lines.size(); ++i) { - string line = lines[i]; - if(line[0] == '#') { - string token = string_strip(line.substr(1, line.size() - 1)); - if(string_startswith(token, "include")) { - token = string_strip(token.substr(7, token.size() - 7)); - if(token[0] == '"') { - const size_t n_start = 1; - const size_t n_end = token.find("\"", n_start); - const string filename = token.substr(n_start, n_end - n_start); - string filepath = path_join(base, filename); - if(!path_exists(filepath)) { - filepath = path_join(path_dirname(source_filepath), - filename); - } - string text; - if(path_read_text(filepath, text)) { - text = path_source_replace_includes_recursive( - base, text, filepath); - /* Use line directives for better error messages. */ - line = line_directive(base, filepath, 1) - + token.replace(0, n_end + 1, "\n" + text + "\n") - + line_directive(base, source_filepath, i + 1); - } - } + const size_t source_length = source.length(); + size_t index = 0; + /* Information about where we are in the source. */ + size_t line_number = 0, column_number = 1; + /* Currently gathered non-preprocessor token. + * Store as start/length rather than token itself to avoid overhead of + * memory re-allocations on each character concatenation. + */ + size_t token_start = 0, token_length = 0; + /* Denotes whether we're inside of preprocessor line, together with + * preprocessor line itself. + * + * TODO(sergey): Investigate whether using token start/end position + * gives measurable speedup. + */ + bool inside_preprocessor = false; + string preprocessor_line = ""; + /* Actual loop over the whole source. */ + while(index < source_length) { + const char ch = source[index]; + if(ch == '\n') { + if(inside_preprocessor) { + result += path_source_handle_preprocessor(preprocessor_line, + source_filepath, + line_number, + state); + /* Start gathering net part of the token. */ + token_start = index; + token_length = 0; + } + inside_preprocessor = false; + preprocessor_line = ""; + column_number = 0; + ++line_number; + } + else if(ch == '#' && column_number == 1 && !inside_preprocessor) { + /* Append all possible non-preprocessor token to the result. */ + if(token_length != 0) { + result.append(source, token_start, token_length); + token_start = index; + token_length = 0; } + inside_preprocessor = true; + } + if(inside_preprocessor) { + preprocessor_line += ch; + } + else { + ++token_length; } - result += line + "\n"; + ++index; + ++column_number; } - + /* Append possible tokens which happened before special events handled + * above. + */ + if(token_length != 0) { + result.append(source, token_start, token_length); + } + if(inside_preprocessor) { + result += path_source_handle_preprocessor(preprocessor_line, + source_filepath, + line_number, + state); + } + /* Store result for further reuse. */ + state->processed_files[source_filepath] = result; return result; } @@ -837,10 +950,12 @@ string path_source_replace_includes(const string& source, const string& path, const string& source_filename) { + SourceReplaceState state; + state.base = path; return path_source_replace_includes_recursive( - path, source, - path_join(path, source_filename)); + path_join(path, source_filename), + &state); } FILE *path_fopen(const string& path, const string& mode) diff --git a/intern/cycles/util/util_progress.h b/intern/cycles/util/util_progress.h index cd4fe52fdc9..134383e88db 100644 --- a/intern/cycles/util/util_progress.h +++ b/intern/cycles/util/util_progress.h @@ -41,6 +41,7 @@ public: denoised_tiles = 0; start_time = time_dt(); render_start_time = time_dt(); + end_time = 0.0; status = "Initializing"; substatus = ""; sync_status = ""; @@ -80,6 +81,7 @@ public: denoised_tiles = 0; start_time = time_dt(); render_start_time = time_dt(); + end_time = 0.0; status = "Initializing"; substatus = ""; sync_status = ""; @@ -146,6 +148,7 @@ public: thread_scoped_lock lock(progress_mutex); start_time = time_dt(); + end_time = 0.0; } void set_render_start_time() @@ -169,8 +172,15 @@ public: { thread_scoped_lock lock(progress_mutex); - total_time_ = time_dt() - start_time; - render_time_ = time_dt() - render_start_time; + double time = (end_time > 0) ? end_time : time_dt(); + + total_time_ = time - start_time; + render_time_ = time - render_start_time; + } + + void set_end_time() + { + end_time = time_dt(); } void reset_sample() @@ -337,6 +347,8 @@ protected: int rendered_tiles, denoised_tiles; double start_time, render_start_time; + /* End time written when render is done, so it doesn't keep increasing on redraws. */ + double end_time; string status; string substatus; diff --git a/intern/cycles/util/util_simd.h b/intern/cycles/util/util_simd.h index 587febe3e52..58b3d267266 100644 --- a/intern/cycles/util/util_simd.h +++ b/intern/cycles/util/util_simd.h @@ -18,19 +18,38 @@ #ifndef __UTIL_SIMD_TYPES_H__ #define __UTIL_SIMD_TYPES_H__ +#ifndef __KERNEL_GPU__ + #include <limits> #include "util/util_debug.h" -#include "util/util_types.h" +#include "util/util_defines.h" + +/* SSE Intrinsics includes + * + * We assume __KERNEL_SSEX__ flags to have been defined at this point */ + +/* SSE intrinsics headers */ +#ifndef FREE_WINDOWS64 + +#ifdef _MSC_VER +# include <intrin.h> +#elif (defined(__x86_64__) || defined(__i386__)) +# include <x86intrin.h> +#endif + +#else + +/* MinGW64 has conflicting declarations for these SSE headers in <windows.h>. + * Since we can't avoid including <windows.h>, better only include that */ +#include "util/util_windows.h" + +#endif CCL_NAMESPACE_BEGIN #ifdef __KERNEL_SSE2__ -struct sseb; -struct ssei; -struct ssef; - extern const __m128 _mm_lookupmask_ps[16]; /* Special Types */ @@ -328,12 +347,12 @@ __forceinline size_t __bscf(size_t& v) #endif /* _WIN32 */ -static const unsigned int BITSCAN_NO_BIT_SET_32 = 32; -static const size_t BITSCAN_NO_BIT_SET_64 = 64; +/* Test __KERNEL_SSE41__ for MSVC which does not define __SSE4_1__, and test + * __SSE4_1__ to avoid OpenImageIO conflicts with our emulation macros on other + * platforms when compiling code outside the kernel. */ +#if !(defined(__KERNEL_SSE41__) || defined(__SSE4_1__) || defined(__SSE4_2__)) -#ifdef __KERNEL_SSE3__ -/* Emulation of SSE4 functions with SSE3 */ -# ifndef __KERNEL_SSE41__ +/* Emulation of SSE4 functions with SSE2 */ #define _MM_FROUND_TO_NEAREST_INT 0x00 #define _MM_FROUND_TO_NEG_INF 0x01 @@ -342,50 +361,50 @@ static const size_t BITSCAN_NO_BIT_SET_64 = 64; #define _MM_FROUND_CUR_DIRECTION 0x04 #undef _mm_blendv_ps -#define _mm_blendv_ps __emu_mm_blendv_ps -__forceinline __m128 _mm_blendv_ps( __m128 value, __m128 input, __m128 mask ) { - return _mm_or_ps(_mm_and_ps(mask, input), _mm_andnot_ps(mask, value)); +#define _mm_blendv_ps _mm_blendv_ps_emu +__forceinline __m128 _mm_blendv_ps_emu( __m128 value, __m128 input, __m128 mask) +{ + __m128i isignmask = _mm_set1_epi32(0x80000000); + __m128 signmask = _mm_castsi128_ps(isignmask); + __m128i iandsign = _mm_castps_si128(_mm_and_ps(mask, signmask)); + __m128i icmpmask = _mm_cmpeq_epi32(iandsign, isignmask); + __m128 cmpmask = _mm_castsi128_ps(icmpmask); + return _mm_or_ps(_mm_and_ps(cmpmask, input), _mm_andnot_ps(cmpmask, value)); } #undef _mm_blend_ps -#define _mm_blend_ps __emu_mm_blend_ps -__forceinline __m128 _mm_blend_ps( __m128 value, __m128 input, const int mask ) { +#define _mm_blend_ps _mm_blend_ps_emu +__forceinline __m128 _mm_blend_ps_emu( __m128 value, __m128 input, const int mask) +{ assert(mask < 0x10); return _mm_blendv_ps(value, input, _mm_lookupmask_ps[mask]); } #undef _mm_blendv_epi8 -#define _mm_blendv_epi8 __emu_mm_blendv_epi8 -__forceinline __m128i _mm_blendv_epi8( __m128i value, __m128i input, __m128i mask ) { +#define _mm_blendv_epi8 _mm_blendv_epi8_emu +__forceinline __m128i _mm_blendv_epi8_emu( __m128i value, __m128i input, __m128i mask) +{ return _mm_or_si128(_mm_and_si128(mask, input), _mm_andnot_si128(mask, value)); } -#undef _mm_mullo_epi32 -#define _mm_mullo_epi32 __emu_mm_mullo_epi32 -__forceinline __m128i _mm_mullo_epi32( __m128i value, __m128i input ) { - __m128i rvalue; - char* _r = (char*)(&rvalue + 1); - char* _v = (char*)(& value + 1); - char* _i = (char*)(& input + 1); - for( ssize_t i = -16 ; i != 0 ; i += 4 ) *((int32_t*)(_r + i)) = *((int32_t*)(_v + i))* *((int32_t*)(_i + i)); - return rvalue; -} - #undef _mm_min_epi32 -#define _mm_min_epi32 __emu_mm_min_epi32 -__forceinline __m128i _mm_min_epi32( __m128i value, __m128i input ) { +#define _mm_min_epi32 _mm_min_epi32_emu +__forceinline __m128i _mm_min_epi32_emu( __m128i value, __m128i input) +{ return _mm_blendv_epi8(input, value, _mm_cmplt_epi32(value, input)); } #undef _mm_max_epi32 -#define _mm_max_epi32 __emu_mm_max_epi32 -__forceinline __m128i _mm_max_epi32( __m128i value, __m128i input ) { +#define _mm_max_epi32 _mm_max_epi32_emu +__forceinline __m128i _mm_max_epi32_emu( __m128i value, __m128i input) +{ return _mm_blendv_epi8(value, input, _mm_cmplt_epi32(value, input)); } #undef _mm_extract_epi32 -#define _mm_extract_epi32 __emu_mm_extract_epi32 -__forceinline int _mm_extract_epi32( __m128i input, const int index ) { - switch ( index ) { +#define _mm_extract_epi32 _mm_extract_epi32_emu +__forceinline int _mm_extract_epi32_emu( __m128i input, const int index) +{ + switch(index) { case 0: return _mm_cvtsi128_si32(input); case 1: return _mm_cvtsi128_si32(_mm_shuffle_epi32(input, _MM_SHUFFLE(1, 1, 1, 1))); case 2: return _mm_cvtsi128_si32(_mm_shuffle_epi32(input, _MM_SHUFFLE(2, 2, 2, 2))); @@ -395,27 +414,26 @@ __forceinline int _mm_extract_epi32( __m128i input, const int index ) { } #undef _mm_insert_epi32 -#define _mm_insert_epi32 __emu_mm_insert_epi32 -__forceinline __m128i _mm_insert_epi32( __m128i value, int input, const int index ) { +#define _mm_insert_epi32 _mm_insert_epi32_emu +__forceinline __m128i _mm_insert_epi32_emu( __m128i value, int input, const int index) +{ assert(index >= 0 && index < 4); ((int*)&value)[index] = input; return value; } -#undef _mm_extract_ps -#define _mm_extract_ps __emu_mm_extract_ps -__forceinline int _mm_extract_ps( __m128 input, const int index ) { - int32_t* ptr = (int32_t*)&input; return ptr[index]; -} - #undef _mm_insert_ps -#define _mm_insert_ps __emu_mm_insert_ps -__forceinline __m128 _mm_insert_ps( __m128 value, __m128 input, const int index ) -{ assert(index < 0x100); ((float*)&value)[(index >> 4)&0x3] = ((float*)&input)[index >> 6]; return _mm_andnot_ps(_mm_lookupmask_ps[index&0xf], value); } +#define _mm_insert_ps _mm_insert_ps_emu +__forceinline __m128 _mm_insert_ps_emu( __m128 value, __m128 input, const int index) +{ + assert(index < 0x100); + ((float*)&value)[(index >> 4)&0x3] = ((float*)&input)[index >> 6]; + return _mm_andnot_ps(_mm_lookupmask_ps[index&0xf], value); +} #undef _mm_round_ps -#define _mm_round_ps __emu_mm_round_ps -__forceinline __m128 _mm_round_ps( __m128 value, const int flags ) +#define _mm_round_ps _mm_round_ps_emu +__forceinline __m128 _mm_round_ps_emu( __m128 value, const int flags) { - switch ( flags ) + switch(flags) { case _MM_FROUND_TO_NEAREST_INT: return _mm_cvtepi32_ps(_mm_cvtps_epi32(value)); case _MM_FROUND_TO_NEG_INF : return _mm_cvtepi32_ps(_mm_cvtps_epi32(_mm_add_ps(value, _mm_set1_ps(-0.5f)))); @@ -425,57 +443,7 @@ __forceinline __m128 _mm_round_ps( __m128 value, const int flags ) return value; } -# ifdef _M_X64 -#undef _mm_insert_epi64 -#define _mm_insert_epi64 __emu_mm_insert_epi64 -__forceinline __m128i _mm_insert_epi64( __m128i value, __int64 input, const int index ) { - assert(size_t(index) < 4); ((__int64*)&value)[index] = input; return value; -} - -#undef _mm_extract_epi64 -#define _mm_extract_epi64 __emu_mm_extract_epi64 -__forceinline __int64 _mm_extract_epi64( __m128i input, const int index ) { - assert(size_t(index) < 2); - return index == 0 ? _mm_cvtsi128_si64x(input) : _mm_cvtsi128_si64x(_mm_unpackhi_epi64(input, input)); -} -# endif - -# endif - -#undef _mm_fabs_ps -#define _mm_fabs_ps(x) _mm_and_ps(x, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff))) - -/* Return a __m128 with every element set to the largest element of v. */ -ccl_device_inline __m128 _mm_hmax_ps(__m128 v) -{ - /* v[0, 1, 2, 3] => [0, 1, 0, 1] and [2, 3, 2, 3] => v[max(0, 2), max(1, 3), max(0, 2), max(1, 3)] */ - v = _mm_max_ps(_mm_movehl_ps(v, v), _mm_movelh_ps(v, v)); - /* v[max(0, 2), max(1, 3), max(0, 2), max(1, 3)] => [4 times max(1, 3)] and [4 times max(0, 2)] => v[4 times max(0, 1, 2, 3)] */ - v = _mm_max_ps(_mm_movehdup_ps(v), _mm_moveldup_ps(v)); - return v; -} - -/* Return the sum of the four elements of x. */ -ccl_device_inline float _mm_hsum_ss(__m128 x) -{ - __m128 a = _mm_movehdup_ps(x); - __m128 b = _mm_add_ps(x, a); - return _mm_cvtss_f32(_mm_add_ss(_mm_movehl_ps(a, b), b)); -} - -/* Return a __m128 with every element set to the sum of the four elements of x. */ -ccl_device_inline __m128 _mm_hsum_ps(__m128 x) -{ - x = _mm_hadd_ps(x, x); - x = _mm_hadd_ps(x, x); - return x; -} - -/* Replace elements of x with zero where mask isn't set. */ -#undef _mm_mask_ps -#define _mm_mask_ps(x, mask) _mm_blendv_ps(_mm_setzero_ps(), x, mask) - -#endif +#endif /* !(defined(__KERNEL_SSE41__) || defined(__SSE4_1__) || defined(__SSE4_2__)) */ #else /* __KERNEL_SSE2__ */ @@ -496,13 +464,19 @@ ccl_device_inline int bitscan(int value) #endif /* __KERNEL_SSE2__ */ +/* quiet unused define warnings */ +#if defined(__KERNEL_SSE2__) || \ + defined(__KERNEL_SSE3__) || \ + defined(__KERNEL_SSSE3__) || \ + defined(__KERNEL_SSE41__) || \ + defined(__KERNEL_AVX__) || \ + defined(__KERNEL_AVX2__) + /* do nothing */ +#endif + CCL_NAMESPACE_END -#include "util/util_math.h" -#include "util/util_sseb.h" -#include "util/util_ssei.h" -#include "util/util_ssef.h" -#include "util/util_avxf.h" +#endif /* __KERNEL_GPU__ */ #endif /* __UTIL_SIMD_TYPES_H__ */ diff --git a/intern/cycles/util/util_sseb.h b/intern/cycles/util/util_sseb.h index 6e669701f3b..93c22aafdcd 100644 --- a/intern/cycles/util/util_sseb.h +++ b/intern/cycles/util/util_sseb.h @@ -22,6 +22,9 @@ CCL_NAMESPACE_BEGIN #ifdef __KERNEL_SSE2__ +struct ssei; +struct ssef; + /*! 4-wide SSE bool type. */ struct sseb { diff --git a/intern/cycles/util/util_ssef.h b/intern/cycles/util/util_ssef.h index cf99a08efae..bb007ff84a9 100644 --- a/intern/cycles/util/util_ssef.h +++ b/intern/cycles/util/util_ssef.h @@ -22,6 +22,9 @@ CCL_NAMESPACE_BEGIN #ifdef __KERNEL_SSE2__ +struct sseb; +struct ssef; + /*! 4-wide SSE float type. */ struct ssef { diff --git a/intern/cycles/util/util_ssei.h b/intern/cycles/util/util_ssei.h index 5f62569268c..ef2a9e68b7d 100644 --- a/intern/cycles/util/util_ssei.h +++ b/intern/cycles/util/util_ssei.h @@ -22,6 +22,9 @@ CCL_NAMESPACE_BEGIN #ifdef __KERNEL_SSE2__ +struct sseb; +struct ssef; + /*! 4-wide SSE integer type. */ struct ssei { @@ -234,8 +237,10 @@ __forceinline size_t select_max(const sseb& valid, const ssei& v) { const ssei a #else -__forceinline int reduce_min(const ssei& v) { return min(min(v[0],v[1]),min(v[2],v[3])); } -__forceinline int reduce_max(const ssei& v) { return max(max(v[0],v[1]),max(v[2],v[3])); } +__forceinline int ssei_min(int a, int b) { return (a < b)? a: b; } +__forceinline int ssei_max(int a, int b) { return (a > b)? a: b; } +__forceinline int reduce_min(const ssei& v) { return ssei_min(ssei_min(v[0],v[1]),ssei_min(v[2],v[3])); } +__forceinline int reduce_max(const ssei& v) { return ssei_max(ssei_max(v[0],v[1]),ssei_max(v[2],v[3])); } __forceinline int reduce_add(const ssei& v) { return v[0]+v[1]+v[2]+v[3]; } #endif diff --git a/intern/cycles/util/util_stats.h b/intern/cycles/util/util_stats.h index baba549753d..7667f58eb7d 100644 --- a/intern/cycles/util/util_stats.h +++ b/intern/cycles/util/util_stats.h @@ -30,7 +30,7 @@ public: void mem_alloc(size_t size) { atomic_add_and_fetch_z(&mem_used, size); - atomic_update_max_z(&mem_peak, mem_used); + atomic_fetch_and_update_max_z(&mem_peak, mem_used); } void mem_free(size_t size) { diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp index fb0c34e1dc4..6ed97b0e0a6 100644 --- a/intern/cycles/util/util_task.cpp +++ b/intern/cycles/util/util_task.cpp @@ -206,9 +206,9 @@ void TaskScheduler::init(int num_threads) threads.resize(num_threads); const int num_groups = system_cpu_group_count(); - unsigned short num_process_groups; + unsigned short num_process_groups = 0; vector<unsigned short> process_groups; - int current_group_threads; + int current_group_threads = 0; if(num_groups > 1) { process_groups.resize(num_groups); num_process_groups = system_cpu_process_groups(num_groups, diff --git a/intern/cycles/util/util_time.h b/intern/cycles/util/util_time.h index 65798244111..f03aa590e9b 100644 --- a/intern/cycles/util/util_time.h +++ b/intern/cycles/util/util_time.h @@ -37,7 +37,7 @@ public: ~scoped_timer() { if(value_ != NULL) { - *value_ = time_dt() - time_start_; + *value_ = get_time(); } } @@ -46,6 +46,11 @@ public: return time_start_; } + double get_time() const + { + return time_dt() - time_start_; + } + protected: double *value_; double time_start_; diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h index a5d1d7152d5..aabca6c81fc 100644 --- a/intern/cycles/util/util_types.h +++ b/intern/cycles/util/util_types.h @@ -21,72 +21,18 @@ # include <stdlib.h> #endif -/* Bitness */ +/* Standard Integer Types */ -#if defined(__ppc64__) || defined(__PPC64__) || defined(__x86_64__) || defined(__ia64__) || defined(_M_X64) -# define __KERNEL_64_BIT__ +#if !defined(__KERNEL_GPU__) && !defined(_WIN32) +# include <stdint.h> #endif -/* Qualifiers for kernel code shared by CPU and GPU */ - -#ifndef __KERNEL_GPU__ -# define ccl_device static inline -# define ccl_device_noinline static -# define ccl_global -# define ccl_constant -# define ccl_local -# define ccl_local_param -# define ccl_private -# define ccl_restrict __restrict -# define __KERNEL_WITH_SSE_ALIGN__ - -# if defined(_WIN32) && !defined(FREE_WINDOWS) -# define ccl_device_inline static __forceinline -# define ccl_device_forceinline static __forceinline -# define ccl_align(...) __declspec(align(__VA_ARGS__)) -# ifdef __KERNEL_64_BIT__ -# define ccl_try_align(...) __declspec(align(__VA_ARGS__)) -# else /* __KERNEL_64_BIT__ */ -# undef __KERNEL_WITH_SSE_ALIGN__ -/* No support for function arguments (error C2719). */ -# define ccl_try_align(...) -# endif /* __KERNEL_64_BIT__ */ -# define ccl_may_alias -# define ccl_always_inline __forceinline -# define ccl_never_inline __declspec(noinline) -# define ccl_maybe_unused -# else /* _WIN32 && !FREE_WINDOWS */ -# define ccl_device_inline static inline __attribute__((always_inline)) -# define ccl_device_forceinline static inline __attribute__((always_inline)) -# define ccl_align(...) __attribute__((aligned(__VA_ARGS__))) -# ifndef FREE_WINDOWS64 -# define __forceinline inline __attribute__((always_inline)) -# endif -# define ccl_try_align(...) __attribute__((aligned(__VA_ARGS__))) -# define ccl_may_alias __attribute__((__may_alias__)) -# define ccl_always_inline __attribute__((always_inline)) -# define ccl_never_inline __attribute__((noinline)) -# define ccl_maybe_unused __attribute__((used)) -# endif /* _WIN32 && !FREE_WINDOWS */ - -/* Use to suppress '-Wimplicit-fallthrough' (in place of 'break'). */ -# if defined(__GNUC__) && (__GNUC__ >= 7) /* gcc7.0+ only */ -# define ATTR_FALLTHROUGH __attribute__((fallthrough)) -# else -# define ATTR_FALLTHROUGH ((void)0) -# endif -#endif /* __KERNEL_GPU__ */ - -/* Standard Integer Types */ +#include "util/util_defines.h" #ifndef __KERNEL_GPU__ -/* int8_t, uint16_t, and friends */ -# ifndef _WIN32 -# include <stdint.h> -# endif -/* SIMD Types */ # include "util/util_optimization.h" -#endif /* __KERNEL_GPU__ */ +# include "util/util_simd.h" +#endif CCL_NAMESPACE_BEGIN @@ -201,65 +147,8 @@ enum ExtensionType { EXTENSION_NUM_TYPES, }; -/* macros */ - -/* hints for branch prediction, only use in code that runs a _lot_ */ -#if defined(__GNUC__) && defined(__KERNEL_CPU__) -# define LIKELY(x) __builtin_expect(!!(x), 1) -# define UNLIKELY(x) __builtin_expect(!!(x), 0) -#else -# define LIKELY(x) (x) -# define UNLIKELY(x) (x) -#endif - -#if defined(__cplusplus) && ((__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1800)) -# define HAS_CPP11_FEATURES -#endif - -#if defined(__GNUC__) || defined(__clang__) -# if defined(HAS_CPP11_FEATURES) -/* Some magic to be sure we don't have reference in the type. */ -template<typename T> static inline T decltype_helper(T x) { return x; } -# define TYPEOF(x) decltype(decltype_helper(x)) -# else -# define TYPEOF(x) typeof(x) -# endif -#endif - -/* Causes warning: - * incompatible types when assigning to type 'Foo' from type 'Bar' - * ... the compiler optimizes away the temp var */ -#ifdef __GNUC__ -#define CHECK_TYPE(var, type) { \ - TYPEOF(var) *__tmp; \ - __tmp = (type *)NULL; \ - (void)__tmp; \ -} (void)0 - -#define CHECK_TYPE_PAIR(var_a, var_b) { \ - TYPEOF(var_a) *__tmp; \ - __tmp = (typeof(var_b) *)NULL; \ - (void)__tmp; \ -} (void)0 -#else -# define CHECK_TYPE(var, type) -# define CHECK_TYPE_PAIR(var_a, var_b) -#endif - -/* can be used in simple macros */ -#define CHECK_TYPE_INLINE(val, type) \ - ((void)(((type)0) != (val))) - - CCL_NAMESPACE_END -#ifndef __KERNEL_GPU__ -# include <cassert> -# define util_assert(statement) assert(statement) -#else -# define util_assert(statement) -#endif - /* Vectorized types declaration. */ #include "util/util_types_uchar2.h" #include "util/util_types_uchar3.h" @@ -298,5 +187,13 @@ CCL_NAMESPACE_END #include "util/util_types_vector3_impl.h" +/* SSE types. */ +#ifndef __KERNEL_GPU__ +# include "util/util_sseb.h" +# include "util/util_ssei.h" +# include "util/util_ssef.h" +# include "util/util_avxf.h" +#endif + #endif /* __UTIL_TYPES_H__ */ diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index e549a48d4b9..31e92c94eed 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -168,10 +168,6 @@ elseif(APPLE AND NOT WITH_X11) ) endif() - if(WITH_CODEC_QUICKTIME) - add_definitions(-DWITH_QUICKTIME) - endif() - elseif(WITH_X11) list(APPEND INC_SYS ${X11_X11_INCLUDE_PATH} diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp index f25f6637cb1..a6adba12152 100644 --- a/intern/ghost/intern/GHOST_EventPrinter.cpp +++ b/intern/ghost/intern/GHOST_EventPrinter.cpp @@ -193,16 +193,6 @@ void GHOST_EventPrinter::getKeyString(GHOST_TKey key, char str[32]) const } else if ((key >= GHOST_kKeyNumpad0) && (key <= GHOST_kKeyNumpad9)) { sprintf(str, "Numpad %d", (key - GHOST_kKeyNumpad0)); -#if defined(__sun__) || defined(__sun) - } - else if (key == 268828432) { /* solaris keyboards are messed up */ - /* This should really test XK_F11 but that doesn't work */ - strcpy(str, "F11"); - } - else if (key == 268828433) { /* solaris keyboards are messed up */ - /* This should really test XK_F12 but that doesn't work */ - strcpy(str, "F12"); -#endif } else if ((key >= GHOST_kKeyF1) && (key <= GHOST_kKeyF24)) { sprintf(str, "F%d", key - GHOST_kKeyF1 + 1); diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index b142c2f7194..6802ad42c7b 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -292,11 +292,6 @@ protected: /** Ignores window size messages (when window is dragged). */ bool m_ignoreWindowSizedMessages; - /** Stores the mouse cursor delta due to setting a new cursor position - * Needed because cocoa event delta cursor move takes setCursorPosition changes too. - */ - GHOST_TInt32 m_cursorDelta_x, m_cursorDelta_y; - /** Temporarily ignore momentum scroll events */ bool m_ignoreMomentumScroll; /** Is the scroll wheel event generated by a multitouch trackpad or mouse? */ diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 173f59c9c8f..42ccfb06fd9 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -366,8 +366,6 @@ GHOST_SystemCocoa::GHOST_SystemCocoa() char *rstring = NULL; m_modifierMask =0; - m_cursorDelta_x=0; - m_cursorDelta_y=0; m_outsideLoopEventProcessed = false; m_needDelayedApplicationBecomeActiveEventProcessing = false; m_displayManager = new GHOST_DisplayManagerCocoa (); @@ -644,6 +642,13 @@ GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(GHOST_TInt32 x, GHOST_T CGDisplayMoveCursorToPoint((CGDirectDisplayID)[[[windowScreen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue], CGPointMake(xf, yf)); + // See https://stackoverflow.com/a/17559012. By default, hardware events + // will be suppressed for 500ms after a synthetic mouse event. For unknown + // reasons CGEventSourceSetLocalEventsSuppressionInterval does not work, + // however calling CGAssociateMouseAndMouseCursorPosition also removes the + // delay, even if this is undocumented. + CGAssociateMouseAndMouseCursorPosition(true); + [pool drain]; return GHOST_kSuccess; } @@ -1249,27 +1254,6 @@ bool GHOST_SystemCocoa::handleTabletEvent(void *eventPtr) } } -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070 -enum { - NSEventPhaseNone = 0, - NSEventPhaseBegan = 0x1 << 0, - NSEventPhaseStationary = 0x1 << 1, - NSEventPhaseChanged = 0x1 << 2, - NSEventPhaseEnded = 0x1 << 3, - NSEventPhaseCancelled = 0x1 << 4, -}; -typedef NSUInteger NSEventPhase; - -@interface NSEvent (AvailableOn1070AndLater) -- (BOOL)hasPreciseScrollingDeltas; -- (CGFloat)scrollingDeltaX; -- (CGFloat)scrollingDeltaY; -- (NSEventPhase)momentumPhase; -- (BOOL)isDirectionInvertedFromDevice; -- (NSEventPhase)phase; -@end -#endif - GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) { NSEvent *event = (NSEvent *)eventPtr; @@ -1354,9 +1338,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) case GHOST_kGrabWrap: //Wrap cursor at area/window boundaries { NSPoint mousePos = [cocoawindow mouseLocationOutsideOfEventStream]; - GHOST_TInt32 x_mouse= mousePos.x; - GHOST_TInt32 y_mouse= mousePos.y; - GHOST_TInt32 x_accum, y_accum, x_cur, y_cur, x, y; + GHOST_TInt32 x_mouse = mousePos.x; + GHOST_TInt32 y_mouse = mousePos.y; GHOST_Rect bounds, windowBounds, correctedBounds; /* fallback to window bounds */ @@ -1370,29 +1353,26 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) correctedBounds.m_b = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_b; correctedBounds.m_t = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_t; - //Update accumulation counts + //Get accumulation from previous mouse warps + GHOST_TInt32 x_accum, y_accum; window->getCursorGrabAccum(x_accum, y_accum); - x_accum += [event deltaX]-m_cursorDelta_x; - y_accum += -[event deltaY]-m_cursorDelta_y; //Strange Apple implementation (inverted coordinates for the deltaY) ... - window->setCursorGrabAccum(x_accum, y_accum); //Warp mouse cursor if needed - x_mouse += [event deltaX]-m_cursorDelta_x; - y_mouse += -[event deltaY]-m_cursorDelta_y; - correctedBounds.wrapPoint(x_mouse, y_mouse, 2); - - //Compensate for mouse moved event taking cursor position set into account - m_cursorDelta_x = x_mouse-mousePos.x; - m_cursorDelta_y = y_mouse-mousePos.y; + GHOST_TInt32 warped_x_mouse = x_mouse; + GHOST_TInt32 warped_y_mouse = y_mouse; + correctedBounds.wrapPoint(warped_x_mouse, warped_y_mouse, 4); //Set new cursor position - window->clientToScreenIntern(x_mouse, y_mouse, x_cur, y_cur); - setMouseCursorPosition(x_cur, y_cur); /* wrap */ + if (x_mouse != warped_x_mouse || y_mouse != warped_y_mouse) { + GHOST_TInt32 warped_x, warped_y; + window->clientToScreenIntern(warped_x_mouse, warped_y_mouse, warped_x, warped_y); + setMouseCursorPosition(warped_x, warped_y); /* wrap */ + window->setCursorGrabAccum(x_accum + (x_mouse - warped_x_mouse), y_accum + (y_mouse - warped_y_mouse)); + } - //Post event - window->getCursorGrabInitPos(x_cur, y_cur); - window->screenToClientIntern(x_cur, y_cur, x_cur, y_cur); - window->clientToScreenIntern(x_cur + x_accum, y_cur + y_accum, x, y); + //Generate event + GHOST_TInt32 x, y; + window->clientToScreenIntern(x_mouse + x_accum, y_mouse + y_accum, x, y); pushEvent(new GHOST_EventCursor([event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y)); break; } @@ -1404,9 +1384,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) window->clientToScreenIntern(mousePos.x, mousePos.y, x, y); pushEvent(new GHOST_EventCursor([event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y)); - - m_cursorDelta_x=0; - m_cursorDelta_y=0; //Mouse motion occurred between two cursor warps, so we can reset the delta counter break; } } @@ -1461,7 +1438,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) double dx; double dy; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 /* with 10.7 nice scrolling deltas are supported */ dx = [event scrollingDeltaX]; dy = [event scrollingDeltaY]; @@ -1471,29 +1447,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) dx = [event deltaX]; dy = [event deltaY]; } -#else - /* trying to pretend you have nice scrolls... */ - dx = [event deltaX]; - dy = -[event deltaY]; - const double deltaMax = 50.0; - - if ((dx == 0) && (dy == 0)) break; - - /* Quadratic acceleration */ - dx = dx*(fabs(dx) + 0.5); - if (dx < 0.0) dx -= 0.5; - else dx += 0.5; - if (dx < -deltaMax) dx = -deltaMax; - else if (dx > deltaMax) dx = deltaMax; - - dy = dy*(fabs(dy) + 0.5); - if (dy < 0.0) dy -= 0.5; - else dy += 0.5; - if (dy < -deltaMax) dy= -deltaMax; - else if (dy > deltaMax) dy= deltaMax; - - dy = -dy; -#endif window->clientToScreenIntern(mousePos.x, mousePos.y, x, y); pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000, window, GHOST_kTrackpadEventScroll, x, y, dx, dy)); diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 30cfac08153..8fff565338f 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -1601,26 +1601,6 @@ convertXKey(KeySym key) } else if ((key >= XK_F1) && (key <= XK_F24)) { type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1)); -#if defined(__sun) || defined(__sun__) - /* This is a bit of a hack, but it looks like sun - * Used F11 and friends for its special keys Stop,again etc.. - * So this little patch enables F11 and F12 to work as expected - * following link has documentation on it: - * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408 - * also from /usr/include/X11/Sunkeysym.h - * #define SunXK_F36 0x1005FF10 // Labeled F11 - * #define SunXK_F37 0x1005FF11 // Labeled F12 - * - * mein@cs.umn.edu - */ - - } - else if (key == 268828432) { - type = GHOST_kKeyF11; - } - else if (key == 268828433) { - type = GHOST_kKeyF12; -#endif } else { switch (key) { @@ -1714,19 +1694,6 @@ convertXKey(KeySym key) GXMAP(type, XF86XK_AudioForward, GHOST_kKeyMediaLast); #endif #endif - - /* some extra sun cruft (NICE KEYBOARD!) */ -#ifdef __sun__ - GXMAP(type, 0xffde, GHOST_kKeyNumpad1); - GXMAP(type, 0xffe0, GHOST_kKeyNumpad3); - GXMAP(type, 0xffdc, GHOST_kKeyNumpad5); - GXMAP(type, 0xffd8, GHOST_kKeyNumpad7); - GXMAP(type, 0xffda, GHOST_kKeyNumpad9); - - GXMAP(type, 0xffd6, GHOST_kKeyNumpadSlash); - GXMAP(type, 0xffd7, GHOST_kKeyNumpadAsterisk); -#endif - default: type = GHOST_kKeyUnknown; break; diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index 5168c48ca2f..9dbc85d91e2 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -303,8 +303,6 @@ protected: GHOST_TabletData m_tablet; - bool m_lionStyleFullScreen; - bool m_immediateDraw; bool m_debug_context; // for debug messages during context setup }; diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 97615dcea96..20060ac1267 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -43,14 +43,6 @@ #include <sys/sysctl.h> -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070 -/* Lion style fullscreen support when building with the 10.6 SDK */ -enum { - NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7, - NSFullScreenWindowMask = 1 << 14 -}; -#endif - #pragma mark Cocoa window delegate object @interface CocoaWindowDelegate : NSObject @@ -511,14 +503,6 @@ enum { #pragma mark initialization / finalization -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070 -@interface NSView (NSOpenGLSurfaceResolution) -- (BOOL)wantsBestResolutionOpenGLSurface; -- (void)setWantsBestResolutionOpenGLSurface:(BOOL)flag; -- (NSRect)convertRectToBacking:(NSRect)bounds; -@end -#endif - GHOST_WindowCocoa::GHOST_WindowCocoa( GHOST_SystemCocoa *systemCocoa, const STR_String& title, @@ -537,7 +521,6 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( m_systemCocoa = systemCocoa; m_fullScreen = false; m_immediateDraw = false; - m_lionStyleFullScreen = false; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @@ -613,16 +596,6 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( if (state == GHOST_kWindowStateFullScreen) setState(GHOST_kWindowStateFullScreen); - // Starting with 10.9 (darwin 13.x.x), we can use Lion fullscreen, - // since it now has better multi-monitor support - // if the screens are spawned, additional screens get useless, - // so we only use lionStyleFullScreen when screens have separate spaces - - if ([NSScreen respondsToSelector:@selector(screensHaveSeparateSpaces)] && [NSScreen screensHaveSeparateSpaces]) { - // implies we are on >= OSX 10.9 - m_lionStyleFullScreen = true; - } - [pool drain]; } @@ -760,28 +733,18 @@ void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - if (!m_fullScreen) { - NSRect screenSize = [[m_window screen] visibleFrame]; + NSRect screenSize = [[m_window screen] visibleFrame]; - //Max window contents as screen size (excluding title bar...) - NSRect contentRect = [CocoaWindow contentRectForFrameRect:screenSize - styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)]; + //Max window contents as screen size (excluding title bar...) + NSRect contentRect = [CocoaWindow contentRectForFrameRect:screenSize + styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)]; - rect = [m_window contentRectForFrameRect:[m_window frame]]; - - bounds.m_b = contentRect.size.height - (rect.origin.y -contentRect.origin.y); - bounds.m_l = rect.origin.x -contentRect.origin.x; - bounds.m_r = rect.origin.x-contentRect.origin.x + rect.size.width; - bounds.m_t = contentRect.size.height - (rect.origin.y + rect.size.height -contentRect.origin.y); - } - else { - NSRect screenSize = [[m_window screen] frame]; - - bounds.m_b = screenSize.origin.y + screenSize.size.height; - bounds.m_l = screenSize.origin.x; - bounds.m_r = screenSize.origin.x + screenSize.size.width; - bounds.m_t = screenSize.origin.y; - } + rect = [m_window contentRectForFrameRect:[m_window frame]]; + + bounds.m_b = contentRect.size.height - (rect.origin.y -contentRect.origin.y); + bounds.m_l = rect.origin.x -contentRect.origin.x; + bounds.m_r = rect.origin.x-contentRect.origin.x + rect.size.width; + bounds.m_t = contentRect.size.height - (rect.origin.y + rect.size.height -contentRect.origin.y); [pool drain]; } @@ -856,9 +819,6 @@ GHOST_TWindowState GHOST_WindowCocoa::getState() const state = GHOST_kWindowStateNormal; } } - else if (m_fullScreen) { - state = GHOST_kWindowStateFullScreen; - } else if ([m_window isMiniaturized]) { state = GHOST_kWindowStateMinimized; } @@ -940,15 +900,12 @@ NSScreen* GHOST_WindowCocoa::getScreen() /* called for event, when window leaves monitor to another */ void GHOST_WindowCocoa::setNativePixelSize(void) { - /* make sure 10.6 keeps running */ - if ([m_openGLView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) { - NSRect backingBounds = [m_openGLView convertRectToBacking:[m_openGLView bounds]]; - - GHOST_Rect rect; - getClientBounds(rect); + NSRect backingBounds = [m_openGLView convertRectToBacking:[m_openGLView bounds]]; + + GHOST_Rect rect; + getClientBounds(rect); - m_nativePixelSize = (float)backingBounds.size.width / (float)rect.getWidth(); - } + m_nativePixelSize = (float)backingBounds.size.width / (float)rect.getWidth(); } /** @@ -973,35 +930,8 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state) { NSUInteger masks = [m_window styleMask]; - if (!m_fullScreen && !(masks & NSFullScreenWindowMask)) { - if (m_lionStyleFullScreen) { - [m_window toggleFullScreen:nil]; - break; - } - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - /* This status change needs to be done before Cocoa call to enter fullscreen mode - * to give window delegate hint not to forward its deactivation to ghost wm that - * doesn't know view/window difference. */ - m_fullScreen = true; - - /* Disable toggle for Lion style fullscreen */ - [m_window setCollectionBehavior:NSWindowCollectionBehaviorDefault]; - - //10.6 provides Cocoa functions to autoshow menu bar, and to change a window style - //Hide menu & dock if on primary screen. else only menu - if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]]) { - [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)]; - } - //Make window borderless and enlarge it - [m_window setStyleMask:NSBorderlessWindowMask]; - [m_window setFrame:[[m_window screen] frame] display:YES]; - [m_window makeFirstResponder:m_openGLView]; - - //Tell WM of view new size - m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this); - - [pool drain]; + if (!(masks & NSFullScreenWindowMask)) { + [m_window toggleFullScreen:nil]; } break; } @@ -1014,26 +944,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state) // Lion style fullscreen [m_window toggleFullScreen:nil]; } - else if (m_fullScreen) { - m_fullScreen = false; - - /* Enable toggle for into Lion style fullscreen */ - [m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - - //Exit fullscreen - //Show again menu & dock if needed - if ([[m_window screen] isEqual:[NSScreen mainScreen]]) { - [NSApp setPresentationOptions:NSApplicationPresentationDefault]; - } - //Make window normal and resize it - [m_window setStyleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)]; - [m_window setFrame:[[m_window screen] visibleFrame] display:YES]; - //TODO for 10.6 only : window title is forgotten after the style change - [m_window makeFirstResponder:m_openGLView]; - - //Tell WM of view new size - m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this); - } else if ([m_window isMiniaturized]) [m_window deminiaturize:nil]; else if ([m_window isZoomed]) @@ -1223,7 +1133,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setProgressBar(float progress) return GHOST_kSuccess; } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 static void postNotification() { NSUserNotification *notification = [[NSUserNotification alloc] init]; @@ -1233,7 +1142,6 @@ static void postNotification() [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification]; [notification release]; } -#endif GHOST_TSuccess GHOST_WindowCocoa::endProgressBar() { @@ -1248,15 +1156,13 @@ GHOST_TSuccess GHOST_WindowCocoa::endProgressBar() [dockIcon unlockFocus]; [NSApp setApplicationIconImage:dockIcon]; - - // With OSX 10.8 and later, we can use notifications to inform the user when the progress reached 100% - // Atm. just fire this when the progressbar ends, the behavior is controlled in the NotificationCenter - // If Blender is not frontmost window, a message pops up with sound, in any case an entry in notifications -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 + // We use notifications to inform the user when the progress reached 100% + // Atm. just fire this when the progressbar ends, the behavior is controlled + // in the NotificationCenter If Blender is not frontmost window, a message + // pops up with sound, in any case an entry in notifications if ([NSUserNotificationCenter respondsToSelector:@selector(defaultUserNotificationCenter)]) { postNotification(); } -#endif [dockIcon release]; @@ -1370,9 +1276,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode //Make window key if it wasn't to get the mouse move events [m_window makeKeyWindow]; - //Dissociate cursor position even for warp mode, to allow mouse acceleration to work even when warping the cursor - err = CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; - [pool drain]; } } @@ -1382,7 +1285,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode setWindowCursorVisibility(true); } - err = CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ setCursorGrabAccum(0, 0); m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; /* disable */ diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index fc46164c135..7ac54e5c915 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -890,19 +890,14 @@ void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam) if (fpWTPacket) { if (fpWTPacket((HCTX)lParam, wParam, &pkt)) { if (m_tabletData) { - switch (pkt.pkCursor) { - case 0: /* first device */ - case 3: /* second device */ + switch (pkt.pkCursor % 3) { /* % 3 for multiple devices ("DualTrack") */ + case 0: m_tabletData->Active = GHOST_kTabletModeNone; /* puck - not yet supported */ break; case 1: - case 4: - case 7: m_tabletData->Active = GHOST_kTabletModeStylus; /* stylus */ break; case 2: - case 5: - case 8: m_tabletData->Active = GHOST_kTabletModeEraser; /* eraser */ break; } diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 2019f58251f..9e019b233f6 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -59,10 +59,6 @@ //For DPI value #include <X11/Xresource.h> -#if defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__) || defined(_AIX) -# include <strings.h> -#endif - #include <cstring> #include <cstdio> diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h index 05a98c1a4e5..f6048a04cf3 100644 --- a/intern/guardedalloc/MEM_guardedalloc.h +++ b/intern/guardedalloc/MEM_guardedalloc.h @@ -225,7 +225,7 @@ public: \ MEM_freeN(mem); \ } \ -#if defined __GNUC__ || defined __sun +#if defined __GNUC__ # define OBJECT_GUARDED_NEW(type, args ...) \ new(MEM_mallocN(sizeof(type), __func__)) type(args) #else diff --git a/intern/guardedalloc/intern/mallocn_lockfree_impl.c b/intern/guardedalloc/intern/mallocn_lockfree_impl.c index b4838cdca18..66573b91ace 100644 --- a/intern/guardedalloc/intern/mallocn_lockfree_impl.c +++ b/intern/guardedalloc/intern/mallocn_lockfree_impl.c @@ -76,12 +76,7 @@ enum { MEM_INLINE void update_maximum(size_t *maximum_value, size_t value) { #ifdef USE_ATOMIC_MAX - size_t prev_value = *maximum_value; - while (prev_value < value) { - if (atomic_cas_z(maximum_value, prev_value, value) != prev_value) { - break; - } - } + atomic_fetch_and_update_max_z(maximum_value, value); #else *maximum_value = value > *maximum_value ? value : *maximum_value; #endif diff --git a/intern/itasc/kdl/tree.hpp b/intern/itasc/kdl/tree.hpp index c8a253fc901..bd35f82d185 100644 --- a/intern/itasc/kdl/tree.hpp +++ b/intern/itasc/kdl/tree.hpp @@ -34,7 +34,7 @@ namespace KDL //Forward declaration class TreeElement; // Eigen allocator is needed for alignment of Eigen data types - typedef std::map<std::string,TreeElement, std::less<std::string>, Eigen::aligned_allocator<std::pair<std::string, TreeElement> > > SegmentMap; + typedef std::map<std::string,TreeElement, std::less<std::string>, Eigen::aligned_allocator<std::pair<const std::string, TreeElement> > > SegmentMap; class TreeElement { diff --git a/intern/mikktspace/mikktspace.c b/intern/mikktspace/mikktspace.c index 0342ae0146f..f832b356ffe 100644 --- a/intern/mikktspace/mikktspace.c +++ b/intern/mikktspace/mikktspace.c @@ -39,17 +39,23 @@ #define INTERNAL_RND_SORT_SEED 39871946 +#ifdef _MSC_VER +# define MIKK_INLINE static __forceinline +#else +# define MIKK_INLINE static inline __attribute__((always_inline)) __attribute__((unused)) +#endif + // internal structure typedef struct { float x, y, z; } SVec3; -static tbool veq( const SVec3 v1, const SVec3 v2 ) +MIKK_INLINE tbool veq( const SVec3 v1, const SVec3 v2 ) { return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z); } -static SVec3 vadd( const SVec3 v1, const SVec3 v2 ) +MIKK_INLINE SVec3 vadd( const SVec3 v1, const SVec3 v2 ) { SVec3 vRes; @@ -61,7 +67,7 @@ static SVec3 vadd( const SVec3 v1, const SVec3 v2 ) } -static SVec3 vsub( const SVec3 v1, const SVec3 v2 ) +MIKK_INLINE SVec3 vsub( const SVec3 v1, const SVec3 v2 ) { SVec3 vRes; @@ -72,7 +78,7 @@ static SVec3 vsub( const SVec3 v1, const SVec3 v2 ) return vRes; } -static SVec3 vscale(const float fS, const SVec3 v) +MIKK_INLINE SVec3 vscale(const float fS, const SVec3 v) { SVec3 vRes; @@ -83,39 +89,54 @@ static SVec3 vscale(const float fS, const SVec3 v) return vRes; } -static float LengthSquared( const SVec3 v ) +MIKK_INLINE float LengthSquared( const SVec3 v ) { return v.x*v.x + v.y*v.y + v.z*v.z; } -static float Length( const SVec3 v ) +MIKK_INLINE float Length( const SVec3 v ) { return sqrtf(LengthSquared(v)); } -static SVec3 Normalize( const SVec3 v ) +#if 0 // UNUSED +MIKK_INLINE SVec3 Normalize( const SVec3 v ) +{ + return vscale(1.0f / Length(v), v); +} +#endif + +MIKK_INLINE SVec3 NormalizeSafe( const SVec3 v ) { - return vscale(1 / Length(v), v); + const float len = Length(v); + if (len != 0.0f) { + return vscale(1.0f / len, v); + } + else + { + return v; + } } -static float vdot( const SVec3 v1, const SVec3 v2) +MIKK_INLINE float vdot( const SVec3 v1, const SVec3 v2) { return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; } -static tbool NotZero(const float fX) +MIKK_INLINE tbool NotZero(const float fX) { // could possibly use FLT_EPSILON instead return fabsf(fX) > FLT_MIN; } -static tbool VNotZero(const SVec3 v) +#if 0 // UNUSED +MIKK_INLINE tbool VNotZero(const SVec3 v) { // might change this to an epsilon based test return NotZero(v.x) || NotZero(v.y) || NotZero(v.z); } - +#endif typedef struct { @@ -169,13 +190,13 @@ static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], con const int iNrActiveGroups, const int piTriListIn[], const float fThresCos, const SMikkTSpaceContext * pContext); -static int MakeIndex(const int iFace, const int iVert) +MIKK_INLINE int MakeIndex(const int iFace, const int iVert) { assert(iVert>=0 && iVert<4 && iFace>=0); return (iFace<<2) | (iVert&0x3); } -static void IndexToData(int * piFace, int * piVert, const int iIndexIn) +MIKK_INLINE void IndexToData(int * piFace, int * piVert, const int iIndexIn) { piVert[0] = iIndexIn&0x3; piFace[0] = iIndexIn>>2; @@ -202,8 +223,8 @@ static STSpace AvgTSpace(const STSpace * pTS0, const STSpace * pTS1) ts_res.fMagT = 0.5f*(pTS0->fMagT+pTS1->fMagT); ts_res.vOs = vadd(pTS0->vOs,pTS1->vOs); ts_res.vOt = vadd(pTS0->vOt,pTS1->vOt); - if ( VNotZero(ts_res.vOs) ) ts_res.vOs = Normalize(ts_res.vOs); - if ( VNotZero(ts_res.vOt) ) ts_res.vOt = Normalize(ts_res.vOt); + ts_res.vOs = NormalizeSafe(ts_res.vOs); + ts_res.vOt = NormalizeSafe(ts_res.vOt); } return ts_res; @@ -211,9 +232,9 @@ static STSpace AvgTSpace(const STSpace * pTS0, const STSpace * pTS1) -static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index); -static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index); -static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index); +MIKK_INLINE SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index); +MIKK_INLINE SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index); +MIKK_INLINE SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index); // degen triangles @@ -238,7 +259,7 @@ tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThre int iNrActiveGroups = 0, index = 0; const int iNrFaces = pContext->m_pInterface->m_getNumFaces(pContext); tbool bRes = TFALSE; - const float fThresCos = (float) cos((fAngularThreshold*(float)M_PI)/180.0f); + const float fThresCos = cosf((fAngularThreshold*(float)M_PI)/180.0f); // verify all call-backs have been set if ( pContext->m_pInterface->m_getNumFaces==NULL || @@ -258,7 +279,7 @@ tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThre if (iNrTrianglesIn<=0) return TFALSE; // allocate memory for an index list - piTriListIn = (int *) malloc(sizeof(int)*3*iNrTrianglesIn); + piTriListIn = (int *) malloc(sizeof(int[3])*iNrTrianglesIn); pTriInfos = (STriInfo *) malloc(sizeof(STriInfo)*iNrTrianglesIn); if (piTriListIn==NULL || pTriInfos==NULL) { @@ -311,7 +332,7 @@ tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThre // based on the 4 rules, identify groups based on connectivity iNrMaxGroups = iNrTrianglesIn*3; pGroups = (SGroup *) malloc(sizeof(SGroup)*iNrMaxGroups); - piGroupTrianglesBuffer = (int *) malloc(sizeof(int)*iNrTrianglesIn*3); + piGroupTrianglesBuffer = (int *) malloc(sizeof(int[3])*iNrTrianglesIn); if (pGroups==NULL || piGroupTrianglesBuffer==NULL) { if (pGroups!=NULL) free(pGroups); @@ -427,6 +448,7 @@ typedef struct { } STmpVert; static const int g_iCells = 2048; +static const float g_iCells_fl = 2048.0f; #ifdef _MSC_VER # define NOINLINE __declspec(noinline) @@ -439,7 +461,7 @@ static const int g_iCells = 2048; // results for the same effective input value fVal. static NOINLINE int FindGridCell(const float fMin, const float fMax, const float fVal) { - const float fIndex = g_iCells * ((fVal-fMin)/(fMax-fMin)); + const float fIndex = g_iCells_fl * ((fVal-fMin)/(fMax-fMin)); const int iIndex = (int)fIndex; return iIndex < g_iCells ? (iIndex >= 0 ? iIndex : 0) : (g_iCells - 1); } @@ -488,7 +510,7 @@ static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SM } // make allocations - piHashTable = (int *) malloc(sizeof(int)*iNrTrianglesIn*3); + piHashTable = (int *) malloc(sizeof(int[3])*iNrTrianglesIn); piHashCount = (int *) malloc(sizeof(int)*g_iCells); piHashOffsets = (int *) malloc(sizeof(int)*g_iCells); piHashCount2 = (int *) malloc(sizeof(int)*g_iCells); @@ -544,7 +566,7 @@ static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SM if (iMaxCount<piHashCount[k]) iMaxCount=piHashCount[k]; pTmpVert = (STmpVert *) malloc(sizeof(STmpVert)*iMaxCount); - + // complete the merge for (k=0; k<g_iCells; k++) @@ -880,7 +902,7 @@ static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_ return iTSpacesOffs; } -static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index) +MIKK_INLINE SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index) { int iF, iI; SVec3 res; float pos[3]; @@ -890,7 +912,7 @@ static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index) return res; } -static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index) +MIKK_INLINE SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index) { int iF, iI; SVec3 res; float norm[3]; @@ -900,7 +922,7 @@ static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index) return res; } -static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index) +MIKK_INLINE SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index) { int iF, iI; SVec3 res; float texc[2]; @@ -1048,7 +1070,7 @@ static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMi // match up edge pairs { - SEdge * pEdges = (SEdge *) malloc(sizeof(SEdge)*iNrTrianglesIn*3); + SEdge * pEdges = (SEdge *) malloc(sizeof(SEdge[3])*iNrTrianglesIn); if (pEdges==NULL) BuildNeighborsSlow(pTriInfos, piTriListIn, iNrTrianglesIn); else @@ -1064,7 +1086,7 @@ static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMi ///////////////////////////////////////////////////////////////////////////////////////////////////// static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], const int iMyTriIndex, SGroup * pGroup); -static void AddTriToGroup(SGroup * pGroup, const int iTriIndex); +MIKK_INLINE void AddTriToGroup(SGroup * pGroup, const int iTriIndex); static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn) { @@ -1130,7 +1152,7 @@ static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupT return iNrActiveGroups; } -static void AddTriToGroup(SGroup * pGroup, const int iTriIndex) +MIKK_INLINE void AddTriToGroup(SGroup * pGroup, const int iTriIndex) { pGroup->pFaceIndices[pGroup->iNrFaces] = iTriIndex; ++pGroup->iNrFaces; @@ -1247,10 +1269,8 @@ static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], con n = GetNormal(pContext, iVertIndex); // project - vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n)); - vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n)); - if ( VNotZero(vOs) ) vOs = Normalize(vOs); - if ( VNotZero(vOt) ) vOt = Normalize(vOt); + vOs = NormalizeSafe(vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n))); + vOt = NormalizeSafe(vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n))); // original face number iOF_1 = pTriInfos[f].iOrgFaceNumber; @@ -1262,10 +1282,8 @@ static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], con const int iOF_2 = pTriInfos[t].iOrgFaceNumber; // project - SVec3 vOs2 = vsub(pTriInfos[t].vOs, vscale(vdot(n,pTriInfos[t].vOs), n)); - SVec3 vOt2 = vsub(pTriInfos[t].vOt, vscale(vdot(n,pTriInfos[t].vOt), n)); - if ( VNotZero(vOs2) ) vOs2 = Normalize(vOs2); - if ( VNotZero(vOt2) ) vOt2 = Normalize(vOt2); + SVec3 vOs2 = NormalizeSafe(vsub(pTriInfos[t].vOs, vscale(vdot(n,pTriInfos[t].vOs), n))); + SVec3 vOt2 = NormalizeSafe(vsub(pTriInfos[t].vOt, vscale(vdot(n,pTriInfos[t].vOt), n))); { const tbool bAny = ( (pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY )!=0 ? TTRUE : TFALSE; @@ -1321,7 +1339,7 @@ static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], con } pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers; pUniSubGroups[iUniqueSubGroups].pTriMembers = pIndices; - memcpy(pIndices, tmp_group.pTriMembers, iMembers*sizeof(int)); + memcpy(pIndices, tmp_group.pTriMembers, sizeof(int)*iMembers); pSubGroupTspace[iUniqueSubGroups] = EvalTspace(tmp_group.pTriMembers, iMembers, piTriListIn, pTriInfos, pContext, pGroup->iVertexRepresentitive); ++iUniqueSubGroups; @@ -1392,10 +1410,8 @@ static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriL // project index = piTriListIn[3*f+i]; n = GetNormal(pContext, index); - vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n)); - vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n)); - if ( VNotZero(vOs) ) vOs = Normalize(vOs); - if ( VNotZero(vOt) ) vOt = Normalize(vOt); + vOs = NormalizeSafe(vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n))); + vOt = NormalizeSafe(vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n))); i2 = piTriListIn[3*f + (i<2?(i+1):0)]; i1 = piTriListIn[3*f + i]; @@ -1408,8 +1424,8 @@ static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriL v2 = vsub(p2,p1); // project - v1 = vsub(v1, vscale(vdot(n,v1),n)); if ( VNotZero(v1) ) v1 = Normalize(v1); - v2 = vsub(v2, vscale(vdot(n,v2),n)); if ( VNotZero(v2) ) v2 = Normalize(v2); + v1 = NormalizeSafe(vsub(v1, vscale(vdot(n,v1),n))); + v2 = NormalizeSafe(vsub(v2, vscale(vdot(n,v2),n))); // weight contribution by the angle // between the two edge vectors @@ -1427,8 +1443,8 @@ static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriL } // normalize - if ( VNotZero(res.vOs) ) res.vOs = Normalize(res.vOs); - if ( VNotZero(res.vOt) ) res.vOt = Normalize(res.vOt); + res.vOs = NormalizeSafe(res.vOs); + res.vOt = NormalizeSafe(res.vOt); if (fAngleSum>0) { res.fMagS /= fAngleSum; @@ -1464,7 +1480,7 @@ static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSee iL=iLeft; iR=iRight; n = (iR-iL)+1; assert(n>=0); - index = (int) (uSeed%n); + index = (int) (uSeed%(unsigned int)n); iMid=pSortBuffer[index + iL]; @@ -1661,6 +1677,20 @@ static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int } return; } + else if(iElems < 16) { + int i, j; + for (i = 0; i < iElems - 1; i++) { + for (j = 0; j < iElems - i - 1; j++) { + int index = iLeft + j; + if (pSortBuffer[index].array[channel] > pSortBuffer[index + 1].array[channel]) { + sTmp = pSortBuffer[index]; + pSortBuffer[index] = pSortBuffer[index + 1]; + pSortBuffer[index + 1] = sTmp; + } + } + } + return; + } // Random t=uSeed&31; @@ -1672,7 +1702,7 @@ static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int iR = iRight; n = (iR-iL)+1; assert(n>=0); - index = (int) (uSeed%n); + index = (int) (uSeed%(unsigned int)n); iMid=pSortBuffer[index + iL].array[channel]; @@ -1817,47 +1847,134 @@ static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int i assert(iNrTrianglesIn == t); } -static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris) +typedef struct VertReverseLookupContext { + tbool bIsInitialized; + int * pLookup; + int iMaxVertIndex; +} VertReverseLookupContext; + +static void GenerateReverseLookup( + const int piTriListIn[], + const int iNrTrianglesIn, + VertReverseLookupContext *pLookupCtx) +{ + int t; + // Figure out what size of lookup array we need. + pLookupCtx->iMaxVertIndex = -1; + for (t=0; t<3*iNrTrianglesIn; t++) + { + int iVertIndex = piTriListIn[t]; + if (iVertIndex > pLookupCtx->iMaxVertIndex) { + pLookupCtx->iMaxVertIndex = iVertIndex; + } + } + // Allocate memory. + if (pLookupCtx->iMaxVertIndex < 1) + { + // Nothing to allocate, all triangles are degenerate. + return; + } + pLookupCtx->pLookup = malloc(sizeof(int) * (pLookupCtx->iMaxVertIndex + 1)); + if (pLookupCtx->pLookup == NULL) + { + // Most likely run out of memory. + return; + } + // Fill in lookup. + for (t=0; t<=pLookupCtx->iMaxVertIndex; t++) { + pLookupCtx->pLookup[t] = -1; + } + for (t=0; t<3*iNrTrianglesIn; t++) + { + int iVertIndex = piTriListIn[t]; + if (pLookupCtx->pLookup[iVertIndex] != -1) + { + continue; + } + pLookupCtx->pLookup[iVertIndex] = t; + } +} + +static int LookupVertexIndexFromGoodTriangle( + VertReverseLookupContext *pLookupCtx, + int piTriListIn[], + const int iNrTrianglesIn, + const int iVertexIndex) +{ + // Allocate lookup on demand. + if (!pLookupCtx->bIsInitialized) + { + GenerateReverseLookup(piTriListIn, + iNrTrianglesIn, + pLookupCtx); + pLookupCtx->bIsInitialized = TTRUE; + } + // Make sure vertex index is in the mapping. + if (iVertexIndex > pLookupCtx->iMaxVertIndex) + { + return -1; + } + if (pLookupCtx->pLookup == NULL) { + return -1; + } + // Perform actual lookup. + return pLookupCtx->pLookup[iVertexIndex]; +} + +static void FreeReverseLookup(VertReverseLookupContext *pLookupCtx) +{ + if (!pLookupCtx->bIsInitialized) { + return; + } + if (pLookupCtx->pLookup != NULL) { + free(pLookupCtx->pLookup); + } +} + +static void DegenEpilogue(STSpace psTspace[], + STriInfo pTriInfos[], + int piTriListIn[], + const SMikkTSpaceContext * pContext, + const int iNrTrianglesIn, + const int iTotTris) { int t=0, i=0; + VertReverseLookupContext lookupCtx = { TFALSE }; // deal with degenerate triangles - // punishment for degenerate triangles is O(N^2) + // punishment for degenerate triangles is O(iNrTrianglesIn) extra memory. for (t=iNrTrianglesIn; t<iTotTris; t++) { // degenerate triangles on a quad with one good triangle are skipped // here but processed in the next loop const tbool bSkip = (pTriInfos[t].iFlag&QUAD_ONE_DEGEN_TRI)!=0 ? TTRUE : TFALSE; + if (bSkip) { + continue; + } - if (!bSkip) + for (i=0; i<3; i++) { - for (i=0; i<3; i++) + const int index1 = piTriListIn[t*3+i]; + int j = LookupVertexIndexFromGoodTriangle(&lookupCtx, + piTriListIn, + iNrTrianglesIn, + index1); + if (j < 0) { - const int index1 = piTriListIn[t*3+i]; - // search through the good triangles - tbool bNotFound = TTRUE; - int j=0; - while (bNotFound && j<(3*iNrTrianglesIn)) - { - const int index2 = piTriListIn[j]; - if (index1==index2) bNotFound=TFALSE; - else ++j; - } - - if (!bNotFound) - { - const int iTri = j/3; - const int iVert = j%3; - const int iSrcVert=pTriInfos[iTri].vert_num[iVert]; - const int iSrcOffs=pTriInfos[iTri].iTSpacesOffs; - const int iDstVert=pTriInfos[t].vert_num[i]; - const int iDstOffs=pTriInfos[t].iTSpacesOffs; - - // copy tspace - psTspace[iDstOffs+iDstVert] = psTspace[iSrcOffs+iSrcVert]; - } + // Matching vertex from good triangle is not found. + continue; } + + const int iTri = j/3; + const int iVert = j%3; + const int iSrcVert=pTriInfos[iTri].vert_num[iVert]; + const int iSrcOffs=pTriInfos[iTri].iTSpacesOffs; + const int iDstVert=pTriInfos[t].vert_num[i]; + const int iDstOffs=pTriInfos[t].iTSpacesOffs; + // copy tspace + psTspace[iDstOffs+iDstVert] = psTspace[iSrcOffs+iSrcVert]; } } + FreeReverseLookup(&lookupCtx); // deal with degenerate quads with one good triangle for (t=0; t<iNrTrianglesIn; t++) diff --git a/intern/openvdb/intern/openvdb_writer.cc b/intern/openvdb/intern/openvdb_writer.cc index 923752909d9..e886c5a76a8 100644 --- a/intern/openvdb/intern/openvdb_writer.cc +++ b/intern/openvdb/intern/openvdb_writer.cc @@ -45,7 +45,11 @@ void OpenVDBWriter::insert(const openvdb::GridBase::Ptr &grid) void OpenVDBWriter::insert(const openvdb::GridBase &grid) { +#if (OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER == 3) m_grids->push_back(grid.copyGrid()); +#else + m_grids->push_back(grid.copyGridWithNewTree()); +#endif } void OpenVDBWriter::insertFloatMeta(const openvdb::Name &name, const float value) diff --git a/intern/string/intern/STR_String.cpp b/intern/string/intern/STR_String.cpp index 4612c91b6a6..3ec65ddc725 100644 --- a/intern/string/intern/STR_String.cpp +++ b/intern/string/intern/STR_String.cpp @@ -37,9 +37,6 @@ #include <stdlib.h> #include <ctype.h> #include <string.h> -#if defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__) || defined(_AIX) -# include <strings.h> -#endif #include "STR_String.h" /*------------------------------------------------------------------------------------------------- @@ -5,6 +5,7 @@ setlocal EnableDelayedExpansion setlocal ENABLEEXTENSIONS set BLENDER_DIR=%~dp0 set BLENDER_DIR_NOSPACES=%BLENDER_DIR: =% +for %%X in (svn.exe) do (set HAS_SVN=%%~$PATH:X) if not "%BLENDER_DIR%"=="%BLENDER_DIR_NOSPACES%" ( echo There are spaces detected in the build path "%BLENDER_DIR%", this is currently not supported, exiting.... goto EOF @@ -17,6 +18,9 @@ set BUILD_CMAKE_ARGS= set BUILD_ARCH= set BUILD_VS_VER= set BUILD_VS_YEAR= +set BUILD_VS_LIBDIRPOST= +set BUILD_VS_LIBDIR= +set BUILD_VS_SVNDIR= set BUILD_NGE= set KEY_NAME= set MSBUILD_PLATFORM= @@ -67,25 +71,28 @@ if NOT "%1" == "" ( -C"%BLENDER_DIR%\build_files\cmake\config\bpy_module.cmake" ) else if "%1" == "release" ( set TARGET=Release - ) else if "%1" == "x86" ( + ) else if "%1" == "x86" ( set BUILD_ARCH=x86 - ) else if "%1" == "x64" ( + ) else if "%1" == "x64" ( set BUILD_ARCH=x64 - ) else if "%1" == "2017" ( + ) else if "%1" == "2017" ( set BUILD_VS_VER=15 set BUILD_VS_YEAR=2017 - ) else if "%1" == "2015" ( + set BUILD_VS_LIBDIRPOST=vc14 + ) else if "%1" == "2015" ( set BUILD_VS_VER=14 set BUILD_VS_YEAR=2015 - ) else if "%1" == "2013" ( + set BUILD_VS_LIBDIRPOST=vc14 + ) else if "%1" == "2013" ( set BUILD_VS_VER=12 set BUILD_VS_YEAR=2013 - ) else if "%1" == "packagename" ( + set BUILD_VS_LIBDIRPOST=vc12 + ) else if "%1" == "packagename" ( set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DCPACK_OVERRIDE_PACKAGENAME="%2" shift /1 - ) else if "%1" == "nobuild" ( + ) else if "%1" == "nobuild" ( set NOBUILD=1 - ) else if "%1" == "showhash" ( + ) else if "%1" == "showhash" ( for /f "delims=" %%i in ('git rev-parse HEAD') do echo Branch_hash=%%i cd release/datafiles/locale for /f "delims=" %%i in ('git rev-parse HEAD') do echo Locale_hash=%%i @@ -122,31 +129,32 @@ if "%BUILD_ARCH%"=="" ( set BUILD_ARCH=x86 ) ) else if "%BUILD_ARCH%"=="x64" ( - set WINDOWS_ARCH= Win64 - ) else if "%BUILD_ARCH%"=="x86" ( - set WINDOWS_ARCH= - ) + set WINDOWS_ARCH= Win64 +) else if "%BUILD_ARCH%"=="x86" ( + set WINDOWS_ARCH= +) if "%BUILD_VS_VER%"=="" ( set BUILD_VS_VER=12 set BUILD_VS_YEAR=2013 + set BUILD_VS_LIBDIRPOST=vc12 ) if "%BUILD_ARCH%"=="x64" ( set MSBUILD_PLATFORM=x64 - ) else if "%BUILD_ARCH%"=="x86" ( - set MSBUILD_PLATFORM=win32 +) else if "%BUILD_ARCH%"=="x86" ( + set MSBUILD_PLATFORM=win32 ) if "%target%"=="Release" ( - rem for vc12 check for both cuda 7.5 and 8 - if "%CUDA_PATH%"=="" ( - echo Cuda Not found, aborting! - goto EOF - ) - set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^ - -C"%BLENDER_DIR%\build_files\cmake\config\blender_release.cmake" + rem for vc12 check for both cuda 7.5 and 8 + if "%CUDA_PATH%"=="" ( + echo Cuda Not found, aborting! + goto EOF + ) + set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^ + -C"%BLENDER_DIR%\build_files\cmake\config\blender_release.cmake" ) :DetectMSVC @@ -183,8 +191,9 @@ if %ERRORLEVEL% NEQ 0 ( echo Visual Studio 2013 not found, trying Visual Studio 2015. set BUILD_VS_VER=14 set BUILD_VS_YEAR=2015 + set BUILD_VS_LIBDIRPOST=vc14 goto DetectMSVC - ) else ( + ) else ( echo Error: "MSBuild" command not in the PATH. echo You must have MSVC installed and run this from the "Developer Command Prompt" echo ^(available from Visual Studio's Start menu entry^), aborting! @@ -204,11 +213,36 @@ if %ERRORLEVEL% NEQ 0 ( echo You must have CMake installed and added to your PATH, aborting! goto EOF ) -if NOT EXIST %BLENDER_DIR%..\lib\nul ( - echo Error: Path to libraries not found "%BLENDER_DIR%..\lib\" + +if "%BUILD_ARCH%"=="x64" ( + set BUILD_VS_SVNDIR=win64_%BUILD_VS_LIBDIRPOST% +) else if "%BUILD_ARCH%"=="x86" ( + set BUILD_VS_SVNDIR=windows_%BUILD_VS_LIBDIRPOST% +) +set BUILD_VS_LIBDIR="%BLENDER_DIR%..\lib\%BUILD_VS_SVNDIR%" + +if NOT EXIST %BUILD_VS_LIBDIR% ( + rem libs not found, but svn is on the system + if not "%HAS_SVN%"=="" ( + echo. + echo The required external libraries in %BUILD_VS_LIBDIR% are missing + echo. + set /p GetLibs= "Would you like to download them? (y/n)" + if /I "!GetLibs!"=="Y" ( + echo. + echo Downloading %BUILD_VS_SVNDIR% libraries, please wait. + echo. + svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/%BUILD_VS_SVNDIR% %BUILD_VS_LIBDIR% + ) + ) +) + +if NOT EXIST %BUILD_VS_LIBDIR% ( + echo Error: Path to libraries not found "%BUILD_VS_LIBDIR%" echo This is needed for building, aborting! goto EOF ) + if "%TARGET%"=="" ( echo Error: Convenience target not set echo This is required for building, aborting! @@ -297,31 +331,32 @@ echo Blender successfully built, run from: "%BUILD_DIR%\bin\%BUILD_TYPE%\blender echo. goto EOF :HELP - echo. - echo Convenience targets - echo - release ^(identical to the official blender.org builds^) - echo - full ^(same as release minus the cuda kernels^) - echo - lite - echo - headless - echo - cycles - echo - bpy - echo. - echo Utilities ^(not associated with building^) - echo - clean ^(Target must be set^) - echo - update - echo - nobuild ^(only generate project files^) - echo - showhash ^(Show git hashes of source tree^) - echo. - echo Configuration options - echo - with_tests ^(enable building unit tests^) - echo - noge ^(disable building game enginge and player^) - echo - debug ^(Build an unoptimized debuggable build^) - echo - packagename [newname] ^(override default cpack package name^) - echo - buildir [newdir] ^(override default build folder^) - echo - x86 ^(override host auto-detect and build 32 bit code^) - echo - x64 ^(override host auto-detect and build 64 bit code^) - echo - 2013 ^(build with visual studio 2013^) - echo - 2015 ^(build with visual studio 2015^) [EXPERIMENTAL] - echo. + echo. + echo Convenience targets + echo - release ^(identical to the official blender.org builds^) + echo - full ^(same as release minus the cuda kernels^) + echo - lite + echo - headless + echo - cycles + echo - bpy + echo. + echo Utilities ^(not associated with building^) + echo - clean ^(Target must be set^) + echo - update + echo - nobuild ^(only generate project files^) + echo - showhash ^(Show git hashes of source tree^) + echo. + echo Configuration options + echo - with_tests ^(enable building unit tests^) + echo - noge ^(disable building game enginge and player^) + echo - debug ^(Build an unoptimized debuggable build^) + echo - packagename [newname] ^(override default cpack package name^) + echo - buildir [newdir] ^(override default build folder^) + echo - x86 ^(override host auto-detect and build 32 bit code^) + echo - x64 ^(override host auto-detect and build 64 bit code^) + echo - 2013 ^(build with visual studio 2013^) + echo - 2015 ^(build with visual studio 2015^) [EXPERIMENTAL] + echo - 2017 ^(build with visual studio 2017^) [EXPERIMENTAL] + echo. :EOF diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png Binary files differindex 60956db2576..1cd817a8e8c 100644 --- a/release/datafiles/splash.png +++ b/release/datafiles/splash.png diff --git a/release/datafiles/splash_2x.png b/release/datafiles/splash_2x.png Binary files differindex 3a5000c6bbc..2ba54b92cff 100644 --- a/release/datafiles/splash_2x.png +++ b/release/datafiles/splash_2x.png diff --git a/release/scripts/freestyle/styles/apriori_and_causal_density.py b/release/scripts/freestyle/styles/apriori_and_causal_density.py index 2ba768af835..42fc3370488 100644 --- a/release/scripts/freestyle/styles/apriori_and_causal_density.py +++ b/release/scripts/freestyle/styles/apriori_and_causal_density.py @@ -19,8 +19,8 @@ # Filename : apriori_and_causal_density.py # Author : Stephane Grabli # Date : 04/08/2005 -# Purpose : Selects the lines with high a priori density and -# subjects them to the causal density so as to avoid +# Purpose : Selects the lines with high a priori density and +# subjects them to the causal density so as to avoid # cluttering from freestyle.chainingiterators import ChainPredicateIterator diff --git a/release/scripts/freestyle/styles/cartoon.py b/release/scripts/freestyle/styles/cartoon.py index e630127db1a..87518bb832e 100644 --- a/release/scripts/freestyle/styles/cartoon.py +++ b/release/scripts/freestyle/styles/cartoon.py @@ -19,7 +19,7 @@ # Filename : cartoon.py # Author : Stephane Grabli # Date : 04/08/2005 -# Purpose : Draws colored lines. The color is automatically +# Purpose : Draws colored lines. The color is automatically # inferred from each object's material in a cartoon-like # fashion. diff --git a/release/scripts/freestyle/styles/external_contour_sketchy.py b/release/scripts/freestyle/styles/external_contour_sketchy.py index 44dbda4709f..6bccf23ac8d 100644 --- a/release/scripts/freestyle/styles/external_contour_sketchy.py +++ b/release/scripts/freestyle/styles/external_contour_sketchy.py @@ -19,8 +19,8 @@ # Filename : external_contour_sketchy.py # Author : Stephane Grabli # Date : 04/08/2005 -# Purpose : Draws the external contour of the scene using a sketchy -# chaining iterator (in particular each ViewEdge can be drawn +# Purpose : Draws the external contour of the scene using a sketchy +# chaining iterator (in particular each ViewEdge can be drawn # several times from freestyle.chainingiterators import pySketchyChainingIterator @@ -41,7 +41,7 @@ from freestyle.shaders import ( from freestyle.types import Operators -upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D()) +upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D()) Operators.select(upred) Operators.bidirectional_chain(pySketchyChainingIterator(), NotUP1D(upred)) shaders_list = [ diff --git a/release/scripts/freestyle/styles/haloing.py b/release/scripts/freestyle/styles/haloing.py index 6cd37779a42..34e4f65cf91 100644 --- a/release/scripts/freestyle/styles/haloing.py +++ b/release/scripts/freestyle/styles/haloing.py @@ -19,8 +19,8 @@ # Filename : haloing.py # Author : Stephane Grabli # Date : 04/08/2005 -# Purpose : This style module selects the lines that -# are connected (in the image) to a specific +# Purpose : This style module selects the lines that +# are connected (in the image) to a specific # object and trims them in order to produce # a haloing effect around the target shape @@ -42,14 +42,14 @@ from freestyle.shaders import ( from freestyle.types import Id, Operators -# id corresponds to the id of the target object +# id corresponds to the id of the target object # (accessed by SHIFT+click) id = Id(3,0) upred = AndUP1D(QuantitativeInvisibilityUP1D(0), pyIsOccludedByUP1D(id)) Operators.select(upred) Operators.bidirectional_chain(ChainSilhouetteIterator(), NotUP1D(upred)) shaders_list = [ - IncreasingThicknessShader(3, 5), + IncreasingThicknessShader(3, 5), IncreasingColorShader(1,0,0, 1,0,1,0,1), SamplingShader(1.0), pyTVertexRemoverShader(), diff --git a/release/scripts/freestyle/styles/invisible_lines.py b/release/scripts/freestyle/styles/invisible_lines.py index 461429b6437..5506f4ef11f 100644 --- a/release/scripts/freestyle/styles/invisible_lines.py +++ b/release/scripts/freestyle/styles/invisible_lines.py @@ -19,7 +19,7 @@ # Filename : invisible_lines.py # Author : Stephane Grabli # Date : 04/08/2005 -# Purpose : Draws all lines whose Quantitative Invisibility +# Purpose : Draws all lines whose Quantitative Invisibility # is different from 0 from freestyle.chainingiterators import ChainSilhouetteIterator diff --git a/release/scripts/freestyle/styles/long_anisotropically_dense.py b/release/scripts/freestyle/styles/long_anisotropically_dense.py index 50bec4f1a79..bfd5910cefe 100644 --- a/release/scripts/freestyle/styles/long_anisotropically_dense.py +++ b/release/scripts/freestyle/styles/long_anisotropically_dense.py @@ -19,13 +19,13 @@ # Filename : long_anisotropically_dense.py # Author : Stephane Grabli # Date : 04/08/2005 -# Purpose : Selects the lines that are long and have a high anisotropic -# a priori density and uses causal density +# Purpose : Selects the lines that are long and have a high anisotropic +# a priori density and uses causal density # to draw without cluttering. Ideally, half of the # selected lines are culled using the causal density. # # ********************* WARNING ************************************* -# ******** The Directional a priori density maps must ****** +# ******** The Directional a priori density maps must ****** # ******** have been computed prior to using this style module ****** from freestyle.chainingiterators import ChainSilhouetteIterator @@ -75,7 +75,7 @@ Operators.sort(pyLengthBP1D()) shaders_list = [ SamplingShader(2.0), ConstantThicknessShader(2), - ConstantColorShader(0.2,0.2,0.25,1), + ConstantColorShader(0.2,0.2,0.25,1), ] ## uniform culling Operators.create(pyDensityUP1D(3.0,2.0e-2, IntegrationType.MEAN, 0.1), shaders_list) diff --git a/release/scripts/freestyle/styles/multiple_parameterization.py b/release/scripts/freestyle/styles/multiple_parameterization.py index 0e224c74bbf..c03a61c9a81 100644 --- a/release/scripts/freestyle/styles/multiple_parameterization.py +++ b/release/scripts/freestyle/styles/multiple_parameterization.py @@ -19,7 +19,7 @@ # Filename : multiple_parameterization.py # Author : Stephane Grabli # Date : 04/08/2005 -# Purpose : The thickness and the color of the strokes vary continuously +# Purpose : The thickness and the color of the strokes vary continuously # independently from occlusions although only # visible lines are actually drawn. This is equivalent # to assigning the thickness using a parameterization covering diff --git a/release/scripts/freestyle/styles/nature.py b/release/scripts/freestyle/styles/nature.py index 74a42e6b2e5..1061f22017a 100644 --- a/release/scripts/freestyle/styles/nature.py +++ b/release/scripts/freestyle/styles/nature.py @@ -22,7 +22,7 @@ # Purpose : Uses the NatureUP1D predicate to select the lines # of a given type (among Nature.SILHOUETTE, Nature.CREASE, Nature.SUGGESTIVE_CONTOURS, # Nature.BORDERS). -# The suggestive contours must have been enabled in the +# The suggestive contours must have been enabled in the # options dialog to appear in the View Map. from freestyle.chainingiterators import ChainSilhouetteIterator diff --git a/release/scripts/freestyle/styles/near_lines.py b/release/scripts/freestyle/styles/near_lines.py index 5e260a22382..14c8d2f9e01 100644 --- a/release/scripts/freestyle/styles/near_lines.py +++ b/release/scripts/freestyle/styles/near_lines.py @@ -19,7 +19,7 @@ # Filename : near_lines.py # Author : Stephane Grabli # Date : 04/08/2005 -# Purpose : Draws the lines that are "closer" than a threshold +# Purpose : Draws the lines that are "closer" than a threshold # (between 0 and 1) from freestyle.chainingiterators import ChainSilhouetteIterator diff --git a/release/scripts/freestyle/styles/qi1.py b/release/scripts/freestyle/styles/qi1.py index d70e56d401a..4d87055eafb 100644 --- a/release/scripts/freestyle/styles/qi1.py +++ b/release/scripts/freestyle/styles/qi1.py @@ -20,7 +20,7 @@ # Author : Stephane Grabli # Date : 04/08/2005 # Purpose : Draws lines hidden by one surface. -# *** Quantitative Invisibility must have been +# *** Quantitative Invisibility must have been # enabled in the options dialog to use this style module **** from freestyle.chainingiterators import ChainSilhouetteIterator diff --git a/release/scripts/freestyle/styles/qi2.py b/release/scripts/freestyle/styles/qi2.py index 6ac933ecc05..937b5db590a 100644 --- a/release/scripts/freestyle/styles/qi2.py +++ b/release/scripts/freestyle/styles/qi2.py @@ -20,7 +20,7 @@ # Author : Stephane Grabli # Date : 04/08/2005 # Purpose : Draws lines hidden by two surfaces. -# *** Quantitative Invisibility must have been +# *** Quantitative Invisibility must have been # enabled in the options dialog to use this style module **** from freestyle.chainingiterators import ChainSilhouetteIterator diff --git a/release/scripts/freestyle/styles/sequentialsplit_sketchy.py b/release/scripts/freestyle/styles/sequentialsplit_sketchy.py index b980fdc87d7..5755fd3b845 100644 --- a/release/scripts/freestyle/styles/sequentialsplit_sketchy.py +++ b/release/scripts/freestyle/styles/sequentialsplit_sketchy.py @@ -21,7 +21,7 @@ # Date : 04/08/2005 # Purpose : Use the sequential split with two different # predicates to specify respectively the starting and -# the stopping extremities for strokes +# the stopping extremities for strokes from freestyle.chainingiterators import ChainSilhouetteIterator from freestyle.predicates import ( diff --git a/release/scripts/freestyle/styles/sketchy_multiple_parameterization.py b/release/scripts/freestyle/styles/sketchy_multiple_parameterization.py index a3ce6112165..8302ec8e4c3 100644 --- a/release/scripts/freestyle/styles/sketchy_multiple_parameterization.py +++ b/release/scripts/freestyle/styles/sketchy_multiple_parameterization.py @@ -19,7 +19,7 @@ # Filename : sketchy_multiple_parameterization.py # Author : Stephane Grabli # Date : 04/08/2005 -# Purpose : Builds sketchy strokes whose topology relies on a +# Purpose : Builds sketchy strokes whose topology relies on a # parameterization that covers the complete lines (visible+invisible) # whereas only the visible portions are actually drawn diff --git a/release/scripts/freestyle/styles/uniformpruning_zsort.py b/release/scripts/freestyle/styles/uniformpruning_zsort.py index 814e140ee49..64e808d9f8a 100644 --- a/release/scripts/freestyle/styles/uniformpruning_zsort.py +++ b/release/scripts/freestyle/styles/uniformpruning_zsort.py @@ -17,7 +17,7 @@ # ##### END GPL LICENSE BLOCK ##### # Filename : uniformpruning_zsort.py -# Authors : Fredo Durand, Stephane Grabli, Francois Sillion, Emmanuel Turquin +# Authors : Fredo Durand, Stephane Grabli, Francois Sillion, Emmanuel Turquin # Date : 08/04/2005 from freestyle.chainingiterators import ChainSilhouetteIterator diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py index 285e2ebe477..b33588c903b 100644 --- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py +++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py @@ -128,7 +128,7 @@ class SpellChecker: "multisampling", "multiscatter", "multitexture", - "multithreaded", + "multithreaded", "multiuser", "multiview", "namespace", diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py index 1d555ae7123..c3175f93f4e 100644 --- a/release/scripts/modules/bpy/utils/__init__.py +++ b/release/scripts/modules/bpy/utils/__init__.py @@ -37,6 +37,8 @@ __all__ = ( "register_module", "register_manual_map", "unregister_manual_map", + "register_classes_factory", + "register_submodule_factory", "make_rna_paths", "manual_map", "previews", @@ -71,6 +73,7 @@ import addon_utils as _addon_utils _user_preferences = _bpy.context.user_preferences _script_module_dirs = "startup", "modules" +_is_factory_startup = _bpy.app.factory_startup def _test_import(module_name, loaded_modules): @@ -144,6 +147,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): :type refresh_scripts: bool """ use_time = use_class_register_check = _bpy.app.debug_python + use_user = not _is_factory_startup if use_time: import time @@ -234,7 +238,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): from bpy_restrict_state import RestrictBlend with RestrictBlend(): - for base_path in script_paths(): + for base_path in script_paths(use_user=use_user): for path_subdir in _script_module_dirs: path = _os.path.join(base_path, path_subdir) if _os.path.isdir(path): @@ -306,7 +310,7 @@ def script_path_pref(): return _os.path.normpath(path) if path else None -def script_paths(subdir=None, user_pref=True, check_all=False): +def script_paths(subdir=None, user_pref=True, check_all=False, use_user=True): """ Returns a list of valid script paths. @@ -328,15 +332,30 @@ def script_paths(subdir=None, user_pref=True, check_all=False): # so the 'BLENDER_SYSTEM_SCRIPTS' environment variable will be used. base_paths = _bpy_script_paths() + # Defined to be (system, user) so we can skip the second if needed. + if not use_user: + base_paths = base_paths[:1] + if check_all: # All possible paths, no duplicates, keep order. + if use_user: + test_paths = ('LOCAL', 'USER', 'SYSTEM') + else: + test_paths = ('LOCAL', 'SYSTEM') + base_paths = ( - *(path for path in (_os.path.join(resource_path(res), "scripts") - for res in ('LOCAL', 'USER', 'SYSTEM')) if path not in base_paths), + *(path for path in ( + _os.path.join(resource_path(res), "scripts") + for res in test_paths) if path not in base_paths), *base_paths, - ) + ) - for path in (*base_paths, script_path_user(), script_path_pref()): + if use_user: + test_paths = (*base_paths, script_path_user(), script_path_pref()) + else: + test_paths = (*base_paths, script_path_pref()) + + for path in test_paths: if path: path = _os.path.normpath(path) if path not in scripts and _os.path.isdir(path): @@ -381,27 +400,26 @@ def app_template_paths(subdir=None): :return: app template paths. :rtype: generator """ + # Note: keep in sync with: Blender's BKE_appdir_app_template_any - # note: LOCAL, USER, SYSTEM order matches script resolution order. subdir_tuple = (subdir,) if subdir is not None else () - path = _os.path.join(*( - resource_path('LOCAL'), "scripts", "startup", - "bl_app_templates_user", *subdir_tuple)) - if _os.path.isdir(path): - yield path - else: - path = _os.path.join(*( - resource_path('USER'), "scripts", "startup", - "bl_app_templates_user", *subdir_tuple)) - if _os.path.isdir(path): - yield path - - path = _os.path.join(*( - resource_path('SYSTEM'), "scripts", "startup", - "bl_app_templates_system", *subdir_tuple)) - if _os.path.isdir(path): - yield path + # Avoid adding 'bl_app_templates_system' twice. + # Either we have a portable build or an installed system build. + for resource_type, module_name in ( + ('USER', "bl_app_templates_user"), + ('LOCAL', "bl_app_templates_system"), + ('SYSTEM', "bl_app_templates_system"), + ): + path = resource_path(resource_type) + if path: + path = _os.path.join( + *(path, "scripts", "startup", module_name, *subdir_tuple)) + if _os.path.isdir(path): + yield path + # Only load LOCAL or SYSTEM (never both). + if resource_type == 'LOCAL': + break def preset_paths(subdir): @@ -684,6 +702,65 @@ def unregister_module(module, verbose=False): print("done.\n") +def register_classes_factory(classes): + """ + Utility function to create register and unregister functions + which simply registers and unregisters a sequence of classes. + """ + def register(): + from bpy.utils import register_class + for cls in classes: + register_class(cls) + + def unregister(): + from bpy.utils import unregister_class + for cls in reversed(classes): + unregister_class(cls) + + return register, unregister + + +def register_submodule_factory(module_name, submodule_names): + """ + Utility function to create register and unregister functions + which simply load submodules, + calling their register & unregister functions. + + .. note:: + + Modules are registered in the order given, + unregistered in reverse order. + + :arg module_name: The module name, typically ``__name__``. + :type module_name: string + :arg submodule_names: List of submodule names to load and unload. + :type submodule_names: list of strings + :return: register and unregister functions. + :rtype: tuple pair of functions + """ + + module = None + submodules = [] + + def register(): + nonlocal module + module = __import__(name=module_name, fromlist=submodule_names) + submodules[:] = [getattr(module, name) for name in submodule_names] + for mod in submodules: + mod.register() + + def unregister(): + from sys import modules + for mod in reversed(submodules): + mod.unregister() + name = mod.__name__ + delattr(module, name.partition(".")[2]) + del modules[name] + submodules.clear() + + return register, unregister + + # ----------------------------------------------------------------------------- # Manual lookups, each function has to return a basepath and a sequence # of... diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py index 5e21260e5e4..ea0bd77c0f0 100644 --- a/release/scripts/modules/bpy_extras/anim_utils.py +++ b/release/scripts/modules/bpy_extras/anim_utils.py @@ -20,35 +20,118 @@ __all__ = ( "bake_action", - ) + "bake_action_objects", + + "bake_action_iter", + "bake_action_objects_iter", +) import bpy -# XXX visual keying is actually always considered as True in this code... -def bake_action(frame_start, - frame_end, - frame_step=1, - only_selected=False, - do_pose=True, - do_object=True, - do_visual_keying=True, - do_constraint_clear=False, - do_parents_clear=False, - do_clean=False, - action=None, - ): +def bake_action( + obj, + *, + action, frames, + **kwargs +): + """ + :arg obj: Object to bake. + :type obj: :class:`bpy.types.Object` + :arg action: An action to bake the data into, or None for a new action + to be created. + :type action: :class:`bpy.types.Action` or None + :arg frames: Frames to bake. + :type frames: iterable of int + :return: an action or None + :rtype: :class:`bpy.types.Action` """ - Return an image from the file path with options to search multiple paths - and return a placeholder if its not found. - - :arg frame_start: First frame to bake. - :type frame_start: int - :arg frame_end: Last frame to bake. - :type frame_end: int - :arg frame_step: Frame step. - :type frame_step: int + if not (do_pose or do_object): + return None + + action, = bake_action_objects( + [(obj, action)], + frames, + **kwargs, + ) + return action + + +def bake_action_objects( + object_action_pairs, + *, + frames, + **kwargs +): + """ + A version of :func:`bake_action_objects_iter` that takes frames and returns the output. + + :arg frames: Frames to bake. + :type frames: iterable of int + + :return: A sequence of Action or None types (aligned with `object_action_pairs`) + :rtype: sequence of :class:`bpy.types.Action` + """ + iter = bake_action_objects_iter(object_action_pairs, **kwargs) + iter.send(None) + for frame in frames: + iter.send(frame) + return iter.send(None) + + +def bake_action_objects_iter( + object_action_pairs, + **kwargs +): + """ + An coroutine that bakes actions for multiple objects. + + :arg object_action_pairs: Sequence of object action tuples, + action is the destination for the baked data. When None a new action will be created. + :type object_action_pairs: Sequence of (:class:`bpy.types.Object`, :class:`bpy.types.Action`) + """ + scene = bpy.context.scene + frame_back = scene.frame_current + iter_all = tuple( + bake_action_iter(obj, action=action, **kwargs) + for (obj, action) in object_action_pairs + ) + for iter in iter_all: + iter.send(None) + while True: + frame = yield None + if frame is None: + break + scene.frame_set(frame) + scene.update() + for iter in iter_all: + iter.send(frame) + scene.frame_set(frame_back) + yield tuple(iter.send(None) for iter in iter_all) + + +# XXX visual keying is actually always considered as True in this code... +def bake_action_iter( + obj, + *, + action, + only_selected=False, + do_pose=True, + do_object=True, + do_visual_keying=True, + do_constraint_clear=False, + do_parents_clear=False, + do_clean=False +): + """ + An coroutine that bakes action for a single object. + + :arg obj: Object to bake. + :type obj: :class:`bpy.types.Object` + :arg action: An action to bake the data into, or None for a new action + to be created. + :type action: :class:`bpy.types.Action` or None :arg only_selected: Only bake selected bones. :type only_selected: bool :arg do_pose: Bake pose channels. @@ -63,14 +146,10 @@ def bake_action(frame_start, :type do_parents_clear: bool :arg do_clean: Remove redundant keyframes after baking. :type do_clean: bool - :arg action: An action to bake the data into, or None for a new action - to be created. - :type action: :class:`bpy.types.Action` or None :return: an action or None :rtype: :class:`bpy.types.Action` """ - # ------------------------------------------------------------------------- # Helper Functions and vars @@ -112,34 +191,32 @@ def bake_action(frame_start, # ------------------------------------------------------------------------- # Setup the Context - # TODO, pass data rather then grabbing from the context! - scene = bpy.context.scene - obj = bpy.context.object - frame_back = scene.frame_current - if obj.pose is None: do_pose = False if not (do_pose or do_object): - return None + raise Exception("Pose and object baking is disabled, no action needed") pose_info = [] obj_info = [] options = {'INSERTKEY_NEEDED'} - frame_range = range(frame_start, frame_end + 1, frame_step) - # ------------------------------------------------------------------------- # Collect transformations - for f in frame_range: - scene.frame_set(f) - scene.update() + while True: + # Caller is responsible for setting the frame and updating the scene. + frame = yield None + + # Signal we're done! + if frame is None: + break + if do_pose: - pose_info.append(pose_frame_info(obj)) + pose_info.append((frame, pose_frame_info(obj))) if do_object: - obj_info.append(obj_frame_info(obj)) + obj_info.append((frame, obj_frame_info(obj))) # ------------------------------------------------------------------------- # Clean (store initial data) @@ -178,7 +255,7 @@ def bake_action(frame_start, # create compatible eulers euler_prev = None - for (f, matrix) in zip(frame_range, pose_info): + for (f, matrix) in pose_info: pbone.matrix_basis = matrix[name].copy() pbone.keyframe_insert("location", -1, f, name, options) @@ -210,7 +287,7 @@ def bake_action(frame_start, # create compatible eulers euler_prev = None - for (f, matrix) in zip(frame_range, obj_info): + for (f, matrix) in obj_info: name = "Action Bake" # XXX: placeholder obj.matrix_basis = matrix @@ -261,6 +338,4 @@ def bake_action(frame_start, else: i += 1 - scene.frame_set(frame_back) - - return action + yield action diff --git a/release/scripts/modules/keyingsets_utils.py b/release/scripts/modules/keyingsets_utils.py index 8cef64c3590..7ce5f3e029b 100644 --- a/release/scripts/modules/keyingsets_utils.py +++ b/release/scripts/modules/keyingsets_utils.py @@ -232,7 +232,7 @@ bbone_property_ids = ( "bbone_scalein", "bbone_scaleout", - # NOTE: These are in the nested bone struct + # NOTE: These are in the nested bone struct # Do it this way to force them to be included # in whatever actions are being keyed here "bone.bbone_in", diff --git a/release/scripts/modules/nodeitems_utils.py b/release/scripts/modules/nodeitems_utils.py index 904062c36cd..117e35dd028 100644 --- a/release/scripts/modules/nodeitems_utils.py +++ b/release/scripts/modules/nodeitems_utils.py @@ -59,7 +59,11 @@ class NodeItem: return self._label else: # if no custom label is defined, fall back to the node type UI name - return getattr(bpy.types, self.nodetype).bl_rna.name + bl_rna = bpy.types.Node.bl_rna_get_subclass(self.nodetype) + if bl_rna is not None: + return bl_rna.name + else: + return "Unknown" @property def translation_context(self): @@ -67,7 +71,11 @@ class NodeItem: return bpy.app.translations.contexts.default else: # if no custom label is defined, fall back to the node type UI name - return getattr(bpy.types, self.nodetype).bl_rna.translation_context + bl_rna = bpy.types.Node.bl_rna_get_subclass(self.nodetype) + if bl_rna is not None: + return bl_rna.translation_context + else: + return bpy.app.translations.contexts.default # NB: is a staticmethod because called with an explicit self argument # NodeItemCustom sets this as a variable attribute in __init__ diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py index 94f5e9e17bb..1a3d0698871 100644 --- a/release/scripts/modules/rna_info.py +++ b/release/scripts/modules/rna_info.py @@ -82,6 +82,32 @@ def float_as_string(f): return val_str +def get_py_class_from_rna(rna_type): + """ Get's the Python type for a class which isn't necessarily added to ``bpy.types``. + """ + identifier = rna_type.identifier + py_class = getattr(bpy.types, identifier, None) + if py_class is not None: + return py_class + + def subclasses_recurse(cls): + for c in cls.__subclasses__(): + # is_registered + if "bl_rna" in cls.__dict__: + yield c + yield from subclasses_recurse(c) + + while py_class is None: + base = rna_type.base + if base is None: + raise Exception("can't find type") + py_class_base = getattr(bpy.types, base.identifier, None) + if py_class_base is not None: + for cls in subclasses_recurse(py_class_base): + if cls.bl_rna.identifier == identifier: + return cls + + class InfoStructRNA: __slots__ = ( "bl_rna", @@ -146,7 +172,8 @@ class InfoStructRNA: def _get_py_visible_attrs(self): attrs = [] - py_class = getattr(bpy.types, self.identifier) + py_class = get_py_class_from_rna(self.bl_rna) + for attr_str in dir(py_class): if attr_str.startswith("_"): continue @@ -210,6 +237,7 @@ class InfoPropertyRNA: "min", "max", "array_length", + "array_dimensions", "collection_type", "type", "fixed_type", @@ -235,6 +263,7 @@ class InfoPropertyRNA: self.min = getattr(rna_prop, "hard_min", -1) self.max = getattr(rna_prop, "hard_max", -1) self.array_length = getattr(rna_prop, "array_length", 0) + self.array_dimensions = getattr(rna_prop, "array_dimensions", ())[:] self.collection_type = GetInfoStructRNA(rna_prop.srna) self.is_required = rna_prop.is_required self.is_readonly = rna_prop.is_readonly @@ -254,13 +283,21 @@ class InfoPropertyRNA: else: self.is_enum_flag = False + self.default_str = "" # fallback + if self.array_length: self.default = tuple(getattr(rna_prop, "default_array", ())) + if self.array_dimensions[1] != 0: # Multi-dimensional array, convert default flat one accordingly. + self.default_str = tuple(float_as_string(v) if self.type == "float" else str(v) for v in self.default) + for dim in self.array_dimensions[::-1]: + if dim != 0: + self.default = tuple(zip(*((iter(self.default),) * dim))) + self.default_str = tuple("(%s)" % ", ".join(s for s in b) for b in zip(*((iter(self.default_str),) * dim))) + self.default_str = self.default_str[0] elif self.type == "enum" and self.is_enum_flag: self.default = getattr(rna_prop, "default_flag", set()) else: self.default = getattr(rna_prop, "default", None) - self.default_str = "" # fallback if self.type == "pointer": # pointer has no default, just set as None @@ -275,13 +312,12 @@ class InfoPropertyRNA: else: self.default_str = "'%s'" % self.default elif self.array_length: - self.default_str = '' - # special case for floats - if len(self.default) > 0: - if self.type == "float": + if self.array_dimensions[1] == 0: # single dimension array, we already took care of multi-dimensions ones. + # special case for floats + if self.type == "float" and len(self.default) > 0: self.default_str = "(%s)" % ", ".join(float_as_string(f) for f in self.default) - if not self.default_str: - self.default_str = str(self.default) + else: + self.default_str = str(self.default) else: if self.type == "float": self.default_str = float_as_string(self.default) @@ -301,7 +337,10 @@ class InfoPropertyRNA: if self.fixed_type is None: type_str += self.type if self.array_length: - type_str += " array of %d items" % (self.array_length) + if self.array_dimensions[1] != 0: + type_str += " multi-dimensional array of %s items" % (" * ".join(str(d) for d in self.array_dimensions if d != 0)) + else: + type_str += " array of %d items" % (self.array_length) if self.type in {"float", "int"}: type_str += " in [%s, %s]" % (range_str(self.min), range_str(self.max)) @@ -437,7 +476,11 @@ class InfoOperatorRNA: self.args.append(prop) def get_location(self): - op_class = getattr(bpy.types, self.identifier) + try: + op_class = getattr(bpy.types, self.identifier) + except AttributeError: + # defined in C. + return None, None op_func = getattr(op_class, "execute", None) if op_func is None: op_func = getattr(op_class, "invoke", None) @@ -601,7 +644,7 @@ def BuildRNAInfo(): for rna_prop_ptr in (getattr(rna_prop, "fixed_type", None), getattr(rna_prop, "srna", None)): # Does this property point to me? - if rna_prop_ptr: + if rna_prop_ptr and rna_prop_ptr.identifier in rna_references_dict: rna_references_dict[rna_prop_ptr.identifier].append( "%s.%s" % (rna_struct_path, rna_prop_identifier)) @@ -614,7 +657,7 @@ def BuildRNAInfo(): rna_prop_ptr = getattr(rna_prop, "fixed_type", None) # Does this property point to me? - if rna_prop_ptr: + if rna_prop_ptr and rna_prop_ptr.identifier in rna_references_dict: rna_references_dict[rna_prop_ptr.identifier].append( "%s.%s" % (rna_struct_path, rna_func.identifier)) @@ -649,16 +692,22 @@ def BuildRNAInfo(): for rna_info_prop in InfoFunctionRNA.global_lookup.values(): rna_info_prop.build() - for rna_info in InfoStructRNA.global_lookup.values(): - rna_info.build() - for prop in rna_info.properties: - prop.build() - for func in rna_info.functions: - func.build() - for prop in func.args: - prop.build() - for prop in func.return_values: + done_keys = set() + new_keys = set(InfoStructRNA.global_lookup.keys()) + while new_keys: + for rna_key in new_keys: + rna_info = InfoStructRNA.global_lookup[rna_key] + rna_info.build() + for prop in rna_info.properties: prop.build() + for func in rna_info.functions: + func.build() + for prop in func.args: + prop.build() + for prop in func.return_values: + prop.build() + done_keys |= new_keys + new_keys = set(InfoStructRNA.global_lookup.keys()) - done_keys # there are too many invalid defaults, unless we intend to fix, leave this off if 0: diff --git a/release/scripts/modules/rna_keymap_ui.py b/release/scripts/modules/rna_keymap_ui.py index a1a4e5b8763..aa1aa4925a3 100644 --- a/release/scripts/modules/rna_keymap_ui.py +++ b/release/scripts/modules/rna_keymap_ui.py @@ -230,6 +230,7 @@ def draw_filtered(display_keymaps, filter_type, filter_text, layout): "`": 'ACCENT_GRAVE', "*": 'NUMPAD_ASTERIX', "/": 'NUMPAD_SLASH', + '+': 'NUMPAD_PLUS', "RMB": 'RIGHTMOUSE', "LMB": 'LEFTMOUSE', "MMB": 'MIDDLEMOUSE', diff --git a/release/scripts/presets/cycles/integrator/direct_light.py b/release/scripts/presets/cycles/integrator/direct_light.py index 12b332cb431..701aa10d556 100644 --- a/release/scripts/presets/cycles/integrator/direct_light.py +++ b/release/scripts/presets/cycles/integrator/direct_light.py @@ -2,12 +2,10 @@ import bpy cycles = bpy.context.scene.cycles cycles.max_bounces = 8 -cycles.min_bounces = 8 cycles.caustics_reflective = False cycles.caustics_refractive = False cycles.diffuse_bounces = 0 cycles.glossy_bounces = 1 cycles.transmission_bounces = 2 cycles.volume_bounces = 0 -cycles.transparent_min_bounces = 8 cycles.transparent_max_bounces = 8 diff --git a/release/scripts/presets/cycles/integrator/full_global_illumination.py b/release/scripts/presets/cycles/integrator/full_global_illumination.py index 69fa6e735bd..a03c6c8bd64 100644 --- a/release/scripts/presets/cycles/integrator/full_global_illumination.py +++ b/release/scripts/presets/cycles/integrator/full_global_illumination.py @@ -2,12 +2,10 @@ import bpy cycles = bpy.context.scene.cycles cycles.max_bounces = 128 -cycles.min_bounces = 3 cycles.caustics_reflective = True cycles.caustics_refractive = True cycles.diffuse_bounces = 128 cycles.glossy_bounces = 128 cycles.transmission_bounces = 128 cycles.volume_bounces = 128 -cycles.transparent_min_bounces = 8 cycles.transparent_max_bounces = 128 diff --git a/release/scripts/presets/cycles/integrator/limited_global_illumination.py b/release/scripts/presets/cycles/integrator/limited_global_illumination.py index 22a8478d23b..d37bf46c705 100644 --- a/release/scripts/presets/cycles/integrator/limited_global_illumination.py +++ b/release/scripts/presets/cycles/integrator/limited_global_illumination.py @@ -2,12 +2,10 @@ import bpy cycles = bpy.context.scene.cycles cycles.max_bounces = 8 -cycles.min_bounces = 3 cycles.caustics_reflective = False cycles.caustics_refractive = False cycles.diffuse_bounces = 1 cycles.glossy_bounces = 4 cycles.transmission_bounces = 8 cycles.volume_bounces = 2 -cycles.transparent_min_bounces = 8 cycles.transparent_max_bounces = 8 diff --git a/release/scripts/presets/cycles/sampling/final.py b/release/scripts/presets/cycles/sampling/final.py index d03423b6c2e..f1222d927c1 100644 --- a/release/scripts/presets/cycles/sampling/final.py +++ b/release/scripts/presets/cycles/sampling/final.py @@ -1,20 +1,18 @@ import bpy cycles = bpy.context.scene.cycles -cycles.use_square_samples = True - # Path Trace -cycles.samples = 24 -cycles.preview_samples = 12 +cycles.samples = 512 +cycles.preview_samples = 128 # Branched Path Trace -cycles.aa_samples = 8 -cycles.preview_aa_samples = 4 +cycles.aa_samples = 128 +cycles.preview_aa_samples = 32 -cycles.diffuse_samples = 3 -cycles.glossy_samples = 2 -cycles.transmission_samples = 2 +cycles.diffuse_samples = 4 +cycles.glossy_samples = 4 +cycles.transmission_samples = 4 cycles.ao_samples = 1 -cycles.mesh_light_samples = 2 -cycles.subsurface_samples = 2 -cycles.volume_samples = 2 +cycles.mesh_light_samples = 4 +cycles.subsurface_samples = 4 +cycles.volume_samples = 4 diff --git a/release/scripts/presets/cycles/sampling/preview.py b/release/scripts/presets/cycles/sampling/preview.py index 5f071c7474d..c16449e2c8f 100644 --- a/release/scripts/presets/cycles/sampling/preview.py +++ b/release/scripts/presets/cycles/sampling/preview.py @@ -1,20 +1,18 @@ import bpy cycles = bpy.context.scene.cycles -cycles.use_square_samples = True - # Path Trace -cycles.samples = 12 -cycles.preview_samples = 6 +cycles.samples = 128 +cycles.preview_samples = 32 # Branched Path Trace -cycles.aa_samples = 4 -cycles.preview_aa_samples = 2 +cycles.aa_samples = 32 +cycles.preview_aa_samples = 4 -cycles.diffuse_samples = 3 -cycles.glossy_samples = 2 -cycles.transmission_samples = 2 +cycles.diffuse_samples = 4 +cycles.glossy_samples = 4 +cycles.transmission_samples = 4 cycles.ao_samples = 1 -cycles.mesh_light_samples = 2 -cycles.subsurface_samples = 2 -cycles.volume_samples = 2 +cycles.mesh_light_samples = 4 +cycles.subsurface_samples = 4 +cycles.volume_samples = 4 diff --git a/release/scripts/presets/ffmpeg/DVD (note_colon_ this changes render resolution).py b/release/scripts/presets/ffmpeg/DVD_(note_colon__this_changes_render_resolution).py index d858bd70836..d858bd70836 100644 --- a/release/scripts/presets/ffmpeg/DVD (note_colon_ this changes render resolution).py +++ b/release/scripts/presets/ffmpeg/DVD_(note_colon__this_changes_render_resolution).py diff --git a/release/scripts/presets/ffmpeg/h264 in MP4.py b/release/scripts/presets/ffmpeg/h264_in_MP4.py index 0e9c32c4878..0e9c32c4878 100644 --- a/release/scripts/presets/ffmpeg/h264 in MP4.py +++ b/release/scripts/presets/ffmpeg/h264_in_MP4.py diff --git a/release/scripts/presets/ffmpeg/h264 in Matroska.py b/release/scripts/presets/ffmpeg/h264_in_Matroska.py index 1fe066dc4bf..1fe066dc4bf 100644 --- a/release/scripts/presets/ffmpeg/h264 in Matroska.py +++ b/release/scripts/presets/ffmpeg/h264_in_Matroska.py diff --git a/release/scripts/presets/ffmpeg/h264 in Matroska for scrubbing.py b/release/scripts/presets/ffmpeg/h264_in_Matroska_for_scrubbing.py index eb1889d272f..eb1889d272f 100644 --- a/release/scripts/presets/ffmpeg/h264 in Matroska for scrubbing.py +++ b/release/scripts/presets/ffmpeg/h264_in_Matroska_for_scrubbing.py diff --git a/release/scripts/presets/interface_theme/dark_blue_gradient.xml b/release/scripts/presets/interface_theme/dark_blue_gradient.xml index d3d0f5bb522..d226f8531b2 100644 --- a/release/scripts/presets/interface_theme/dark_blue_gradient.xml +++ b/release/scripts/presets/interface_theme/dark_blue_gradient.xml @@ -110,7 +110,7 @@ inner="#39424bcc" inner_sel="#667686bf" item="#191919ff" - text="#000000" + text="#b8b8b8" text_sel="#ffffff" show_shaded="TRUE" shadetop="25" diff --git a/release/scripts/presets/interface_theme/elsyiun.xml b/release/scripts/presets/interface_theme/elsyiun.xml index 7a3d5146636..b9292856fe9 100644 --- a/release/scripts/presets/interface_theme/elsyiun.xml +++ b/release/scripts/presets/interface_theme/elsyiun.xml @@ -110,7 +110,7 @@ inner="#4b4b4bff" inner_sel="#646464ff" item="#191919ff" - text="#000000" + text="#b8b8b8" text_sel="#ffffff" show_shaded="TRUE" shadetop="0" diff --git a/release/scripts/presets/interface_theme/science_lab.xml b/release/scripts/presets/interface_theme/science_lab.xml index 9341e945375..2fe4cf99e41 100644 --- a/release/scripts/presets/interface_theme/science_lab.xml +++ b/release/scripts/presets/interface_theme/science_lab.xml @@ -110,7 +110,7 @@ inner="#303030ff" inner_sel="#678db2ff" item="#191919ff" - text="#272727" + text="#e6f1ff" text_sel="#ffffff" show_shaded="FALSE" shadetop="0" diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py index 02fb05e29eb..0632f9bc3ca 100644 --- a/release/scripts/startup/bl_operators/anim.py +++ b/release/scripts/startup/bl_operators/anim.py @@ -137,6 +137,9 @@ class ANIM_OT_keying_set_export(Operator): break else: self.report({'WARN'}, "Could not find scene using Compositor Node Tree - %s" % (ksp.id)) + elif ksp.id.bl_rna.name == "Key": + # "keys" conflicts with a Python keyword, hence the simple solution won't work + id_bpy_path = "bpy.data.shape_keys[\"%s\"]" % (ksp.id.name) else: idtype_list = ksp.id.bl_rna.name.lower() + "s" id_bpy_path = "bpy.data.%s[\"%s\"]" % (idtype_list, ksp.id.name) @@ -195,7 +198,7 @@ class ANIM_OT_keying_set_export(Operator): class BakeAction(Operator): - """Bake object/pose loc/scale/rotation animation to a new action""" + """Bake all selected objects loc/scale/rotation animation to an action""" bl_idname = "nla.bake" bl_label = "Bake Action" bl_options = {'REGISTER', 'UNDO'} @@ -219,7 +222,7 @@ class BakeAction(Operator): default=1, ) only_selected = BoolProperty( - name="Only Selected", + name="Only Selected Bones", description="Only key selected bones (Pose baking only)", default=True, ) @@ -255,29 +258,27 @@ class BakeAction(Operator): ) def execute(self, context): - from bpy_extras import anim_utils - - action = None - if self.use_current_action: - obj = context.object - if obj.animation_data: - action = obj.animation_data.action - - action = anim_utils.bake_action(self.frame_start, - self.frame_end, - frame_step=self.step, - only_selected=self.only_selected, - do_pose='POSE' in self.bake_types, - do_object='OBJECT' in self.bake_types, - do_visual_keying=self.visual_keying, - do_constraint_clear=self.clear_constraints, - do_parents_clear=self.clear_parents, - do_clean=True, - action=action, - ) - - if action is None: + objects = context.selected_editable_objects + object_action_pairs = ( + [(obj, getattr(obj.animation_data, "action", None)) for obj in objects] + if self.use_current_action else + [(obj, None) for obj in objects] + ) + + actions = anim_utils.bake_action_objects( + object_action_pairs, + frames=range(self.frame_start, self.frame_end + 1, self.step), + only_selected=self.only_selected, + do_pose='POSE' in self.bake_types, + do_object='OBJECT' in self.bake_types, + do_visual_keying=self.visual_keying, + do_constraint_clear=self.clear_constraints, + do_parents_clear=self.clear_parents, + do_clean=True, + ) + + if not any(actions): self.report({'INFO'}, "Nothing to bake") return {'CANCELLED'} diff --git a/release/scripts/startup/bl_operators/clip.py b/release/scripts/startup/bl_operators/clip.py index d8ef9e1f3ef..f63b0495d02 100644 --- a/release/scripts/startup/bl_operators/clip.py +++ b/release/scripts/startup/bl_operators/clip.py @@ -210,7 +210,7 @@ class CLIP_OT_set_active_clip(bpy.types.Operator): @classmethod def poll(cls, context): space = context.space_data - return space.type == 'CLIP_EDITOR' + return space.type == 'CLIP_EDITOR' and space.clip def execute(self, context): clip = context.space_data.clip @@ -254,6 +254,11 @@ class CLIP_OT_track_to_empty(Operator): constraint.object = tracking_object.name constraint.camera = CLIP_camera_for_clip(context, clip) + @classmethod + def poll(cls, context): + space = context.space_data + return space.type == 'CLIP_EDITOR' and space.clip + def execute(self, context): sc = context.space_data clip = sc.clip diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index 1539ffb3545..b7d3866989d 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -131,6 +131,11 @@ def align_objects(context, cursor = (space if space and space.type == 'VIEW_3D' else scene).cursor_location + # We are accessing runtime data such as evaluated bounding box, so we need to + # be sure it is properly updated and valid (bounding box might be lost on operator + # redo). + scene.update() + Left_Front_Up_SEL = [0.0, 0.0, 0.0] Right_Back_Down_SEL = [0.0, 0.0, 0.0] diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py index d9a4afea5cc..0ae600c8046 100644 --- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py +++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py @@ -723,7 +723,7 @@ def main(context, global USER_FILL_HOLES_QUALITY global USER_STRETCH_ASPECT global USER_ISLAND_MARGIN - + from math import cos import time @@ -747,7 +747,7 @@ def main(context, USER_FILL_HOLES = 0 USER_FILL_HOLES_QUALITY = 50 # Only for hole filling. USER_VIEW_INIT = 0 # Only for hole filling. - + is_editmode = (context.active_object.mode == 'EDIT') if is_editmode: bpy.ops.uv.reveal() diff --git a/release/scripts/startup/bl_ui/properties_animviz.py b/release/scripts/startup/bl_ui/properties_animviz.py index 43c01822b58..9782d5a072c 100644 --- a/release/scripts/startup/bl_ui/properties_animviz.py +++ b/release/scripts/startup/bl_ui/properties_animviz.py @@ -87,11 +87,11 @@ class MotionPathButtonsPanel: col.label(text="Show:") col.prop(mps, "show_frame_numbers", text="Frame Numbers") if mpath is not None: - col.prop(mpath, "lines", text='Lines') - col.prop(mpath, "line_thickness", text='Thickness') + col.prop(mpath, "lines", text="Lines") + col.prop(mpath, "line_thickness", text="Thickness") col = split.column() - col.label('') + col.label("") col.prop(mps, "show_keyframe_highlight", text="Keyframes") sub = col.column() sub.enabled = mps.show_keyframe_highlight @@ -102,10 +102,10 @@ class MotionPathButtonsPanel: # Customize path if mpath is not None: row = layout.row(align=True) - row.prop(mpath, "use_custom_color", text='', toggle=True, icon='COLOR') + row.prop(mpath, "use_custom_color", text="", toggle=True, icon='COLOR') sub = row.row(align=True) sub.enabled = mpath.use_custom_color - sub.prop(mpath, "color", text='') + sub.prop(mpath, "color", text="") # FIXME: this panel still needs to be ported so that it will work correctly with animviz diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index 00892d5f85b..9b61101778f 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -886,10 +886,10 @@ class ConstraintButtonsPanel: box.template_cache_file(con, "cache_file") cache_file = con.cache_file - + layout.label(text="Constraint Properties:") box = layout.box() - + if cache_file is not None: box.prop_search(con, "object_path", cache_file, "object_paths") diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index 20038e1354a..6a13e2ddd44 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -96,7 +96,7 @@ class DATA_PT_display(ArmatureButtonsPanel, Panel): col.prop(arm, "use_deform_delay", text="Delay Refresh") -class DATA_PT_bone_group_specials(Menu): +class DATA_MT_bone_group_specials(Menu): bl_label = "Bone Group Specials" def draw(self, context): @@ -130,7 +130,7 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel): col.active = (ob.proxy is None) col.operator("pose.group_add", icon='ZOOMIN', text="") col.operator("pose.group_remove", icon='ZOOMOUT', text="") - col.menu("DATA_PT_bone_group_specials", icon='DOWNARROW_HLT', text="") + col.menu("DATA_MT_bone_group_specials", icon='DOWNARROW_HLT', text="") if group: col.separator() col.operator("pose.group_move", icon='TRIA_UP', text="").direction = 'UP' @@ -180,7 +180,7 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel): if poselib: # warning about poselib being in an invalid state if len(poselib.fcurves) > 0 and len(poselib.pose_markers) == 0: - layout.label(icon='ERROR', text="Error: Potentially corrupt library, run 'Sanitize' operator to fix") + layout.label(icon='ERROR', text="Error: Potentially corrupt library, run 'Sanitize' operator to fix") # list of poses in pose library row = layout.row() @@ -337,7 +337,7 @@ classes = ( DATA_PT_context_arm, DATA_PT_skeleton, DATA_PT_display, - DATA_PT_bone_group_specials, + DATA_MT_bone_group_specials, DATA_PT_bone_groups, DATA_PT_pose_library, DATA_PT_ghost, diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py index 98aa31ac915..f9394139b42 100644 --- a/release/scripts/startup/bl_ui/properties_data_lamp.py +++ b/release/scripts/startup/bl_ui/properties_data_lamp.py @@ -216,7 +216,7 @@ class DATA_PT_shadow(DataButtonsPanel, Panel): split = layout.split() col = split.column() - col.label(text="Form factor sampling:") + col.label(text="Form Factor Sampling:") sub = col.row(align=True) diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index d72855fab6b..8f6e5f2df39 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -146,9 +146,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): layout.row().prop(md, "offset_type", expand=True) def BOOLEAN(self, layout, ob, md): + solver = md.solver if not bpy.app.build_options.mod_boolean: - layout.label("Built without Boolean modifier") - return + if solver == 'CARVE': + layout.label("Built without Carve solver") split = layout.split() @@ -164,9 +165,13 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): split.column().label(text="Solver:") split.column().prop(md, "solver", text="") - if md.solver == 'BMESH': + if solver == 'BMESH': layout.prop(md, "double_threshold") + if bpy.app.debug: + layout.prop(md, "debug_options") + + def BUILD(self, layout, ob, md): split = layout.split() @@ -381,7 +386,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): split = layout.split() col = split.column() - col.label(text="Vertex group:") + col.label(text="Vertex Group:") col.prop_search(md, "vertex_group", ob, "vertex_groups", text="") sub = col.column() sub.active = bool(md.vertex_group) @@ -566,8 +571,8 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col = split.column() col.label(text="Textures:") - col.prop(md, "use_mirror_u", text="U") - col.prop(md, "use_mirror_v", text="V") + col.prop(md, "use_mirror_u", text="Flip U") + col.prop(md, "use_mirror_v", text="Flip V") col = layout.column(align=True) @@ -577,6 +582,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): if md.use_mirror_v: col.prop(md, "mirror_offset_v") + col = layout.column(align=True) + col.prop(md, "offset_u") + col.prop(md, "offset_v") + col = layout.column() if md.use_mirror_merge is True: @@ -747,6 +756,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "steps") col.prop(md, "render_steps") col.prop(md, "use_smooth_shade") + col.prop(md, "use_merge_vertices") + sub = col.column() + sub.active = md.use_merge_vertices + sub.prop(md, "merge_threshold") col = split.column() row = col.row() @@ -917,9 +930,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): scene = bpy.context.scene engine = scene.render.engine - show_adaptive_options = (engine == "CYCLES" and md == ob.modifiers[-1] and - scene.cycles.feature_set == "EXPERIMENTAL") - + show_adaptive_options = ( + engine == 'CYCLES' and md == ob.modifiers[-1] and + scene.cycles.feature_set == 'EXPERIMENTAL' + ) if show_adaptive_options: col.label(text="View:") col.prop(md, "levels", text="Levels") diff --git a/release/scripts/startup/bl_ui/properties_freestyle.py b/release/scripts/startup/bl_ui/properties_freestyle.py index 9c5be7624e0..3d105934bf8 100644 --- a/release/scripts/startup/bl_ui/properties_freestyle.py +++ b/release/scripts/startup/bl_ui/properties_freestyle.py @@ -123,7 +123,7 @@ class RENDERLAYER_PT_freestyle(RenderLayerFreestyleButtonsPanel, Panel): layout.active = rl.use_freestyle row = layout.row() - layout.prop(freestyle, "mode", text="Control mode") + layout.prop(freestyle, "mode", text="Control Mode") layout.prop(freestyle, "use_view_map_cache", text="View Map Cache") layout.label(text="Edge Detection Options:") @@ -285,7 +285,7 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel, def draw_modifier_box_error(self, box, modifier, message): row = box.row() - row.label(text=message, icon="ERROR") + row.label(text=message, icon='ERROR') def draw_modifier_common(self, box, modifier): row = box.row() diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py index 636a9707ab9..277b0842b3d 100644 --- a/release/scripts/startup/bl_ui/properties_game.py +++ b/release/scripts/startup/bl_ui/properties_game.py @@ -90,11 +90,11 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel): split = layout.split() col = split.column() - col.label(text="Linear velocity:") + col.label(text="Linear Velocity:") sub = col.column(align=True) sub.prop(game, "velocity_min", text="Minimum") sub.prop(game, "velocity_max", text="Maximum") - col.label(text="Angular velocity:") + col.label(text="Angular Velocity:") sub = col.column(align=True) sub.prop(game, "angular_velocity_min", text="Minimum") sub.prop(game, "angular_velocity_max", text="Maximum") diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 52835a00796..2aa978a51d8 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -75,16 +75,16 @@ def gpencil_active_brush_settings_simple(context, layout): col.prop(brush, "line_width", slider=True) row = col.row(align=True) - row.prop(brush, "use_random_pressure", text='', icon='RNDCURVE') + row.prop(brush, "use_random_pressure", text="", icon='RNDCURVE') row.prop(brush, "pen_sensitivity_factor", slider=True) - row.prop(brush, "use_pressure", text='', icon='STYLUS_PRESSURE') + row.prop(brush, "use_pressure", text="", icon='STYLUS_PRESSURE') row = col.row(align=True) - row.prop(brush, "use_random_strength", text='', icon='RNDCURVE') + row.prop(brush, "use_random_strength", text="", icon='RNDCURVE') row.prop(brush, "strength", slider=True) - row.prop(brush, "use_strength_pressure", text='', icon='STYLUS_PRESSURE') + row.prop(brush, "use_strength_pressure", text="", icon='STYLUS_PRESSURE') row = col.row(align=True) row.prop(brush, "jitter", slider=True) - row.prop(brush, "use_jitter_pressure", text='', icon='STYLUS_PRESSURE') + row.prop(brush, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE') row = col.row() row.prop(brush, "angle", slider=True) row.prop(brush, "angle_factor", text="Factor", slider=True) @@ -340,19 +340,19 @@ class GreasePencilBrushPanel: row = layout.row() row.prop(brush, "line_width") row = layout.row(align=True) - row.prop(brush, "use_random_pressure", text='', icon='RNDCURVE') + row.prop(brush, "use_random_pressure", text="", icon='RNDCURVE') row.prop(brush, "pen_sensitivity_factor", slider=True) - row.prop(brush, "use_pressure", text='', icon='STYLUS_PRESSURE') + row.prop(brush, "use_pressure", text="", icon='STYLUS_PRESSURE') row = layout.row(align=True) - row.prop(brush, "use_random_strength", text='', icon='RNDCURVE') + row.prop(brush, "use_random_strength", text="", icon='RNDCURVE') row.prop(brush, "strength", slider=True) - row.prop(brush, "use_strength_pressure", text='', icon='STYLUS_PRESSURE') + row.prop(brush, "use_strength_pressure", text="", icon='STYLUS_PRESSURE') row = layout.row(align=True) row.prop(brush, "random_press", slider=True) row = layout.row(align=True) row.prop(brush, "jitter", slider=True) - row.prop(brush, "use_jitter_pressure", text='', icon='STYLUS_PRESSURE') + row.prop(brush, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE') row = layout.row() row.prop(brush, "angle", slider=True) row.prop(brush, "angle_factor", text="Factor", slider=True) @@ -365,7 +365,7 @@ class GreasePencilBrushPanel: col.separator() row = col.row(align=False) row.prop(brush, "pen_subdivision_steps") - row.prop(brush, "random_subdiv", text='Randomness', slider=True) + row.prop(brush, "random_subdiv", text="Randomness", slider=True) class GreasePencilStrokeSculptPanel: @@ -463,7 +463,7 @@ class GreasePencilBrushCurvesPanel: ############################### -class GPENCIL_PIE_tool_palette(Menu): +class GPENCIL_MT_pie_tool_palette(Menu): """A pie menu for quick access to Grease Pencil tools""" bl_label = "Grease Pencil Tools" @@ -487,7 +487,7 @@ class GPENCIL_PIE_tool_palette(Menu): # E - "Settings" Palette is included here too, since it needs to be in a stable position... if gpd and gpd.layers.active: col.separator() - col.operator("wm.call_menu_pie", text="Settings...", icon='SCRIPTWIN').name = "GPENCIL_PIE_settings_palette" + col.operator("wm.call_menu_pie", text="Settings...", icon='SCRIPTWIN').name = "GPENCIL_MT_pie_settings_palette" # Editing tools if gpd: @@ -525,13 +525,13 @@ class GPENCIL_PIE_tool_palette(Menu): col.operator("gpencil.delete", icon='X', text="Delete...") # SE - More Tools - pie.operator("wm.call_menu_pie", text="More...").name = "GPENCIL_PIE_tools_more" + pie.operator("wm.call_menu_pie", text="More...").name = "GPENCIL_MT_pie_tools_more" else: # Toggle Edit Mode pie.operator("gpencil.editmode_toggle", text="Enable Stroke Editing", icon='EDIT') -class GPENCIL_PIE_settings_palette(Menu): +class GPENCIL_MT_pie_settings_palette(Menu): """A pie menu for quick access to Grease Pencil settings""" bl_label = "Grease Pencil Settings" @@ -609,12 +609,12 @@ class GPENCIL_PIE_settings_palette(Menu): row = col.row() row.operator("gpencil.stroke_join", text="Join").type = 'JOIN' row.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY' - col.operator("gpencil.stroke_flip", text="Flip direction") + col.operator("gpencil.stroke_flip", text="Flip Direction") - col.prop(gpd, "show_stroke_direction", text="Show drawing direction") + col.prop(gpd, "show_stroke_direction", text="Show Drawing Direction") -class GPENCIL_PIE_tools_more(Menu): +class GPENCIL_MT_pie_tools_more(Menu): """A pie menu for accessing more Grease Pencil tools""" bl_label = "More Grease Pencil Tools" @@ -643,10 +643,10 @@ class GPENCIL_PIE_tools_more(Menu): pie.operator("transform.tosphere", icon='MOD_MULTIRES') pie.operator("gpencil.convert", icon='OUTLINER_OB_CURVE', text="Convert...") - pie.operator("wm.call_menu_pie", text="Back to Main Palette...").name = "GPENCIL_PIE_tool_palette" + pie.operator("wm.call_menu_pie", text="Back to Main Palette...").name = "GPENCIL_MT_pie_tool_palette" -class GPENCIL_PIE_sculpt(Menu): +class GPENCIL_MT_pie_sculpt(Menu): """A pie menu for accessing Grease Pencil stroke sculpting settings""" bl_label = "Grease Pencil Sculpt" @@ -839,8 +839,8 @@ class GPENCIL_MT_brush_specials(Menu): def draw(self, context): layout = self.layout - layout.operator("gpencil.brush_copy", icon='PASTEDOWN', text="Copy current drawing brush") - layout.operator("gpencil.brush_presets_create", icon='HELP', text="Create a set of predefined brushes") + layout.operator("gpencil.brush_copy", icon='PASTEDOWN', text="Copy Current Drawing Brush") + layout.operator("gpencil.brush_presets_create", icon='HELP', text="Create a Set of Predefined Brushes") class GPENCIL_MT_palettecolor_specials(Menu): @@ -1158,10 +1158,10 @@ class GreasePencilToolsPanel: classes = ( - GPENCIL_PIE_tool_palette, - GPENCIL_PIE_settings_palette, - GPENCIL_PIE_tools_more, - GPENCIL_PIE_sculpt, + GPENCIL_MT_pie_tool_palette, + GPENCIL_MT_pie_settings_palette, + GPENCIL_MT_pie_tools_more, + GPENCIL_MT_pie_sculpt, GPENCIL_MT_snap, GPENCIL_MT_gpencil_edit_specials, GPENCIL_UL_brush, diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index dfd20d90ec4..b79f8263e39 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -157,9 +157,9 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal col.separator() if projpaint: if settings.mode == 'MATERIAL': - col.prop(settings, "use_clone_layer", text="Clone from paint slot") + col.prop(settings, "use_clone_layer", text="Clone from Paint Slot") elif settings.mode == 'IMAGE': - col.prop(settings, "use_clone_layer", text="Clone from image/UV map") + col.prop(settings, "use_clone_layer", text="Clone from Image/UV Map") if settings.use_clone_layer: ob = context.active_object diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index 23e7c0a6787..aa4cb0ba1e9 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -628,7 +628,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel): split = layout.split() col = split.column() - col.label(text="Fluid properties:") + col.label(text="Fluid Properties:") col.prop(fluid, "stiffness", text="Stiffness") col.prop(fluid, "linear_viscosity", text="Viscosity") col.prop(fluid, "buoyancy", text="Buoyancy", slider=True) @@ -749,7 +749,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel): if part.physics_type == 'BOIDS': layout.label(text="Relations:") elif part.physics_type == 'FLUID': - layout.label(text="Fluid interaction:") + layout.label(text="Fluid Interaction:") row = layout.row() row.template_list("UI_UL_list", "particle_targets", psys, "targets", @@ -1081,7 +1081,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel, Panel): col = row.column() col.prop(part, "trail_count") if part.trail_count > 1: - col.prop(part, "use_absolute_path_time", text="Length in frames") + col.prop(part, "use_absolute_path_time", text="Length in Frames") col = row.column() col.prop(part, "path_end", text="Length", slider=not part.use_absolute_path_time) col.prop(part, "length_random", text="Random", slider=True) diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py index 0b98d8738dc..73d3d5fc755 100644 --- a/release/scripts/startup/bl_ui/properties_physics_common.py +++ b/release/scripts/startup/bl_ui/properties_physics_common.py @@ -79,7 +79,7 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel): col = split.column() - if obj.type in {'MESH', 'LATTICE', 'CURVE'}: + if obj.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE', 'FONT'}: physics_add(self, col, context.soft_body, "Soft Body", 'SOFT_BODY', 'MOD_SOFT', True) if obj.type == 'MESH': diff --git a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py index cf1d4f38038..ec7287ef363 100644 --- a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py +++ b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py @@ -245,7 +245,7 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel): # paint-map output row = layout.row() - row.prop_search(surface, "output_name_a", ob.data, "vertex_colors", text="Paintmap layer") + row.prop_search(surface, "output_name_a", ob.data, "vertex_colors", text="Paintmap Layer") if surface.output_exists(object=ob, index=0): ic = 'ZOOMOUT' else: @@ -255,7 +255,7 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel): # wet-map output row = layout.row() - row.prop_search(surface, "output_name_b", ob.data, "vertex_colors", text="Wetmap layer") + row.prop_search(surface, "output_name_b", ob.data, "vertex_colors", text="Wetmap Layer") if surface.output_exists(object=ob, index=1): ic = 'ZOOMOUT' else: @@ -282,7 +282,7 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel): layout.prop(surface, "image_output_path", text="") row = layout.row() row.prop(surface, "image_fileformat", text="") - row.prop(surface, "use_premultiply", text="Premultiply alpha") + row.prop(surface, "use_premultiply", text="Premultiply Alpha") if surface_type == 'PAINT': split = layout.split(percentage=0.4) @@ -439,12 +439,12 @@ class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel): if brush.paint_source == 'PARTICLE_SYSTEM': col.prop_search(brush, "particle_system", ob, "particle_systems", text="") if brush.particle_system: - col.label(text="Particle effect:") + col.label(text="Particle Effect:") sub = col.column() sub.active = not brush.use_particle_radius sub.prop(brush, "solid_radius", text="Solid Radius") col.prop(brush, "use_particle_radius", text="Use Particle's Radius") - col.prop(brush, "smooth_radius", text="Smooth radius") + col.prop(brush, "smooth_radius", text="Smooth Radius") if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE', 'POINT'}: col.prop(brush, "paint_distance", text="Paint Distance") diff --git a/release/scripts/startup/bl_ui/properties_physics_softbody.py b/release/scripts/startup/bl_ui/properties_physics_softbody.py index 5ce4302891d..5efe105e7d8 100644 --- a/release/scripts/startup/bl_ui/properties_physics_softbody.py +++ b/release/scripts/startup/bl_ui/properties_physics_softbody.py @@ -26,6 +26,9 @@ from bl_ui.properties_physics_common import ( ) +COMPAT_OB_TYPES = {'MESH', 'LATTICE', 'CURVE', 'SURFACE', 'FONT'} + + def softbody_panel_enabled(md): return (md.point_cache.is_baked is False) @@ -39,7 +42,7 @@ class PhysicButtonsPanel: def poll(cls, context): ob = context.object rd = context.scene.render - return (ob and (ob.type == 'MESH' or ob.type == 'LATTICE'or ob.type == 'CURVE')) and (rd.engine in cls.COMPAT_ENGINES) and (context.soft_body) + return ob and ob.type in COMPAT_OB_TYPES and rd.engine in cls.COMPAT_ENGINES and context.soft_body class PHYSICS_PT_softbody(PhysicButtonsPanel, Panel): diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index a7e8d9273ad..2f3adf546b8 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -275,6 +275,7 @@ class RENDER_PT_performance(RenderButtonsPanel, Panel): col.separator() col.prop(rd, "preview_start_resolution") + col.prop(rd, "preview_pixel_size", text="") col = split.column() col.label(text="Memory:") @@ -286,7 +287,7 @@ class RENDER_PT_performance(RenderButtonsPanel, Panel): sub.prop(rd, "use_free_image_textures") sub = col.column() sub.active = rd.use_raytrace - sub.label(text="Acceleration structure:") + sub.label(text="Acceleration Structure:") sub.prop(rd, "raytrace_method", text="") if rd.raytrace_method == 'OCTREE': sub.prop(rd, "octree_resolution", text="Resolution") @@ -347,7 +348,7 @@ class RENDER_PT_stamp(RenderButtonsPanel, Panel): col.active = rd.use_stamp row = col.row() row.prop(rd, "stamp_font_size", text="Font Size") - row.prop(rd, "use_stamp_labels", text="Draw labels") + row.prop(rd, "use_stamp_labels", text="Draw Labels") row = col.row() row.column().prop(rd, "stamp_foreground", slider=True) @@ -409,37 +410,6 @@ class RENDER_PT_output(RenderButtonsPanel, Panel): if rd.use_multiview: layout.template_image_views(image_settings) - if file_format == 'QUICKTIME': - quicktime = rd.quicktime - - split = layout.split() - col = split.column() - col.prop(quicktime, "codec_type", text="Video Codec") - col.prop(quicktime, "codec_spatial_quality", text="Quality") - - # Audio - col.prop(quicktime, "audiocodec_type", text="Audio Codec") - if quicktime.audiocodec_type != 'No audio': - split = layout.split() - if quicktime.audiocodec_type == 'LPCM': - split.prop(quicktime, "audio_bitdepth", text="") - - split.prop(quicktime, "audio_samplerate", text="") - - split = layout.split() - col = split.column() - if quicktime.audiocodec_type == 'AAC': - col.prop(quicktime, "audio_bitrate") - - subsplit = split.split() - col = subsplit.column() - - if quicktime.audiocodec_type == 'AAC': - col.prop(quicktime, "audio_codec_isvbr") - - col = subsplit.column() - col.prop(quicktime, "audio_resampling_hq") - class RENDER_PT_encoding(RenderButtonsPanel, Panel): bl_label = "Encoding" @@ -482,9 +452,9 @@ class RENDER_PT_encoding(RenderButtonsPanel, Panel): layout.prop(ffmpeg, "gopsize") # B-Frames row = layout.row() - row.prop(ffmpeg, "use_max_b_frames", text='Max B-frames') + row.prop(ffmpeg, "use_max_b_frames", text="Max B-frames") pbox = row.split() - pbox.prop(ffmpeg, "max_b_frames", text='') + pbox.prop(ffmpeg, "max_b_frames", text="") pbox.enabled = ffmpeg.use_max_b_frames split = layout.split() diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index 43679727992..57195d22340 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -1033,11 +1033,11 @@ class CLIP_PT_proxy(CLIP_PT_clip_view_panel, Panel): if clip.source == 'MOVIE': col2 = col.column() - col2.label(text="Use timecode index:") + col2.label(text="Use Timecode Index:") col2.prop(clip.proxy, "timecode", text="") col2 = col.column() - col2.label(text="Proxy render size:") + col2.label(text="Proxy Render Size:") col.prop(sc.clip_user, "proxy_render_size", text="") @@ -1418,7 +1418,7 @@ class CLIP_MT_tracking_specials(Menu): text="Enable Markers").action = 'ENABLE' layout.operator("clip.disable_markers", - text="Disable markers").action = 'DISABLE' + text="Disable Markers").action = 'DISABLE' layout.separator() layout.operator("clip.set_origin") diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index afb5f6277a1..9868186e39c 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -1110,7 +1110,7 @@ class IMAGE_PT_tools_paint_options(BrushButtonsPanel, Panel): col.prop(ups, "use_unified_color", text="Color") -class IMAGE_UV_sculpt_curve(Panel): +class IMAGE_PT_uv_sculpt_curve(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'TOOLS' bl_label = "UV Sculpt Curve" @@ -1141,7 +1141,7 @@ class IMAGE_UV_sculpt_curve(Panel): row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX' -class IMAGE_UV_sculpt(Panel, ImagePaintPanel): +class IMAGE_PT_uv_sculpt(Panel, ImagePaintPanel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'TOOLS' bl_category = "Tools" @@ -1394,8 +1394,8 @@ classes = ( IMAGE_PT_tools_imagepaint_symmetry, IMAGE_PT_tools_brush_appearance, IMAGE_PT_tools_paint_options, - IMAGE_UV_sculpt, - IMAGE_UV_sculpt_curve, + IMAGE_PT_uv_sculpt, + IMAGE_PT_uv_sculpt_curve, IMAGE_PT_view_histogram, IMAGE_PT_view_waveform, IMAGE_PT_view_vectorscope, diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index b37b3c5705a..e2056905d93 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -187,10 +187,10 @@ class NODE_MT_view(Menu): if context.space_data.show_backdrop: layout.separator() - layout.operator("node.backimage_move", text="Backdrop move") - layout.operator("node.backimage_zoom", text="Backdrop zoom in").factor = 1.2 - layout.operator("node.backimage_zoom", text="Backdrop zoom out").factor = 0.83333 - layout.operator("node.backimage_fit", text="Fit backdrop to available space") + layout.operator("node.backimage_move", text="Backdrop Move") + layout.operator("node.backimage_zoom", text="Backdrop Zoom In").factor = 1.2 + layout.operator("node.backimage_zoom", text="Backdrop Zoom Out").factor = 0.83333 + layout.operator("node.backimage_fit", text="Fit Backdrop to Available Space") layout.separator() @@ -243,7 +243,7 @@ class NODE_MT_node(Menu): layout.separator() - layout.operator("node.join", text="Join in new Frame") + layout.operator("node.join", text="Join in New Frame") layout.operator("node.detach", text="Remove from Frame") layout.separator() diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 4eb550bbb35..731ab3d4b14 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -56,7 +56,7 @@ class OUTLINER_HT_header(Header): row.operator("anim.keyframe_delete", text="", icon='KEY_DEHLT') else: row = layout.row() - row.label(text="No Keying Set active") + row.label(text="No Keying Set Active") elif space.display_mode == 'ORPHAN_DATA': layout.operator("outliner.orphans_purge") diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 79bb10cefeb..06dd90685b7 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -43,7 +43,7 @@ def draw_color_balance(layout, color_balance): col.separator() col.separator() col.prop(color_balance, "lift", text="") - col.prop(color_balance, "invert_lift", text="Invert", icon="ARROW_LEFTRIGHT") + col.prop(color_balance, "invert_lift", text="Invert", icon='ARROW_LEFTRIGHT') split.template_color_picker(color_balance, "lift", value_slider=True, cubic=True) box = layout.box() @@ -53,7 +53,7 @@ def draw_color_balance(layout, color_balance): col.separator() col.separator() col.prop(color_balance, "gamma", text="") - col.prop(color_balance, "invert_gamma", text="Invert", icon="ARROW_LEFTRIGHT") + col.prop(color_balance, "invert_gamma", text="Invert", icon='ARROW_LEFTRIGHT') split.template_color_picker(color_balance, "gamma", value_slider=True, lock_luminosity=True, cubic=True) box = layout.box() @@ -63,7 +63,7 @@ def draw_color_balance(layout, color_balance): col.separator() col.separator() col.prop(color_balance, "gain", text="") - col.prop(color_balance, "invert_gain", text="Invert", icon="ARROW_LEFTRIGHT") + col.prop(color_balance, "invert_gain", text="Invert", icon='ARROW_LEFTRIGHT') split.template_color_picker(color_balance, "gain", value_slider=True, lock_luminosity=True, cubic=True) @@ -197,7 +197,7 @@ class SEQUENCER_MT_view(Menu): layout.operator_context = 'INVOKE_DEFAULT' if is_preview: layout.operator_context = 'INVOKE_REGION_PREVIEW' - layout.operator("sequencer.view_all_preview", text="Fit preview in window") + layout.operator("sequencer.view_all_preview", text="Fit Preview in Window") layout.separator() @@ -246,10 +246,10 @@ class SEQUENCER_MT_select(Menu): layout.operator("sequencer.select_active_side", text="Strips to the Left").side = 'LEFT' layout.operator("sequencer.select_active_side", text="Strips to the Right").side = 'RIGHT' - props = layout.operator("sequencer.select", text="All strips to the Left") + props = layout.operator("sequencer.select", text="All Strips to the Left") props.left_right = 'LEFT' props.linked_time = True - props = layout.operator("sequencer.select", text="All strips to the Right") + props = layout.operator("sequencer.select", text="All Strips to the Right") props.left_right = 'RIGHT' props.linked_time = True @@ -397,15 +397,15 @@ class SEQUENCER_MT_strip(Menu): layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("transform.transform", text="Grab/Move").mode = 'TRANSLATION' - layout.operator("transform.transform", text="Grab/Extend from frame").mode = 'TIME_EXTEND' + layout.operator("transform.transform", text="Grab/Extend from Frame").mode = 'TIME_EXTEND' layout.operator("sequencer.gap_remove").all = False layout.operator("sequencer.gap_insert") # uiItemO(layout, NULL, 0, "sequencer.strip_snap"); // TODO - add this operator layout.separator() - layout.operator("sequencer.cut", text="Cut (hard) at frame").type = 'HARD' - layout.operator("sequencer.cut", text="Cut (soft) at frame").type = 'SOFT' + layout.operator("sequencer.cut", text="Cut (Hard) at Frame").type = 'HARD' + layout.operator("sequencer.cut", text="Cut (Soft) at Frame").type = 'SOFT' layout.operator("sequencer.slip", text="Slip Strip Contents") layout.operator("sequencer.images_separate") layout.operator("sequencer.offset_clear") @@ -631,7 +631,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): if strip.use_as_speed: layout.prop(strip, "speed_factor") else: - layout.prop(strip, "speed_factor", text="Frame number") + layout.prop(strip, "speed_factor", text="Frame Number") layout.prop(strip, "scale_to_length") elif strip.type == 'TRANSFORM': @@ -698,7 +698,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): row.label("") else: col.separator() - col.label(text="Two or more channels are needed below this strip", icon="INFO") + col.label(text="Two or more channels are needed below this strip", icon='INFO') elif strip.type == 'TEXT': @@ -728,7 +728,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): elif strip.type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'ALPHA_OVER', 'ALPHA_UNDER', 'OVER_DROP'}: col.prop(strip, "use_default_fade", "Default fade") if not strip.use_default_fade: - col.prop(strip, "effect_fader", text="Effect fader") + col.prop(strip, "effect_fader", text="Effect Fader") elif strip.type == 'GAUSSIAN_BLUR': row = col.row(align=True) row.prop(strip, "size_x") @@ -784,7 +784,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel): split.label(text="Alpha:") split.prop(strip, "alpha_mode", text="") - layout.operator("sequencer.change_path", icon="FILESEL").filter_image = True + layout.operator("sequencer.change_path", icon='FILESEL').filter_image = True elif seq_type == 'MOVIE': split = layout.split(percentage=0.2) @@ -1056,9 +1056,9 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel): proxy = strip.proxy flow = layout.column_flow() - flow.prop(sequencer, "proxy_storage", text='Storage') + flow.prop(sequencer, "proxy_storage", text="Storage") if sequencer.proxy_storage == 'PROJECT': - flow.prop(sequencer, "proxy_dir", text='Directory') + flow.prop(sequencer, "proxy_dir", text="Directory") else: flow.prop(proxy, "use_proxy_custom_directory") flow.prop(proxy, "use_proxy_custom_file") @@ -1077,7 +1077,7 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel): layout.prop(proxy, "use_overwrite") col = layout.column() - col.prop(proxy, "quality", text="Build JPEG quality") + col.prop(proxy, "quality", text="Build JPEG Quality") if strip.type == 'MOVIE': col = layout.column() @@ -1101,9 +1101,6 @@ class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel): render = context.scene.render col = layout.column() - col.prop(render, "use_sequencer_gl_preview", text="OpenGL Preview") - col = layout.column() - #col.active = render.use_sequencer_gl_preview col.prop(render, "sequencer_gl_preview", text="") row = col.row() diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 03a40085172..5ba1f0b8dcb 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -218,6 +218,7 @@ class USERPREF_PT_interface(Panel): col = row.column() col.label(text="Display:") col.prop(view, "ui_scale", text="Scale") + col.prop(view, "ui_line_width", text="Line Width") col.prop(view, "show_tooltips") col.prop(view, "show_tooltips_python") col.prop(view, "show_object_info", text="Object Info") @@ -249,6 +250,7 @@ class USERPREF_PT_interface(Panel): col = row.column() col.label(text="View Manipulation:") col.prop(view, "use_mouse_depth_cursor") + col.prop(view, "use_cursor_lock_adjust") col.prop(view, "use_mouse_depth_navigate") col.prop(view, "use_zoom_to_mouse") col.prop(view, "use_rotate_around_active") @@ -477,7 +479,7 @@ class USERPREF_PT_system(Panel): col.label(text="Sound:") col.row().prop(system, "audio_device", expand=False) sub = col.column() - sub.active = system.audio_device != 'NONE' and system.audio_device != 'Null' + sub.active = system.audio_device not in {'NONE', 'Null'} #sub.prop(system, "use_preview_images") sub.prop(system, "audio_channels", text="Channels") sub.prop(system, "audio_mixing_buffer", text="Mixing Buffer") @@ -1105,29 +1107,29 @@ class USERPREF_MT_ndof_settings(Menu): layout.prop(input_prefs, "ndof_show_guide") layout.separator() - layout.label(text="Orbit style") + layout.label(text="Orbit Style") layout.row().prop(input_prefs, "ndof_view_navigate_method", text="") layout.row().prop(input_prefs, "ndof_view_rotate_method", text="") layout.separator() - layout.label(text="Orbit options") + layout.label(text="Orbit Options") layout.prop(input_prefs, "ndof_rotx_invert_axis") layout.prop(input_prefs, "ndof_roty_invert_axis") layout.prop(input_prefs, "ndof_rotz_invert_axis") # view2d use pan/zoom layout.separator() - layout.label(text="Pan options") + layout.label(text="Pan Options") layout.prop(input_prefs, "ndof_panx_invert_axis") layout.prop(input_prefs, "ndof_pany_invert_axis") layout.prop(input_prefs, "ndof_panz_invert_axis") layout.prop(input_prefs, "ndof_pan_yz_swap_axis") - layout.label(text="Zoom options") + layout.label(text="Zoom Options") layout.prop(input_prefs, "ndof_zoom_invert") if is_view3d: layout.separator() - layout.label(text="Fly/Walk options") + layout.label(text="Fly/Walk Options") layout.prop(input_prefs, "ndof_fly_helicopter", icon='NDOF_FLY') layout.prop(input_prefs, "ndof_lock_horizon", icon='NDOF_DOM') @@ -1452,7 +1454,7 @@ class USERPREF_PT_addons(Panel): sub = row.row() sub.active = is_enabled - sub.label(text='%s: %s' % (info["category"], info["name"])) + sub.label(text="%s: %s" % (info["category"], info["name"])) if info["warning"]: sub.label(icon='ERROR') @@ -1480,11 +1482,11 @@ class USERPREF_PT_addons(Panel): if info["version"]: split = colsub.row().split(percentage=0.15) split.label(text="Version:") - split.label(text='.'.join(str(x) for x in info["version"]), translate=False) + split.label(text=".".join(str(x) for x in info["version"]), translate=False) if info["warning"]: split = colsub.row().split(percentage=0.15) split.label(text="Warning:") - split.label(text=' ' + info["warning"], icon='ERROR') + split.label(text=" " + info["warning"], icon='ERROR') user_addon = USERPREF_PT_addons.is_user_addon(mod, user_addon_paths) tot_row = bool(info["wiki_url"]) + bool(user_addon) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 02c0f69ac82..1086f22b8da 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -55,7 +55,7 @@ class VIEW3D_HT_header(Header): # Occlude geometry if ((view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'PARTICLE_EDIT' or (mode == 'EDIT' and obj.type == 'MESH'))) or - (mode == 'WEIGHT_PAINT')): + (mode in {'WEIGHT_PAINT', 'VERTEX_PAINT'})): row.prop(view, "use_occlude_geometry", text="") # Proportional editing @@ -170,7 +170,7 @@ class VIEW3D_MT_editor_menus(Menu): mesh = obj.data if mesh.use_paint_mask: layout.menu("VIEW3D_MT_select_paint_mask") - elif mesh.use_paint_mask_vertex and mode_string == 'PAINT_WEIGHT': + elif mesh.use_paint_mask_vertex and mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX'}: layout.menu("VIEW3D_MT_select_paint_mask_vertex") elif mode_string != 'SCULPT': layout.menu("VIEW3D_MT_select_%s" % mode_string.lower()) @@ -294,7 +294,8 @@ class VIEW3D_MT_transform_object(VIEW3D_MT_transform_base): layout.operator("object.origin_set", text="Geometry to Origin").type = 'GEOMETRY_ORIGIN' layout.operator("object.origin_set", text="Origin to Geometry").type = 'ORIGIN_GEOMETRY' layout.operator("object.origin_set", text="Origin to 3D Cursor").type = 'ORIGIN_CURSOR' - layout.operator("object.origin_set", text="Origin to Center of Mass").type = 'ORIGIN_CENTER_OF_MASS' + layout.operator("object.origin_set", text="Origin to Center of Mass (Surface)").type = 'ORIGIN_CENTER_OF_MASS' + layout.operator("object.origin_set", text="Origin to Center of Mass (Volume)").type = 'ORIGIN_CENTER_OF_VOLUME' layout.separator() layout.operator("object.randomize_transform") @@ -1710,7 +1711,7 @@ class VIEW3D_MT_brush(Menu): # skip if no active brush if not brush: - layout.label(text="No Brushes currently available", icon="INFO") + layout.label(text="No Brushes currently available", icon='INFO') return # brush paint modes @@ -1779,6 +1780,7 @@ class VIEW3D_MT_paint_vertex(Menu): layout.operator("paint.vertex_color_set") layout.operator("paint.vertex_color_smooth") layout.operator("paint.vertex_color_dirt") + layout.operator("paint.vertex_color_from_weight") layout.separator() @@ -2113,7 +2115,7 @@ class VIEW3D_MT_pose_transform(Menu): layout.separator() - layout.operator("pose.user_transforms_clear", text="Reset unkeyed") + layout.operator("pose.user_transforms_clear", text="Reset Unkeyed") class VIEW3D_MT_pose_slide(Menu): diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 2e291d3d471..d260bfe3460 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -51,6 +51,19 @@ def draw_keyframing_tools(context, layout): row.operator("anim.keyframe_delete_v3d", text="Remove") +# Used by vertex & weight paint +def draw_vpaint_symmetry(layout, vpaint): + col = layout.column(align=True) + col.label(text="Mirror:") + row = col.row(align=True) + + row.prop(vpaint, "use_symmetry_x", text="X", toggle=True) + row.prop(vpaint, "use_symmetry_y", text="Y", toggle=True) + row.prop(vpaint, "use_symmetry_z", text="Z", toggle=True) + + col = layout.column() + col.prop(vpaint, "radial_symmetry", text="Radial") + # ********** default tools for object-mode **************** @@ -916,16 +929,18 @@ class VIEW3D_PT_imapaint_tools_missing(Panel, View3DPaintPanel): col.separator() col.label("Missing Canvas", icon='INFO') col.label("Add or assign a canvas image below") - col.label("Canvas Image") - col.template_ID(toolsettings, "canvas") + col.label("Canvas Image:") + # todo this should be combinded into a single row + col.template_ID(toolsettings, "canvas", open="image.open") col.operator("image.new", text="New").gen_context = 'PAINT_CANVAS' if toolsettings.missing_stencil: col.separator() col.label("Missing Stencil", icon='INFO') col.label("Add or assign a stencil image below") - col.label("Stencil Image") - col.template_ID(toolsettings, "stencil_image") + col.label("Stencil Image:") + # todo this should be combinded into a single row + col.template_ID(toolsettings, "stencil_image", open="image.open") col.operator("image.new", text="New").gen_context = 'PAINT_STENCIL' @@ -1118,7 +1133,7 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel): col.prop(brush, "vertex_tool", text="Blend") - if brush.vertex_tool == 'BLUR': + if brush.vertex_tool != 'SMEAR': col.prop(brush, "use_accumulate") col.separator() @@ -1132,7 +1147,11 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel): self.prop_unified_color_picker(col, context, brush, "color", value_slider=True) if settings.palette: col.template_palette(settings, "palette", color=True) - self.prop_unified_color(col, context, brush, "color", text="") + row = col.row(align=True) + self.prop_unified_color(row, context, brush, "color", text="") + self.prop_unified_color(row, context, brush, "secondary_color", text="") + row.separator() + row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="") col.separator() row = col.row(align=True) @@ -1149,6 +1168,8 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel): # row.prop(brush, "use_pressure_jitter", toggle=True, text="") col.separator() col.prop(brush, "vertex_tool", text="Blend") + col.prop(brush, "use_accumulate") + col.prop(brush, "use_alpha") col.separator() col.template_ID(settings, "palette", new="palette.new") @@ -1200,20 +1221,20 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel): ob = context.active_object col = layout.column() - col.label("Painting Mode") + col.label("Painting Mode:") col.prop(settings, "mode", text="") col.separator() if settings.mode == 'MATERIAL': if len(ob.material_slots) > 1: - col.label("Materials") + col.label("Materials:") col.template_list("MATERIAL_UL_matslots", "layers", ob, "material_slots", ob, "active_material_index", rows=2) mat = ob.active_material if mat: - col.label("Available Paint Slots") + col.label("Available Paint Slots:") col.template_list("TEXTURE_UL_texpaintslots", "", mat, "texture_paint_images", mat, "paint_active_slot", rows=2) @@ -1233,16 +1254,17 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel): col.separator() if slot and slot.index != -1: - col.label("UV Map") + col.label("UV Map:") col.prop_search(slot, "uv_layer", ob.data, "uv_textures", text="") elif settings.mode == 'IMAGE': mesh = ob.data uv_text = mesh.uv_textures.active.name if mesh.uv_textures.active else "" - col.label("Canvas Image") - col.template_ID(settings, "canvas") + col.label("Canvas Image:") + # todo this should be combinded into a single row + col.template_ID(settings, "canvas", open="image.open") col.operator("image.new", text="New").gen_context = 'PAINT_CANVAS' - col.label("UV Map") + col.label("UV Map:") col.menu("VIEW3D_MT_tools_projectpaint_uvlayer", text=uv_text, translate=False) col.separator() @@ -1276,14 +1298,15 @@ class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel): col.active = ipaint.use_stencil_layer stencil_text = mesh.uv_texture_stencil.name if mesh.uv_texture_stencil else "" - col.label("UV Map") + col.label("UV Map:") col.menu("VIEW3D_MT_tools_projectpaint_stencil", text=stencil_text, translate=False) - col.label("Stencil Image") - col.template_ID(ipaint, "stencil_image") + col.label("Stencil Image:") + # todo this should be combinded into a single row + col.template_ID(ipaint, "stencil_image", open="image.open") col.operator("image.new", text="New").gen_context = 'PAINT_STENCIL' - col.label("Visualization") + col.label("Visualization:") row = col.row(align=True) row.prop(ipaint, "stencil_color", text="") row.prop(ipaint, "invert_stencil", text="", icon='IMAGE_ALPHA') @@ -1713,6 +1736,19 @@ class VIEW3D_PT_tools_weightpaint(View3DPanel, Panel): props.data_type = 'VGROUP_WEIGHTS' +class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel): + bl_category = "Tools" + bl_context = "weightpaint" + bl_options = {'DEFAULT_CLOSED'} + bl_label = "Symmetry" + + def draw(self, context): + layout = self.layout + toolsettings = context.tool_settings + wpaint = toolsettings.weight_paint + draw_vpaint_symmetry(layout, wpaint) + + class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel): bl_category = "Options" bl_context = "weightpaint" @@ -1775,6 +1811,20 @@ class VIEW3D_PT_tools_vertexpaint(Panel, View3DPaintPanel): #~ col.label(text="Multiply:") #~ col.prop(vpaint, "mul", text="") + +class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel): + bl_category = "Tools" + bl_context = "vertexpaint" + bl_options = {'DEFAULT_CLOSED'} + bl_label = "Symmetry" + + def draw(self, context): + layout = self.layout + toolsettings = context.tool_settings + vpaint = toolsettings.vertex_paint + draw_vpaint_symmetry(layout, vpaint) + + # ********** default tools for texture-paint **************** @@ -1921,7 +1971,7 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, Panel): col = layout.column(align=True) if pe.is_hair: col.active = pe.is_editable - col.prop(pe, "use_emitter_deflect", text="Deflect emitter") + col.prop(pe, "use_emitter_deflect", text="Deflect Emitter") sub = col.row(align=True) sub.active = pe.use_emitter_deflect sub.prop(pe, "emitter_distance", text="Distance") @@ -2054,8 +2104,10 @@ classes = ( VIEW3D_PT_sculpt_symmetry, VIEW3D_PT_tools_brush_appearance, VIEW3D_PT_tools_weightpaint, + VIEW3D_PT_tools_weightpaint_symmetry, VIEW3D_PT_tools_weightpaint_options, VIEW3D_PT_tools_vertexpaint, + VIEW3D_PT_tools_vertexpaint_symmetry, VIEW3D_PT_tools_imagepaint_external, VIEW3D_PT_tools_imagepaint_symmetry, VIEW3D_PT_tools_projectpaint, diff --git a/release/scripts/startup/keyingsets_builtins.py b/release/scripts/startup/keyingsets_builtins.py index f62e3602bb9..390c043bb31 100644 --- a/release/scripts/startup/keyingsets_builtins.py +++ b/release/scripts/startup/keyingsets_builtins.py @@ -494,7 +494,7 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo): # bendy bone properties def doBBone(ksi, context, ks, pchan): bone = pchan.bone - + # This check is crude, but is the best we can do for now # It simply adds all of these if the bbone has segments # (and the bone is a control bone). This may lead to some diff --git a/release/scripts/templates_py/custom_nodes.py b/release/scripts/templates_py/custom_nodes.py index 32c61abace7..8ca748c1d66 100644 --- a/release/scripts/templates_py/custom_nodes.py +++ b/release/scripts/templates_py/custom_nodes.py @@ -11,7 +11,7 @@ class MyCustomTree(NodeTree): # Optional identifier string. If not explicitly defined, the python class name is used. bl_idname = 'CustomTreeType' # Label for nice name display - bl_label = 'Custom Node Tree' + bl_label = "Custom Node Tree" # Icon identifier bl_icon = 'NODETREE' @@ -23,24 +23,24 @@ class MyCustomSocket(NodeSocket): # Optional identifier string. If not explicitly defined, the python class name is used. bl_idname = 'CustomSocketType' # Label for nice name display - bl_label = 'Custom Node Socket' + bl_label = "Custom Node Socket" # Enum items list - my_items = [ - ("DOWN", "Down", "Where your feet are"), - ("UP", "Up", "Where your head should be"), - ("LEFT", "Left", "Not right"), - ("RIGHT", "Right", "Not left") - ] + my_items = ( + ('DOWN', "Down", "Where your feet are"), + ('UP', "Up", "Where your head should be"), + ('LEFT', "Left", "Not right"), + ('RIGHT', "Right", "Not left") + ) - myEnumProperty = bpy.props.EnumProperty(name="Direction", description="Just an example", items=my_items, default='UP') + my_enum_prop = bpy.props.EnumProperty(name="Direction", description="Just an example", items=my_items, default='UP') # Optional function for drawing the socket input value def draw(self, context, layout, node, text): if self.is_output or self.is_linked: layout.label(text) else: - layout.prop(self, "myEnumProperty", text=text) + layout.prop(self, "my_enum_prop", text=text) # Socket color def draw_color(self, context, node): @@ -63,7 +63,7 @@ class MyCustomNode(Node, MyCustomTreeNode): # Optional identifier string. If not explicitly defined, the python class name is used. bl_idname = 'CustomNodeType' # Label for nice name display - bl_label = 'Custom Node' + bl_label = "Custom Node" # Icon identifier bl_icon = 'SOUND' @@ -71,8 +71,8 @@ class MyCustomNode(Node, MyCustomTreeNode): # These work just like custom properties in ID data blocks # Extensive information can be found under # http://wiki.blender.org/index.php/Doc:2.6/Manual/Extensions/Python/Properties - myStringProperty = bpy.props.StringProperty() - myFloatProperty = bpy.props.FloatProperty(default=3.1415926) + my_string_prop = bpy.props.StringProperty() + my_float_prop = bpy.props.FloatProperty(default=3.1415926) # === Optional Functions === # Initialization function, called when a new node is created. @@ -99,14 +99,14 @@ class MyCustomNode(Node, MyCustomTreeNode): # Additional buttons displayed on the node. def draw_buttons(self, context, layout): layout.label("Node settings") - layout.prop(self, "myFloatProperty") + layout.prop(self, "my_float_prop") # Detail buttons in the sidebar. # If this function is not defined, the draw_buttons function is used instead def draw_buttons_ext(self, context, layout): - layout.prop(self, "myFloatProperty") - # myStringProperty button will only be visible in the sidebar - layout.prop(self, "myStringProperty") + layout.prop(self, "my_float_prop") + # my_string_prop button will only be visible in the sidebar + layout.prop(self, "my_string_prop") # Optional: custom label # Explicit user label overrides this, but here we can define a label dynamically @@ -122,7 +122,6 @@ class MyCustomNode(Node, MyCustomTreeNode): import nodeitems_utils from nodeitems_utils import NodeCategory, NodeItem - # our own base class with an appropriate poll function, # so the categories only show up in our own tree type class MyNodeCategory(NodeCategory): @@ -130,44 +129,50 @@ class MyNodeCategory(NodeCategory): def poll(cls, context): return context.space_data.tree_type == 'CustomTreeType' + # all categories in a list node_categories = [ # identifier, label, items list - MyNodeCategory("SOMENODES", "Some Nodes", items=[ + MyNodeCategory('SOMENODES', "Some Nodes", items=[ # our basic node NodeItem("CustomNodeType"), - ]), - MyNodeCategory("OTHERNODES", "Other Nodes", items=[ + ]), + MyNodeCategory('OTHERNODES', "Other Nodes", items=[ # the node item can have additional settings, # which are applied to new nodes # NB: settings values are stored as string expressions, # for this reason they should be converted to strings using repr() NodeItem("CustomNodeType", label="Node A", settings={ - "myStringProperty": repr("Lorem ipsum dolor sit amet"), - "myFloatProperty": repr(1.0), - }), + "my_string_prop": repr("Lorem ipsum dolor sit amet"), + "my_float_prop": repr(1.0), + }), NodeItem("CustomNodeType", label="Node B", settings={ - "myStringProperty": repr("consectetur adipisicing elit"), - "myFloatProperty": repr(2.0), - }), - ]), - ] - + "my_string_prop": repr("consectetur adipisicing elit"), + "my_float_prop": repr(2.0), + }), + ]), +] + +classes = ( + MyCustomTree, + MyCustomSocket, + MyCustomNode, +) def register(): - bpy.utils.register_class(MyCustomTree) - bpy.utils.register_class(MyCustomSocket) - bpy.utils.register_class(MyCustomNode) + from bpy.utils import register_class + for cls in classes: + register_class(cls) - nodeitems_utils.register_node_categories("CUSTOM_NODES", node_categories) + nodeitems_utils.register_node_categories('CUSTOM_NODES', node_categories) def unregister(): - nodeitems_utils.unregister_node_categories("CUSTOM_NODES") + nodeitems_utils.unregister_node_categories('CUSTOM_NODES') - bpy.utils.unregister_class(MyCustomTree) - bpy.utils.unregister_class(MyCustomSocket) - bpy.utils.unregister_class(MyCustomNode) + from bpy.utils import unregister_class + for cls in reversed(classes): + unregister_class(cls) if __name__ == "__main__": diff --git a/release/scripts/templates_py/gamelogic.py b/release/scripts/templates_py/gamelogic.py index 01ac27c56cd..e589ad43e63 100644 --- a/release/scripts/templates_py/gamelogic.py +++ b/release/scripts/templates_py/gamelogic.py @@ -62,7 +62,7 @@ def main(): # adding to our objects "life" property """ actu_collide = cont.sensors["collision_sens"] - for ob in actu_collide.objectHitList: + for ob in actu_collide.hitObjectList: # Check to see the object has this property if "life" in ob: own["life"] += ob["life"] diff --git a/release/text/copyright.txt b/release/text/copyright.txt index 207d6f54ea8..d0490b9ca91 100644 --- a/release/text/copyright.txt +++ b/release/text/copyright.txt @@ -21,7 +21,7 @@ Subject to the provisions of the GNU GPL license, BF grants You a non-exclusive right to use the Software at any computer You own or use. Artwork you create with the Software - whether it is images, movies, - scripts, exported 3d files or the .blend files themselves - is your sole + exported 3d files or the .blend files themselves - is your sole property, and can be licensed or sold under any conditions you prefer. 2. Permitted copying and electronic distribution of Software diff --git a/source/blender/quicktime/CMakeLists.txt b/release/windows/blendthumb/CMakeLists.txt index f853c35457f..1e5f5131a36 100644 --- a/source/blender/quicktime/CMakeLists.txt +++ b/release/windows/blendthumb/CMakeLists.txt @@ -23,40 +23,20 @@ # # ***** END GPL LICENSE BLOCK ***** -set(INC - . - ../avi - ../blenkernel - ../blenlib - ../imbuf - ../imbuf/intern - ../makesdna - ../makesrna - ../render/extern/include - ../windowmanager - ../../../intern/guardedalloc +#----------------------------------------------------------------------------- +cmake_minimum_required(VERSION 2.8) +project(BlendThumb) + +#Bring the headers, such as Student.h into the project +include_directories(${ZLIB_INCLUDE}) + +#Can manually add the sources using the set command as follows: +set(SOURCES src/BlenderThumb.cpp + src/BlendThumb.def + src/BlendThumb.rc + src/Dll.cpp ) - -set(INC_SYS - ${QUICKTIME_INCLUDE_DIRS} -) - -set(SRC - apple/qtkit_import.m - apple/qtkit_export.m - - quicktime_export.h - quicktime_import.h -) - -add_definitions(-DWITH_QUICKTIME) - -if(WITH_AUDASPACE) - add_definitions(${AUDASPACE_DEFINITIONS}) - - list(APPEND INC_SYS - ${AUDASPACE_C_INCLUDE_DIRS} - ) -endif() - -blender_add_lib(bf_quicktime "${SRC}" "${INC}" "${INC_SYS}") + +add_library(BlendThumb SHARED ${SOURCES}) +target_link_libraries(BlendThumb ${ZLIB_LIBS}) +install (TARGETS BlendThumb DESTINATION bin) diff --git a/release/windows/blendthumb/src/BlendThumb.def b/release/windows/blendthumb/src/BlendThumb.def new file mode 100644 index 00000000000..71f9236735f --- /dev/null +++ b/release/windows/blendthumb/src/BlendThumb.def @@ -0,0 +1,5 @@ +EXPORTS + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE
\ No newline at end of file diff --git a/release/windows/blendthumb/src/BlendThumb.rc b/release/windows/blendthumb/src/BlendThumb.rc new file mode 100644 index 00000000000..5dfd416b0c5 --- /dev/null +++ b/release/windows/blendthumb/src/BlendThumb.rc @@ -0,0 +1,26 @@ +#define IDR_VERSION1 1 + +IDR_VERSION1 VERSIONINFO +FILEVERSION 1,4,0,0 +PRODUCTVERSION 2,78,0,0 +FILEOS 0x00000004 +FILETYPE 0x00000002 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "FFFF04B0" + BEGIN + VALUE "FileVersion", "1.4\0" + VALUE "ProductVersion", "2.78\0" + VALUE "FileDescription", "Blender Thumbnail Handler\0" + VALUE "OriginalFilename", "BlendThumb.dll\0" + VALUE "ProductName", "Blender\0" + VALUE "LegalCopyright", "GPL2, 2016\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 0x04B0 + END +END + diff --git a/release/windows/blendthumb/src/BlenderThumb.cpp b/release/windows/blendthumb/src/BlenderThumb.cpp new file mode 100644 index 00000000000..508b9f74852 --- /dev/null +++ b/release/windows/blendthumb/src/BlenderThumb.cpp @@ -0,0 +1,324 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <shlwapi.h> +#include <thumbcache.h> // For IThumbnailProvider. +#include <new> + +#pragma comment(lib, "shlwapi.lib") + +// this thumbnail provider implements IInitializeWithStream to enable being hosted +// in an isolated process for robustness + +class CBlendThumb : public IInitializeWithStream, public IThumbnailProvider +{ +public: + CBlendThumb() : _cRef(1), _pStream(NULL) {} + + virtual ~CBlendThumb() + { + if (_pStream) + { + _pStream->Release(); + } + } + + // IUnknown + IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv) + { + static const QITAB qit[] = + { + QITABENT(CBlendThumb, IInitializeWithStream), + QITABENT(CBlendThumb, IThumbnailProvider), + { 0 }, + }; + return QISearch(this, qit, riid, ppv); + } + + IFACEMETHODIMP_(ULONG) AddRef() + { + return InterlockedIncrement(&_cRef); + } + + IFACEMETHODIMP_(ULONG) Release() + { + ULONG cRef = InterlockedDecrement(&_cRef); + if (!cRef) + { + delete this; + } + return cRef; + } + + // IInitializeWithStream + IFACEMETHODIMP Initialize(IStream *pStream, DWORD grfMode); + + // IThumbnailProvider + IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha); + +private: + long _cRef; + IStream *_pStream; // provided during initialization. +}; + +HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv) +{ + CBlendThumb *pNew = new (std::nothrow) CBlendThumb(); + HRESULT hr = pNew ? S_OK : E_OUTOFMEMORY; + if (SUCCEEDED(hr)) + { + hr = pNew->QueryInterface(riid, ppv); + pNew->Release(); + } + return hr; +} + +// IInitializeWithStream +IFACEMETHODIMP CBlendThumb::Initialize(IStream *pStream, DWORD) +{ + HRESULT hr = E_UNEXPECTED; // can only be inited once + if (_pStream == NULL) + { + // take a reference to the stream if we have not been inited yet + hr = pStream->QueryInterface(&_pStream); + } + return hr; +} + +#include <math.h> +#include <zlib.h> +#include "Wincodec.h" +const unsigned char gzip_magic[3] = { 0x1f, 0x8b, 0x08 }; + +// IThumbnailProvider +IFACEMETHODIMP CBlendThumb::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha) +{ + ULONG BytesRead; + HRESULT hr = S_FALSE; + LARGE_INTEGER SeekPos; + + // Compressed? + unsigned char in_magic[3]; + _pStream->Read(&in_magic,3,&BytesRead); + bool gzipped = true; + for ( int i=0; i < 3; i++ ) + if ( in_magic[i] != gzip_magic[i] ) + { + gzipped = false; + break; + } + + if (gzipped) + { + // Zlib inflate + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + + // Get compressed file length + SeekPos.QuadPart = 0; + _pStream->Seek(SeekPos,STREAM_SEEK_END,NULL); + + // Get compressed and uncompressed size + uLong source_size; + uLongf dest_size; + //SeekPos.QuadPart = -4; // last 4 bytes define size of uncompressed file + //ULARGE_INTEGER Tell; + //_pStream->Seek(SeekPos,STREAM_SEEK_END,&Tell); + //source_size = (uLong)Tell.QuadPart + 4; // src + //_pStream->Read(&dest_size,4,&BytesRead); // dest + dest_size = 1024*70; // thumbnail is currently always inside the first 65KB...if it moves or enlargens this line will have to change or go! + source_size = (uLong)max(SeekPos.QuadPart,dest_size); // for safety, assume no compression + + // Input + Bytef* src = new Bytef[source_size]; + stream.next_in = (Bytef*)src; + stream.avail_in = (uInt)source_size; + + // Output + Bytef* dest = new Bytef[dest_size]; + stream.next_out = (Bytef*)dest; + stream.avail_out = dest_size; + + // IStream to src + SeekPos.QuadPart = 0; + _pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL); + _pStream->Read(src,source_size,&BytesRead); + + // Do the inflation + int err; + err = inflateInit2(&stream,16); // 16 means "gzip"...nice! + err = inflate(&stream, Z_FINISH); + err = inflateEnd(&stream); + + // Replace the IStream, which is read-only + _pStream->Release(); + _pStream = SHCreateMemStream(dest,dest_size); + + delete[] src; + delete[] dest; + } + + // Blender version, early out if sub 2.5 + SeekPos.QuadPart = 9; + _pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL); + char version[4]; + version[3] = '\0'; + _pStream->Read(&version,3,&BytesRead); + if ( BytesRead != 3) + return E_UNEXPECTED; + int iVersion = atoi(version); + if ( iVersion < 250 ) + return S_FALSE; + + // 32 or 64 bit blend? + SeekPos.QuadPart = 7; + _pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL); + + char _PointerSize; + _pStream->Read(&_PointerSize,1,&BytesRead); + + int PointerSize = _PointerSize == '_' ? 4 : 8; + int HeaderSize = 16 + PointerSize; + + // Find and read thumbnail ("TEST") block + SeekPos.QuadPart = 12; + _pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL); + int BlockOffset = 12; + while ( _pStream ) + { + // Scan current block + char BlockName[5]; + BlockName[4] = '\0'; + int BlockSize = 0; + + if (_pStream->Read(BlockName,4,&BytesRead) == S_OK && _pStream->Read((void*)&BlockSize,4,&BytesRead) == S_OK) + { + if ( strcmp (BlockName,"TEST") != 0 ) + { + SeekPos.QuadPart = BlockOffset += HeaderSize + BlockSize; + _pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL); + continue; + } + } + else break; // eof + + // Found the block + SeekPos.QuadPart = BlockOffset + HeaderSize; + _pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL); + + int width, height; + _pStream->Read((char*)&width,4,&BytesRead); + _pStream->Read((char*)&height,4,&BytesRead); + BlockSize -= 8; + + // Isolate RGBA data + char* pRGBA = new char[BlockSize]; + _pStream->Read(pRGBA,BlockSize,&BytesRead); + + if (BytesRead != (ULONG)BlockSize) + return E_UNEXPECTED; + + // Convert to BGRA for Windows + for (int i=0; i < BlockSize; i+=4 ) + { + #define RED_BYTE pRGBA[i] + #define BLUE_BYTE pRGBA[i+2] + + char red = RED_BYTE; + RED_BYTE = BLUE_BYTE; + BLUE_BYTE = red; + } + + // Flip vertically (Blender stores it upside-down) + unsigned int LineSize = width*4; + char* FlippedImage = new char[BlockSize]; + for (int i=0; i<height; i++) + { + if ( 0 != memcpy_s(&FlippedImage[ (height - i - 1)*LineSize ],LineSize,&pRGBA[ i*LineSize ],LineSize)) + return E_UNEXPECTED; + } + delete[] pRGBA; + pRGBA = FlippedImage; + + // Create image + *phbmp = CreateBitmap(width,height,1,32,pRGBA); + if (!*phbmp) + return E_FAIL; + *pdwAlpha = WTSAT_ARGB; // it's actually BGRA, not sure why this works + + // Scale down if required + if ( (unsigned)width > cx || (unsigned)height > cx ) + { + float scale = 1.0f / (max(width,height) / (float)cx); + LONG NewWidth = (LONG)(width *scale); + LONG NewHeight = (LONG)(height *scale); + +#ifdef _DEBUG +#if 1 + MessageBox(0,L"Attach now",L"Debugging",MB_OK); +#endif +#endif + IWICImagingFactory *pImgFac; + hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pImgFac)); + + IWICBitmap* WICBmp; + hr = pImgFac->CreateBitmapFromHBITMAP(*phbmp,0,WICBitmapUseAlpha,&WICBmp); + + BITMAPINFO bmi = {}; + bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); + bmi.bmiHeader.biWidth = NewWidth; + bmi.bmiHeader.biHeight = -NewHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + + BYTE *pBits; + HBITMAP ResizedHBmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&pBits, NULL, 0); + hr = ResizedHBmp ? S_OK : E_OUTOFMEMORY; + if (SUCCEEDED(hr)) + { + IWICBitmapScaler* pIScaler; + hr = pImgFac->CreateBitmapScaler(&pIScaler); + hr = pIScaler->Initialize(WICBmp,NewWidth,NewHeight,WICBitmapInterpolationModeFant); + + WICRect rect = {0, 0, NewWidth, NewHeight}; + hr = pIScaler->CopyPixels(&rect, NewWidth * 4, NewWidth * NewHeight * 4, pBits); + + if (SUCCEEDED(hr)) + { + DeleteObject(*phbmp); + *phbmp = ResizedHBmp; + } + else + DeleteObject(ResizedHBmp); + + pIScaler->Release(); + } + WICBmp->Release(); + pImgFac->Release(); + } + else + hr = S_OK; + break; + } + return hr; +} diff --git a/release/windows/blendthumb/src/Dll.cpp b/release/windows/blendthumb/src/Dll.cpp new file mode 100644 index 00000000000..09ccd34ff8e --- /dev/null +++ b/release/windows/blendthumb/src/Dll.cpp @@ -0,0 +1,277 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <objbase.h> +#include <shlwapi.h> +#include <thumbcache.h> // For IThumbnailProvider. +#include <shlobj.h> // For SHChangeNotify +#include <new> + +extern HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv); + +#define SZ_CLSID_BLENDTHUMBHANDLER L"{D45F043D-F17F-4e8a-8435-70971D9FA46D}" +#define SZ_BLENDTHUMBHANDLER L"Blender Thumbnail Handler" +const CLSID CLSID_BlendThumbHandler = { 0xd45f043d, 0xf17f, 0x4e8a, { 0x84, 0x35, 0x70, 0x97, 0x1d, 0x9f, 0xa4, 0x6d } }; + +typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void **ppvObject); +struct CLASS_OBJECT_INIT +{ + const CLSID *pClsid; + PFNCREATEINSTANCE pfnCreate; +}; + +// add classes supported by this module here +const CLASS_OBJECT_INIT c_rgClassObjectInit[] = +{ + { &CLSID_BlendThumbHandler, CBlendThumb_CreateInstance } +}; + + +long g_cRefModule = 0; + +// Handle the the DLL's module +HINSTANCE g_hInst = NULL; + +// Standard DLL functions +STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void *) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + g_hInst = hInstance; + DisableThreadLibraryCalls(hInstance); + } + return TRUE; +} + +STDAPI DllCanUnloadNow() +{ + // Only allow the DLL to be unloaded after all outstanding references have been released + return (g_cRefModule == 0) ? S_OK : S_FALSE; +} + +void DllAddRef() +{ + InterlockedIncrement(&g_cRefModule); +} + +void DllRelease() +{ + InterlockedDecrement(&g_cRefModule); +} + +class CClassFactory : public IClassFactory +{ +public: + static HRESULT CreateInstance(REFCLSID clsid, const CLASS_OBJECT_INIT *pClassObjectInits, size_t cClassObjectInits, REFIID riid, void **ppv) + { + *ppv = NULL; + HRESULT hr = CLASS_E_CLASSNOTAVAILABLE; + for (size_t i = 0; i < cClassObjectInits; i++) + { + if (clsid == *pClassObjectInits[i].pClsid) + { + IClassFactory *pClassFactory = new (std::nothrow) CClassFactory(pClassObjectInits[i].pfnCreate); + hr = pClassFactory ? S_OK : E_OUTOFMEMORY; + if (SUCCEEDED(hr)) + { + hr = pClassFactory->QueryInterface(riid, ppv); + pClassFactory->Release(); + } + break; // match found + } + } + return hr; + } + + CClassFactory(PFNCREATEINSTANCE pfnCreate) : _cRef(1), _pfnCreate(pfnCreate) + { + DllAddRef(); + } + + // IUnknown + IFACEMETHODIMP QueryInterface(REFIID riid, void ** ppv) + { + static const QITAB qit[] = + { + QITABENT(CClassFactory, IClassFactory), + { 0 } + }; + return QISearch(this, qit, riid, ppv); + } + + IFACEMETHODIMP_(ULONG) AddRef() + { + return InterlockedIncrement(&_cRef); + } + + IFACEMETHODIMP_(ULONG) Release() + { + long cRef = InterlockedDecrement(&_cRef); + if (cRef == 0) + { + delete this; + } + return cRef; + } + + // IClassFactory + IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv) + { + return punkOuter ? CLASS_E_NOAGGREGATION : _pfnCreate(riid, ppv); + } + + IFACEMETHODIMP LockServer(BOOL fLock) + { + if (fLock) + { + DllAddRef(); + } + else + { + DllRelease(); + } + return S_OK; + } + +private: + ~CClassFactory() + { + DllRelease(); + } + + long _cRef; + PFNCREATEINSTANCE _pfnCreate; +}; + +STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv) +{ + return CClassFactory::CreateInstance(clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv); +} + +// A struct to hold the information required for a registry entry + +struct REGISTRY_ENTRY +{ + HKEY hkeyRoot; + PCWSTR pszKeyName; + PCWSTR pszValueName; + DWORD dwValueType; + PCWSTR pszData; +}; + +// Creates a registry key (if needed) and sets the default value of the key + +HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry) +{ + HKEY hKey; + HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(pRegistryEntry->hkeyRoot, pRegistryEntry->pszKeyName, + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL)); + if (SUCCEEDED(hr)) + { + // All this just to support REG_DWORD... + DWORD size; + DWORD data; + BYTE* lpData = (LPBYTE) pRegistryEntry->pszData; + switch (pRegistryEntry->dwValueType) + { + case REG_SZ: + size = ((DWORD) wcslen(pRegistryEntry->pszData) + 1) * sizeof(WCHAR); + break; + case REG_DWORD: + size = sizeof(DWORD); + data = (DWORD)pRegistryEntry->pszData; + lpData = (BYTE*)&data; + break; + default: + return E_INVALIDARG; + } + + hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, pRegistryEntry->pszValueName, 0, pRegistryEntry->dwValueType, + lpData, size )); + RegCloseKey(hKey); + } + return hr; +} + +// +// Registers this COM server +// +STDAPI DllRegisterServer() +{ + HRESULT hr; + + WCHAR szModuleName[MAX_PATH]; + + if (!GetModuleFileNameW(g_hInst, szModuleName, ARRAYSIZE(szModuleName))) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + else + { + const REGISTRY_ENTRY rgRegistryEntries[] = + { + // RootKey KeyName ValueName ValueType Data + {HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER, NULL, REG_SZ, SZ_BLENDTHUMBHANDLER}, + {HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32", NULL, REG_SZ, szModuleName}, + {HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32", L"ThreadingModel", REG_SZ, L"Apartment"}, + {HKEY_CURRENT_USER, L"Software\\Classes\\.blend\\", L"Treatment", REG_DWORD, 0}, // doesn't appear to do anything... + {HKEY_CURRENT_USER, L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", NULL, REG_SZ, SZ_CLSID_BLENDTHUMBHANDLER}, + }; + + hr = S_OK; + for (int i = 0; i < ARRAYSIZE(rgRegistryEntries) && SUCCEEDED(hr); i++) + { + hr = CreateRegKeyAndSetValue(&rgRegistryEntries[i]); + } + } + if (SUCCEEDED(hr)) + { + // This tells the shell to invalidate the thumbnail cache. This is important because any .blend files + // viewed before registering this handler would otherwise show cached blank thumbnails. + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); + } + return hr; +} + +// +// Unregisters this COM server +// +STDAPI DllUnregisterServer() +{ + HRESULT hr = S_OK; + + const PCWSTR rgpszKeys[] = + { + L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER, + L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}" + }; + + // Delete the registry entries + for (int i = 0; i < ARRAYSIZE(rgpszKeys) && SUCCEEDED(hr); i++) + { + hr = HRESULT_FROM_WIN32(RegDeleteTreeW(HKEY_CURRENT_USER, rgpszKeys[i])); + if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) + { + // If the registry entry has already been deleted, say S_OK. + hr = S_OK; + } + } + return hr; +} diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index 6f2b78e0845..818d4cd3d89 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -138,10 +138,6 @@ if(WITH_CODEC_AVI) add_subdirectory(avi) endif() -if(WITH_CODEC_QUICKTIME) - add_subdirectory(quicktime) -endif() - if(WITH_PYTHON) add_subdirectory(python) endif() diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc index 1d2bc689027..d6e7a80d174 100644 --- a/source/blender/alembic/intern/abc_customdata.cc +++ b/source/blender/alembic/intern/abc_customdata.cc @@ -252,7 +252,31 @@ static void read_uvs(const CDStreamConfig &config, void *data, } } -static void read_custom_data_mcols(const ICompoundProperty &arbGeomParams, +static size_t mcols_out_of_bounds_check( + const size_t color_index, + const size_t array_size, + const std::string & iobject_full_name, + const PropertyHeader &prop_header, + bool &r_bounds_warning_given) +{ + if (color_index < array_size) { + return color_index; + } + + if (!r_bounds_warning_given) { + std::cerr << "Alembic: color index out of bounds " + "reading face colors for object " + << iobject_full_name + << ", property " + << prop_header.getName() << std::endl; + r_bounds_warning_given = true; + } + + return 0; +} + +static void read_custom_data_mcols(const std::string & iobject_full_name, + const ICompoundProperty &arbGeomParams, const PropertyHeader &prop_header, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss) @@ -303,6 +327,8 @@ static void read_custom_data_mcols(const ICompoundProperty &arbGeomParams, size_t face_index = 0; size_t color_index; + bool bounds_warning_given = false; + for (int i = 0; i < config.totpoly; ++i) { MPoly *poly = &mpolys[i]; MCol *cface = &cfaces[poly->loopstart + poly->totloop]; @@ -311,9 +337,14 @@ static void read_custom_data_mcols(const ICompoundProperty &arbGeomParams, for (int j = 0; j < poly->totloop; ++j, ++face_index) { --cface; --mloop; - color_index = is_facevarying ? face_index : mloop->v; if (use_c3f_ptr) { + color_index = mcols_out_of_bounds_check( + is_facevarying ? face_index : mloop->v, + c3f_ptr->size(), + iobject_full_name, prop_header, + bounds_warning_given); + const Imath::C3f &color = (*c3f_ptr)[color_index]; cface->a = FTOCHAR(color[0]); cface->r = FTOCHAR(color[1]); @@ -321,6 +352,12 @@ static void read_custom_data_mcols(const ICompoundProperty &arbGeomParams, cface->b = 255; } else { + color_index = mcols_out_of_bounds_check( + is_facevarying ? face_index : mloop->v, + c4f_ptr->size(), + iobject_full_name, prop_header, + bounds_warning_given); + const Imath::C4f &color = (*c4f_ptr)[color_index]; cface->a = FTOCHAR(color[0]); cface->r = FTOCHAR(color[1]); @@ -356,7 +393,10 @@ static void read_custom_data_uvs(const ICompoundProperty &prop, read_uvs(config, cd_data, sample.getVals(), sample.getIndices()); } -void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss) +void read_custom_data(const std::string & iobject_full_name, + const ICompoundProperty &prop, + const CDStreamConfig &config, + const Alembic::Abc::ISampleSelector &iss) { if (!prop.valid()) { return; @@ -386,7 +426,7 @@ void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &confi continue; } - read_custom_data_mcols(prop, prop_header, config, iss); + read_custom_data_mcols(iobject_full_name, prop, prop_header, config, iss); continue; } } diff --git a/source/blender/alembic/intern/abc_customdata.h b/source/blender/alembic/intern/abc_customdata.h index 9e671fde386..b3072a2c9f7 100644 --- a/source/blender/alembic/intern/abc_customdata.h +++ b/source/blender/alembic/intern/abc_customdata.h @@ -96,7 +96,8 @@ void write_custom_data(const OCompoundProperty &prop, CustomData *data, int data_type); -void read_custom_data(const ICompoundProperty &prop, +void read_custom_data(const std::string & iobject_full_name, + const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss); diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index 9a4ca6f99a8..6545ced8e4a 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -681,17 +681,17 @@ static void assign_materials(Main *bmain, Object *ob, const std::map<std::string std::string mat_name = it->first; mat_iter = mat_map.find(mat_name.c_str()); - Material *assigned_name; + Material *assigned_mat; if (mat_iter == mat_map.end()) { - assigned_name = BKE_material_add(bmain, mat_name.c_str()); - mat_map[mat_name] = assigned_name; + assigned_mat = BKE_material_add(bmain, mat_name.c_str()); + mat_map[mat_name] = assigned_mat; } else { - assigned_name = mat_iter->second; + assigned_mat = mat_iter->second; } - assign_material(ob, assigned_name, it->second, BKE_MAT_ASSIGN_OBDATA); + assign_material(ob, assigned_mat, it->second, BKE_MAT_ASSIGN_OBDATA); } } } @@ -943,7 +943,8 @@ static void get_weight_and_index(CDStreamConfig &config, config.ceil_index = i1; } -static void read_mesh_sample(ImportSettings *settings, +static void read_mesh_sample(const std::string & iobject_full_name, + ImportSettings *settings, const IPolyMeshSchema &schema, const ISampleSelector &selector, CDStreamConfig &config, @@ -981,10 +982,9 @@ static void read_mesh_sample(ImportSettings *settings, } if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { - read_custom_data(schema.getArbGeomParams(), config, selector); + read_custom_data(iobject_full_name, + schema.getArbGeomParams(), config, selector); } - - /* TODO: face sets */ } CDStreamConfig get_config(DerivedMesh *dm) @@ -1112,7 +1112,8 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, config.time = sample_sel.getRequestedTime(); bool do_normals = false; - read_mesh_sample(&settings, m_schema, sample_sel, config, do_normals); + read_mesh_sample(m_iobject.getFullName(), + &settings, m_schema, sample_sel, config, do_normals); if (new_dm) { /* Check if we had ME_SMOOTH flag set to restore it. */ @@ -1123,6 +1124,16 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, CDDM_calc_normals(new_dm); CDDM_calc_edges(new_dm); + /* Here we assume that the number of materials doesn't change, i.e. that + * the material slots that were created when the object was loaded from + * Alembic are still valid now. */ + size_t num_polys = new_dm->getNumPolys(new_dm); + if (num_polys > 0) { + MPoly *dmpolies = new_dm->getPolyArray(new_dm); + std::map<std::string, int> mat_map; + assign_facesets_to_mpoly(sample_sel, 0, dmpolies, num_polys, mat_map); + } + return new_dm; } @@ -1133,8 +1144,11 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, return dm; } -void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, - const ISampleSelector &sample_sel) +void AbcMeshReader::assign_facesets_to_mpoly( + const ISampleSelector &sample_sel, + size_t poly_start, + MPoly *mpoly, int totpoly, + std::map<std::string, int> & r_mat_map) { std::vector<std::string> face_sets; m_schema.getFaceSetNames(face_sets); @@ -1143,21 +1157,21 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_star return; } - std::map<std::string, int> mat_map; int current_mat = 0; for (int i = 0; i < face_sets.size(); ++i) { const std::string &grp_name = face_sets[i]; - if (mat_map.find(grp_name) == mat_map.end()) { - mat_map[grp_name] = 1 + current_mat++; + if (r_mat_map.find(grp_name) == r_mat_map.end()) { + r_mat_map[grp_name] = 1 + current_mat++; } - const int assigned_mat = mat_map[grp_name]; + const int assigned_mat = r_mat_map[grp_name]; const IFaceSet faceset = m_schema.getFaceSet(grp_name); if (!faceset.valid()) { + std::cerr << " Face set " << grp_name << " invalid for " << m_object_name << "\n"; continue; } @@ -1169,16 +1183,25 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_star for (size_t l = 0; l < num_group_faces; l++) { size_t pos = (*group_faces)[l] + poly_start; - if (pos >= mesh->totpoly) { + if (pos >= totpoly) { std::cerr << "Faceset overflow on " << faceset.getName() << '\n'; break; } - MPoly &poly = mesh->mpoly[pos]; + MPoly &poly = mpoly[pos]; poly.mat_nr = assigned_mat - 1; } } +} + +void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, + const ISampleSelector &sample_sel) +{ + std::map<std::string, int> mat_map; + assign_facesets_to_mpoly(sample_sel, + poly_start, mesh->mpoly, mesh->totpoly, + mat_map); utils::assign_materials(bmain, m_object, mat_map); } @@ -1197,7 +1220,8 @@ ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2) return NULL; } -static void read_subd_sample(ImportSettings *settings, +static void read_subd_sample(const std::string & iobject_full_name, + ImportSettings *settings, const ISubDSchema &schema, const ISampleSelector &selector, CDStreamConfig &config) @@ -1232,10 +1256,9 @@ static void read_subd_sample(ImportSettings *settings, } if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { - read_custom_data(schema.getArbGeomParams(), config, selector); + read_custom_data(iobject_full_name, + schema.getArbGeomParams(), config, selector); } - - /* TODO: face sets */ } /* ************************************************************************** */ @@ -1364,7 +1387,8 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, /* Only read point data when streaming meshes, unless we need to create new ones. */ CDStreamConfig config = get_config(new_dm ? new_dm : dm); config.time = sample_sel.getRequestedTime(); - read_subd_sample(&settings, m_schema, sample_sel, config); + read_subd_sample(m_iobject.getFullName(), + &settings, m_schema, sample_sel, config); if (new_dm) { /* Check if we had ME_SMOOTH flag set to restore it. */ diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h index 6bf1dde3d1d..5c1eb01d8e0 100644 --- a/source/blender/alembic/intern/abc_mesh.h +++ b/source/blender/alembic/intern/abc_mesh.h @@ -112,6 +112,11 @@ public: private: void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, const Alembic::AbcGeom::ISampleSelector &sample_sel); + + void assign_facesets_to_mpoly(const Alembic::Abc::ISampleSelector &sample_sel, + size_t poly_start, + MPoly *mpoly, int totpoly, + std::map<std::string, int> & r_mat_map); }; /* ************************************************************************** */ diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index 26eb7620fb1..24a508e8292 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -370,10 +370,10 @@ AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSe reader = new AbcCurveReader(object, settings); } else { - std::cerr << "Alembic: unknown how to handle objects of schema " + std::cerr << "Alembic: unknown how to handle objects of schema '" << md.get("schemaObjTitle") - << ", skipping object " - << object.getFullName() << std::endl; + << "', skipping object '" + << object.getFullName() << "'" << std::endl; } return reader; diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index bee8e92e969..5503dcb1527 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -990,6 +990,10 @@ CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, CacheRead ImportSettings settings; AbcObjectReader *abc_reader = create_reader(iobject, settings); + if (abc_reader == NULL) { + /* This object is not supported */ + return NULL; + } abc_reader->object(object); abc_reader->incref(); diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 63ff1149a68..700bfe568f1 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -193,7 +193,9 @@ struct DerivedMesh { * \warning Typical access is done via #getLoopTriArray, #getNumLoopTri. */ struct { - struct MLoopTri *array; + /* WARNING! swapping between array (ready-to-be-used data) and array_wip (where data is actually computed) + * shall always be protected by same lock as one used for looptris computing. */ + struct MLoopTri *array, *array_wip; int num; int num_alloc; } looptris; @@ -220,7 +222,7 @@ struct DerivedMesh { /** Recalculates mesh tessellation */ void (*recalcTessellation)(DerivedMesh *dm); - /** Loop tessellation cache */ + /** Loop tessellation cache (WARNING! Only call inside threading-protected code!) */ void (*recalcLoopTri)(DerivedMesh *dm); /** accessor functions */ const struct MLoopTri *(*getLoopTriArray)(DerivedMesh * dm); @@ -625,7 +627,6 @@ void DM_ensure_normals(DerivedMesh *dm); void DM_ensure_tessface(DerivedMesh *dm); void DM_ensure_looptri_data(DerivedMesh *dm); -void DM_ensure_looptri(DerivedMesh *dm); void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num); void DM_update_tessface_data(DerivedMesh *dm); @@ -832,11 +833,5 @@ struct MEdge *DM_get_edge_array(struct DerivedMesh *dm, bool *r_allocated); struct MLoop *DM_get_loop_array(struct DerivedMesh *dm, bool *r_allocated); struct MPoly *DM_get_poly_array(struct DerivedMesh *dm, bool *r_allocated); struct MFace *DM_get_tessface_array(struct DerivedMesh *dm, bool *r_allocated); -const MLoopTri *DM_get_looptri_array( - DerivedMesh *dm, - const MVert *mvert, - const MPoly *mpoly, int mpoly_len, - const MLoop *mloop, int mloop_len, - bool *r_allocated); #endif /* __BKE_DERIVEDMESH_H__ */ diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 5db0c3c9130..28be2b04c71 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -57,8 +57,9 @@ extern "C" { /* Allocate a new bAction with the given name */ struct bAction *add_empty_action(struct Main *bmain, const char name[]); -/* Allocate a copy of the given Action and all its data */ -struct bAction *BKE_action_copy(struct Main *bmain, const struct bAction *src); +void BKE_action_copy_data(struct Main *bmain, struct bAction *act_dst, const struct bAction *act_src, const int flag); +/* Allocate a copy of the given Action and all its data */ +struct bAction *BKE_action_copy(struct Main *bmain, const struct bAction *act_src); /* Deallocate all of the Action's data, but not the Action itself */ void BKE_action_free(struct bAction *act); @@ -150,6 +151,7 @@ void BKE_pose_free_data_ex(struct bPose *pose, bool do_id_user); void BKE_pose_free_data(struct bPose *pose); void BKE_pose_free(struct bPose *pose); void BKE_pose_free_ex(struct bPose *pose, bool do_id_user); +void BKE_pose_copy_data_ex(struct bPose **dst, const struct bPose *src, const int flag, const bool copy_constraints); void BKE_pose_copy_data(struct bPose **dst, const struct bPose *src, const bool copy_constraints); void BKE_pose_channel_copy_data(struct bPoseChannel *pchan, const struct bPoseChannel *pchan_from); struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name); diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 420ae4bb12d..534a57765f6 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -67,10 +67,10 @@ bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct b void BKE_animdata_free(struct ID *id, const bool do_id_user); /* Copy AnimData */ -struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action); +struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const bool do_action); /* Copy AnimData */ -bool BKE_animdata_copy_id(struct ID *id_to, struct ID *id_from, const bool do_action); +bool BKE_animdata_copy_id(struct Main *bmain, struct ID *id_to, struct ID *id_from, const bool do_action); /* Copy AnimData Actions */ void BKE_animdata_copy_id_action(struct ID *id, const bool set_newid); @@ -102,7 +102,7 @@ struct KS_Path *BKE_keyingset_add_path(struct KeyingSet *ks, struct ID *id, cons struct KS_Path *BKE_keyingset_find_path(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, int group_mode); /* Copy all KeyingSets in the given list */ -void BKE_keyingsets_copy(struct ListBase *newlist, struct ListBase *list); +void BKE_keyingsets_copy(struct ListBase *newlist, const struct ListBase *list); /* Free the given Keying Set path */ void BKE_keyingset_free_path(struct KeyingSet *ks, struct KS_Path *ksp); diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 6bfc8c918d6..60fb79d75d5 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -77,6 +77,7 @@ int BKE_armature_bonelist_count(struct ListBase *lb); void BKE_armature_bonelist_free(struct ListBase *lb); void BKE_armature_free(struct bArmature *arm); void BKE_armature_make_local(struct Main *bmain, struct bArmature *arm, const bool lib_local); +void BKE_armature_copy_data(struct Main *bmain, struct bArmature *arm_dst, const struct bArmature *arm_src, const int flag); struct bArmature *BKE_armature_copy(struct Main *bmain, const struct bArmature *arm); /* Bounding box. */ @@ -171,6 +172,11 @@ void BKE_pose_eval_init(struct EvaluationContext *eval_ctx, struct Object *ob, struct bPose *pose); +void BKE_pose_eval_init_ik(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob, + struct bPose *pose); + void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 207631d36bd..f95b1963a91 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,8 +27,8 @@ /* these lines are grep'd, watch out for our not-so-awesome regex * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ -#define BLENDER_VERSION 278 -#define BLENDER_SUBVERSION 5 +#define BLENDER_VERSION 279 +#define BLENDER_SUBVERSION 1 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 42e4e73f2d5..dedb75a080a 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -44,6 +44,7 @@ void BKE_brush_system_exit(void); void BKE_brush_init(struct Brush *brush); struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode); struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode); +void BKE_brush_copy_data(struct Main *bmain, struct Brush *brush_dst, const struct Brush *brush_src, const int flag); struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush); void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local); void BKE_brush_unlink(struct Main *bmain, struct Brush *brush); diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h index f1e643c4a19..e9712681090 100644 --- a/source/blender/blenkernel/BKE_cachefile.h +++ b/source/blender/blenkernel/BKE_cachefile.h @@ -47,6 +47,8 @@ void BKE_cachefile_init(struct CacheFile *cache_file); void BKE_cachefile_free(struct CacheFile *cache_file); +void BKE_cachefile_copy_data( + struct Main *bmain, struct CacheFile *cache_file_dst, const struct CacheFile *cache_file_src, const int flag); struct CacheFile *BKE_cachefile_copy(struct Main *bmain, const struct CacheFile *cache_file); void BKE_cachefile_make_local(struct Main *bmain, struct CacheFile *cache_file, const bool lib_local); diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index b2f22aacb28..04dee70faa6 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -52,6 +52,7 @@ struct GPUFXSettings; void BKE_camera_init(struct Camera *cam); void *BKE_camera_add(struct Main *bmain, const char *name); +void BKE_camera_copy_data(struct Main *bmain, struct Camera *cam_dst, const struct Camera *cam_src, const int flag); struct Camera *BKE_camera_copy(struct Main *bmain, const struct Camera *cam); void BKE_camera_make_local(struct Main *bmain, struct Camera *cam, const bool lib_local); void BKE_camera_free(struct Camera *ca); diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 047d1787f76..4e0eb5c65ac 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -120,6 +120,7 @@ void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list); void BKE_constraints_free(struct ListBase *list); void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user); void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern); +void BKE_constraints_copy_ex(struct ListBase *dst, const struct ListBase *src, const int flag, bool do_extern); void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void *userdata); void BKE_constraint_free_data(struct bConstraint *con); void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user); diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 635e999dd95..a900ba43443 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -78,6 +78,7 @@ void BKE_curve_free(struct Curve *cu); void BKE_curve_editfont_free(struct Curve *cu); void BKE_curve_init(struct Curve *cu); struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type); +void BKE_curve_copy_data(struct Main *bmain, struct Curve *cu_dst, const struct Curve *cu_src, const int flag); struct Curve *BKE_curve_copy(struct Main *bmain, const struct Curve *cu); void BKE_curve_make_local(struct Main *bmain, struct Curve *cu, const bool lib_local); short BKE_curve_type_get(struct Curve *cu); @@ -92,8 +93,8 @@ void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_rot[3], fl bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]); bool BKE_curve_center_median(struct Curve *cu, float cent[3]); bool BKE_curve_center_bounds(struct Curve *cu, float cent[3]); -void BKE_curve_transform_ex(struct Curve *cu, float mat[4][4], const bool do_keys, const float unit_scale); -void BKE_curve_transform(struct Curve *cu, float mat[4][4], const bool do_keys); +void BKE_curve_transform_ex(struct Curve *cu, float mat[4][4], const bool do_keys, const bool do_props, const float unit_scale); +void BKE_curve_transform(struct Curve *cu, float mat[4][4], const bool do_keys, const bool do_props); void BKE_curve_translate(struct Curve *cu, float offset[3], const bool do_keys); void BKE_curve_material_index_remove(struct Curve *cu, int index); void BKE_curve_material_index_clear(struct Curve *cu); @@ -217,7 +218,4 @@ struct EvaluationContext; void BKE_curve_eval_geometry(struct EvaluationContext *eval_ctx, struct Curve *curve); -void BKE_curve_eval_path(struct EvaluationContext *eval_ctx, - struct Curve *curve); - #endif /* __BKE_CURVE_H__ */ diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h index e7ae0f606e7..60ad061bf77 100644 --- a/source/blender/blenkernel/BKE_font.h +++ b/source/blender/blenkernel/BKE_font.h @@ -78,6 +78,7 @@ void BKE_vfont_builtin_register(void *mem, int size); void BKE_vfont_free_data(struct VFont *vfont); void BKE_vfont_free(struct VFont *sc); void BKE_vfont_init(struct VFont *vfont); +void BKE_vfont_copy_data(struct Main *bmain, struct VFont *vfont_dst, const struct VFont *vfont_src, const int flag); struct VFont *BKE_vfont_builtin_get(void); struct VFont *BKE_vfont_load(struct Main *bmain, const char *filepath); struct VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists); diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h index 50407f3bdfc..1045fde0039 100644 --- a/source/blender/blenkernel/BKE_freestyle.h +++ b/source/blender/blenkernel/BKE_freestyle.h @@ -50,7 +50,7 @@ typedef struct FreestyleModuleSettings FreestyleModuleSettings; /* FreestyleConfig */ void BKE_freestyle_config_init(FreestyleConfig *config); void BKE_freestyle_config_free(FreestyleConfig *config); -void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config); +void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag); /* FreestyleConfig.modules */ FreestyleModuleConfig *BKE_freestyle_module_add(FreestyleConfig *config); diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index 830518906ab..790c8051ace 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -83,8 +83,6 @@ typedef struct Global { /* debug flag, G_DEBUG, G_DEBUG_PYTHON & friends, set python or command line args */ int debug; - bool have_quicktime; - /* this variable is written to / read from FileGlobal->fileflags */ int fileflags; diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index bdd28baf137..b6de922c245 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -60,6 +60,7 @@ struct bGPdata *BKE_gpencil_data_addnew(const char name[]); struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src); struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src); +void BKE_gpencil_copy_data(struct Main *bmain, struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag); struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, const struct bGPdata *gpd, bool internal_copy); void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local); diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index 684251c9561..404d1704c78 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -42,6 +42,7 @@ struct Scene; void BKE_group_free(struct Group *group); struct Group *BKE_group_add(struct Main *bmain, const char *name); +void BKE_group_copy_data(struct Main *bmain, struct Group *group_dst, const struct Group *group_src, const int flag); struct Group *BKE_group_copy(struct Main *bmain, const struct Group *group); void BKE_group_make_local(struct Main *bmain, struct Group *group, const bool lib_local); bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index ab8728faedb..5d8cd02756d 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -58,7 +58,7 @@ typedef union IDPropertyTemplate { /* ----------- Property Array Type ---------- */ IDProperty *IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -IDProperty *IDP_CopyIDPArray(const IDProperty *array) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* shallow copies item */ void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item) ATTR_NONNULL(); @@ -103,6 +103,7 @@ IDProperty *IDP_GetPropertyTypeFromGroup(struct IDProperty *prop, const char *na /*-------- Main Functions --------*/ struct IDProperty *IDP_GetProperties(struct ID *id, const bool create_if_needed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); struct IDProperty *IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +struct IDProperty *IDP_CopyProperty_ex(const struct IDProperty *prop, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is_strict) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index e155b0719cc..3c716f39dd0 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -58,6 +58,7 @@ void BKE_images_exit(void); void BKE_image_free_packedfiles(struct Image *image); void BKE_image_free_views(struct Image *image); void BKE_image_free_buffers(struct Image *image); +void BKE_image_free_buffers_ex(struct Image *image, bool do_lock); /* call from library */ void BKE_image_free(struct Image *image); @@ -250,6 +251,7 @@ void BKE_image_packfiles_from_mem(struct ReportList *reports, struct Image *ima, void BKE_image_print_memlist(void); /* empty image block, of similar type and filename */ +void BKE_image_copy_data(struct Main *bmain, struct Image *ima_dst, const struct Image *ima_src, const int flag); struct Image *BKE_image_copy(struct Main *bmain, const struct Image *ima); /* merge source into dest, and free source */ diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 94e8a24fbc5..5eef44ef896 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -51,6 +51,7 @@ extern "C" { void BKE_key_free(struct Key *sc); void BKE_key_free_nolib(struct Key *key); struct Key *BKE_key_add(struct ID *id); +void BKE_key_copy_data(struct Main *bmain, struct Key *key_dst, const struct Key *key_src, const int flag); struct Key *BKE_key_copy(struct Main *bmain, const struct Key *key); struct Key *BKE_key_copy_nolib(struct Key *key); void BKE_key_sort(struct Key *key); diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h index 713ca80fb1a..b68da654520 100644 --- a/source/blender/blenkernel/BKE_lamp.h +++ b/source/blender/blenkernel/BKE_lamp.h @@ -44,6 +44,7 @@ struct Scene; void BKE_lamp_init(struct Lamp *la); struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT; +void BKE_lamp_copy_data(struct Main *bmain, struct Lamp *la_dst, const struct Lamp *la_src, const int flag); struct Lamp *BKE_lamp_copy(struct Main *bmain, const struct Lamp *la) ATTR_WARN_UNUSED_RESULT; struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la, const bool lib_local); diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index ec1cf79832d..f7d006785d2 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -47,6 +47,7 @@ struct MDeformVert; void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb); void BKE_lattice_init(struct Lattice *lt); struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name); +void BKE_lattice_copy_data(struct Main *bmain, struct Lattice *lt_dst, const struct Lattice *lt_src, const int flag); struct Lattice *BKE_lattice_copy(struct Main *bmain, const struct Lattice *lt); void BKE_lattice_free(struct Lattice *lt); void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool lib_local); diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 258dcc84449..b5104b35b3c 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -52,11 +52,38 @@ struct PropertyRNA; size_t BKE_libblock_get_alloc_info(short type, const char **name); void *BKE_libblock_alloc_notest(short type); -void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BKE_libblock_init_empty(struct ID *id); + +/** + * New ID creation/copying options. + */ +enum { + /* *** Generic options (should be handled by all ID types copying, ID creation, etc.). *** */ + /* Create datablock outside of any main database - similar to 'localize' functions of materials etc. */ + LIB_ID_CREATE_NO_MAIN = 1 << 0, + /* Do not affect user refcount of datablocks used by new one (which also gets zero usercount then). + * Implies LIB_ID_CREATE_NO_MAIN. */ + LIB_ID_CREATE_NO_USER_REFCOUNT = 1 << 1, + /* Assume given 'newid' already points to allocated memory for whole datablock (ID + data) - USE WITH CAUTION! + * Implies LIB_ID_CREATE_NO_MAIN. */ + LIB_ID_CREATE_NO_ALLOCATE = 1 << 2, + + LIB_ID_CREATE_NO_DEG_TAG = 1 << 8, /* Do not tag new ID for update in depsgraph. */ + + /* Specific options to some ID types or usages, may be ignored by unrelated ID copying functions. */ + LIB_ID_COPY_NO_PROXY_CLEAR = 1 << 16, /* Object only, needed by make_local code. */ + LIB_ID_COPY_NO_PREVIEW = 1 << 17, /* Do not copy preview data, when supported. */ + LIB_ID_COPY_CACHES = 1 << 18, /* Copy runtime data caches. */ + /* XXX TODO Do we want to keep that? would rather try to get rid of it... */ + LIB_ID_COPY_ACTIONS = 1 << 19, /* EXCEPTION! Deep-copy actions used by animdata of copied ID. */ +}; + +void BKE_libblock_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag); void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +/* "Deprecated" old API. */ void *BKE_libblock_copy_nolib(const struct ID *id, const bool do_action) ATTR_NONNULL(); -void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action); + void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL(); void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL(); @@ -64,13 +91,45 @@ struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* library_remap.c (keep here since they're general functions) */ -void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL(); -void BKE_libblock_free_datablock(struct ID *id) ATTR_NONNULL(); +/** + * New freeing logic options. + */ +enum { + /* *** Generic options (should be handled by all ID types freeing). *** */ + /* Do not try to remove freed ID from given Main (passed Main may be NULL). */ + LIB_ID_FREE_NO_MAIN = 1 << 0, + /* Do not affect user refcount of datablocks used by freed one. + * Implies LIB_ID_FREE_NO_MAIN. */ + LIB_ID_FREE_NO_USER_REFCOUNT = 1 << 1, + /* Assume freed ID datablock memory is managed elsewhere, do not free it + * (still calls relevant ID type's freeing function though) - USE WITH CAUTION! + * Implies LIB_ID_FREE_NO_MAIN. */ + LIB_ID_FREE_NOT_ALLOCATED = 1 << 2, + + LIB_ID_FREE_NO_DEG_TAG = 1 << 8, /* Do not tag freed ID for update in depsgraph. */ + LIB_ID_FREE_NO_UI_USER = 1 << 9, /* Do not attempt to remove freed ID from UI data/notifiers/... */ +}; + +void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, const bool use_flag_from_idtag); +void BKE_id_free(struct Main *bmain, void *idv); +/* Those three naming are bad actually, should be BKE_id_free... (since it goes beyond mere datablock). */ +/* "Deprecated" old API */ void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user) ATTR_NONNULL(); +void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL(); -void BKE_libblock_free_data(struct ID *id, const bool do_id_user) ATTR_NONNULL(); + +void BKE_libblock_management_main_add(struct Main *bmain, void *idv); +void BKE_libblock_management_main_remove(struct Main *bmain, void *idv); + +void BKE_libblock_management_usercounts_set(struct Main *bmain, void *idv); +void BKE_libblock_management_usercounts_clear(struct Main *bmain, void *idv); + +/* TODO should be named "BKE_id_delete()". */ void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL(); +void BKE_libblock_free_datablock(struct ID *id, const int flag) ATTR_NONNULL(); +void BKE_libblock_free_data(struct ID *id, const bool do_id_user) ATTR_NONNULL(); + void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id); void id_lib_extern(struct ID *id); void BKE_library_filepath_set(struct Library *lib, const char *filepath); @@ -87,6 +146,7 @@ void BKE_id_make_local_generic(struct Main *bmain, struct ID *id, const bool id_ bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const bool force_local); bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop); bool id_copy(struct Main *bmain, const struct ID *id, struct ID **newid, bool test); +bool BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag, const bool test); void id_sort_by_name(struct ListBase *lb, struct ID *id); void BKE_id_expand_local(struct Main *bmain, struct ID *id); void BKE_id_copy_ensure_local(struct Main *bmain, const struct ID *old_id, struct ID *new_id); diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h index c7b323d0f6e..3ba4fbe0338 100644 --- a/source/blender/blenkernel/BKE_linestyle.h +++ b/source/blender/blenkernel/BKE_linestyle.h @@ -52,6 +52,9 @@ struct bContext; void BKE_linestyle_init(struct FreestyleLineStyle *linestyle); FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name); void BKE_linestyle_free(FreestyleLineStyle *linestyle); +void BKE_linestyle_copy_data( + struct Main *bmain, struct FreestyleLineStyle *linestyle_dst, const struct FreestyleLineStyle *linestyle_src, + const int flag); FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineStyle *linestyle); void BKE_linestyle_make_local(struct Main *bmain, struct FreestyleLineStyle *linestyle, const bool lib_local); @@ -63,10 +66,14 @@ LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyl LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type); LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type); -LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m); -LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m); -LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m); -LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m); +LineStyleModifier *BKE_linestyle_color_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag); +LineStyleModifier *BKE_linestyle_alpha_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag); +LineStyleModifier *BKE_linestyle_thickness_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag); +LineStyleModifier *BKE_linestyle_geometry_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag); int BKE_linestyle_color_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier); int BKE_linestyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier); diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index 0735d2d97a1..5598f0dc473 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -32,6 +32,7 @@ * \ingroup bke */ +struct EvaluationContext; struct ImageUser; struct Image; struct ListBase; @@ -122,6 +123,7 @@ void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const eMask /* general */ struct Mask *BKE_mask_new(struct Main *bmain, const char *name); +void BKE_mask_copy_data(struct Main *bmain, struct Mask *mask_dst, const struct Mask *mask_src, const int flag); struct Mask *BKE_mask_copy_nolib(struct Mask *mask); struct Mask *BKE_mask_copy(struct Main *bmain, const struct Mask *mask); @@ -232,6 +234,12 @@ float *BKE_mask_point_segment_feather_diff(struct MaskSpline *spline, struct Mas int width, int height, unsigned int *tot_feather_point); +void BKE_mask_layer_evaluate_animation(struct MaskLayer *masklay, const float ctime); +void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, const float ctime); + +void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, struct Mask *mask); +void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, struct Mask *mask); + /* mask_rasterize.c */ struct MaskRasterHandle; typedef struct MaskRasterHandle MaskRasterHandle; diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index 7da962dd6d6..c6ebda2c399 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -54,6 +54,7 @@ void BKE_material_init(struct Material *ma); void BKE_material_remap_object(struct Object *ob, const unsigned int *remap); void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst); struct Material *BKE_material_add(struct Main *bmain, const char *name); +void BKE_material_copy_data(struct Main *bmain, struct Material *ma_dst, const struct Material *ma_src, const int flag); struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma); struct Material *localize_material(struct Material *ma); struct Material *give_node_material(struct Material *ma); /* returns node material or self */ diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index c00a0743ebb..f02704ba903 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -41,6 +41,7 @@ struct MetaElem; void BKE_mball_free(struct MetaBall *mb); void BKE_mball_init(struct MetaBall *mb); struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name); +void BKE_mball_copy_data(struct Main *bmain, struct MetaBall *mb_dst, const struct MetaBall *mb_src, const int flag); struct MetaBall *BKE_mball_copy(struct Main *bmain, const struct MetaBall *mb); void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb, const bool lib_local); @@ -59,7 +60,7 @@ bool BKE_mball_minmax_ex(struct MetaBall *mb, float min[3], float max[3], float obmat[4][4], const short flag); bool BKE_mball_center_median(struct MetaBall *mb, float r_cent[3]); bool BKE_mball_center_bounds(struct MetaBall *mb, float r_cent[3]); -void BKE_mball_transform(struct MetaBall *mb, float mat[4][4]); +void BKE_mball_transform(struct MetaBall *mb, float mat[4][4], const bool do_props); void BKE_mball_translate(struct MetaBall *mb, const float offset[3]); struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index b55b8b2dd3c..f3b2b653e3d 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -87,6 +87,7 @@ int BKE_mesh_edge_other_vert(const struct MEdge *e, int v); void BKE_mesh_free(struct Mesh *me); void BKE_mesh_init(struct Mesh *me); struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name); +void BKE_mesh_copy_data(struct Main *bmain, struct Mesh *me_dst, const struct Mesh *me_src, const int flag); struct Mesh *BKE_mesh_copy(struct Main *bmain, const struct Mesh *me); void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd); void BKE_mesh_ensure_skin_customdata(struct Mesh *me); @@ -279,7 +280,8 @@ void BKE_mesh_poly_edgebitmap_insert( bool BKE_mesh_center_median(const struct Mesh *me, float r_cent[3]); bool BKE_mesh_center_bounds(const struct Mesh *me, float r_cent[3]); -bool BKE_mesh_center_centroid(const struct Mesh *me, float r_cent[3]); +bool BKE_mesh_center_of_surface(const struct Mesh *me, float r_cent[3]); +bool BKE_mesh_center_of_volume(const struct Mesh *me, float r_cent[3]); void BKE_mesh_calc_volume( const struct MVert *mverts, const int mverts_num, diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index b241b5ca5b7..30c47a4b192 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -344,6 +344,7 @@ bool modifier_unique_name(struct ListBase *modifiers, struct ModifierDa void modifier_copyData_generic(const struct ModifierData *md, struct ModifierData *target); void modifier_copyData(struct ModifierData *md, struct ModifierData *target); +void modifier_copyData_ex(struct ModifierData *md, struct ModifierData *target, const int flag); bool modifier_dependsOnTime(struct ModifierData *md); bool modifier_supportsMapping(struct ModifierData *md); bool modifier_supportsCage(struct Scene *scene, struct ModifierData *md); diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index 69fdad5ef7b..3ddf75f204e 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -41,6 +41,7 @@ struct MovieDistortion; void BKE_movieclip_free(struct MovieClip *clip); +void BKE_movieclip_copy_data(struct Main *bmain, struct MovieClip *clip_dst, const struct MovieClip *clip_src, const int flag); struct MovieClip *BKE_movieclip_copy(struct Main *bmain, const struct MovieClip *clip); void BKE_movieclip_make_local(struct Main *bmain, struct MovieClip *clip, const bool lib_local); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index d5279c5b0ce..81de70ca8a4 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -335,6 +335,7 @@ struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char /* copy/free funcs, need to manage ID users */ void ntreeFreeTree(struct bNodeTree *ntree); +void BKE_node_tree_copy_data(struct Main *bmain, struct bNodeTree *ntree_dst, const struct bNodeTree *ntree_src, const int flag); struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user); struct bNodeTree *ntreeCopyTree(struct Main *bmain, const struct bNodeTree *ntree); /* node->id user count */ @@ -452,6 +453,7 @@ void nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node); void nodeUniqueName(struct bNodeTree *ntree, struct bNode *node); void nodeFreeNode(struct bNodeTree *ntree, struct bNode *node); +struct bNode *BKE_node_copy_ex(struct bNodeTree *ntree, struct bNode *node_src, const int flag); struct bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node); struct bNodeLink *nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 0a5035f9a9b..d1a4033957b 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -53,10 +53,10 @@ void BKE_object_workob_clear(struct Object *workob); void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struct Object *workob); void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src); -struct SoftBody *copy_softbody(const struct SoftBody *sb, bool copy_caches); -struct BulletSoftBody *copy_bulletsoftbody(const struct BulletSoftBody *sb); -struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys); -void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src); +struct SoftBody *copy_softbody(const struct SoftBody *sb, const int flag); +struct BulletSoftBody *copy_bulletsoftbody(const struct BulletSoftBody *sb, const int flag); +struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys, const int flag); +void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src, const int flag); void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src); void BKE_object_free_particlesystems(struct Object *ob); void BKE_object_free_softbody(struct Object *ob); @@ -105,7 +105,7 @@ bool BKE_object_lod_is_usable(struct Object *ob, struct Scene *scene); struct Object *BKE_object_lod_meshob_get(struct Object *ob, struct Scene *scene); struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene); -struct Object *BKE_object_copy_ex(struct Main *bmain, const struct Object *ob, bool copy_caches); +void BKE_object_copy_data(struct Main *bmain, struct Object *ob_dst, const struct Object *ob_src, const int flag); struct Object *BKE_object_copy(struct Main *bmain, const struct Object *ob); void BKE_object_make_local(struct Main *bmain, struct Object *ob, const bool lib_local); void BKE_object_make_local_ex(struct Main *bmain, struct Object *ob, const bool lib_local, const bool clear_proxy); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 821dc211591..6cae8d28947 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -99,6 +99,8 @@ void BKE_paint_set_overlay_override(enum OverlayFlags flag); /* palettes */ void BKE_palette_free(struct Palette *palette); struct Palette *BKE_palette_add(struct Main *bmain, const char *name); +void BKE_palette_copy_data( + struct Main *bmain, struct Palette *palette_dst, const struct Palette *palette_src, const int flag); struct Palette *BKE_palette_copy(struct Main *bmain, const struct Palette *palette); void BKE_palette_make_local(struct Main *bmain, struct Palette *palette, const bool lib_local); struct PaletteColor *BKE_palette_color_add(struct Palette *palette); @@ -109,12 +111,14 @@ void BKE_palette_clear(struct Palette *palette); /* paint curves */ struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name); void BKE_paint_curve_free(struct PaintCurve *pc); +void BKE_paint_curve_copy_data( + struct Main *bmain, struct PaintCurve *pc_dst, const struct PaintCurve *pc_src, const int flag); struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, const struct PaintCurve *pc); void BKE_paint_curve_make_local(struct Main *bmain, struct PaintCurve *pc, const bool lib_local); void BKE_paint_init(struct Scene *sce, PaintMode mode, const char col[3]); void BKE_paint_free(struct Paint *p); -void BKE_paint_copy(struct Paint *src, struct Paint *tar); +void BKE_paint_copy(struct Paint *src, struct Paint *tar, const int flag); void BKE_paint_cavity_curve_preset(struct Paint *p, int preset); @@ -156,6 +160,14 @@ void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct B void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]); +/* Used for both vertex color and weight paint */ +struct SculptVertexPaintGeomMap { + int *vert_map_mem; + struct MeshElemMap *vert_to_loop; + int *poly_map_mem; + struct MeshElemMap *vert_to_poly; +}; + /* Session data (mode-specific) */ typedef struct SculptSession { @@ -201,10 +213,39 @@ typedef struct SculptSession { struct SculptStroke *stroke; struct StrokeCache *cache; + + union { + struct { + struct SculptVertexPaintGeomMap gmap; + + /* For non-airbrush painting to re-apply from the original (MLoop aligned). */ + unsigned int *previous_color; + float *previous_accum; + } vpaint; + + struct { + struct SculptVertexPaintGeomMap gmap; + + /* Vertex aligned arrays of weights. */ + float *previous_accum; + float *previous_weight; + /* Keep track of how much each vertex has been painted (non-airbrush only). */ + float *alpha_weight; + } wpaint; + + //struct { + //ToDo: identify sculpt-only fields + //} sculpt; + } mode; + int mode_type; + + /* This flag prevents PBVH from being freed when creating the vp_handle for texture paint. */ + bool building_vp_handle; } SculptSession; void BKE_sculptsession_free(struct Object *ob); void BKE_sculptsession_free_deformMats(struct SculptSession *ss); +void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss); void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder); void BKE_sculptsession_bm_to_me_for_render(struct Object *object); void BKE_sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob, diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index f9948ba500a..ddb4f9c37bd 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -324,6 +324,9 @@ struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct P struct ModifierData *object_add_particle_system(struct Scene *scene, struct Object *ob, const char *name); void object_remove_particle_system(struct Scene *scene, struct Object *ob); struct ParticleSettings *psys_new_settings(const char *name, struct Main *main); +void BKE_particlesettings_copy_data( + struct Main *bmain, struct ParticleSettings *part_dst, const struct ParticleSettings *part_src, + const int flag); struct ParticleSettings *BKE_particlesettings_copy(struct Main *bmain, const struct ParticleSettings *part); void BKE_particlesettings_make_local(struct Main *bmain, struct ParticleSettings *part, const bool lib_local); @@ -473,9 +476,8 @@ typedef struct ParticleRenderData { struct EvaluationContext; -void BKE_particle_system_eval(struct EvaluationContext *eval_ctx, - struct Scene *scene, - struct Object *ob, - struct ParticleSystem *psys); +void BKE_particle_system_eval_init(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob); #endif diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 927303f8b3c..cc84be6e2c1 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -32,6 +32,7 @@ struct CCGElem; struct CCGKey; +struct CCGDerivedMesh; struct CustomData; struct DMFlagMat; struct MPoly; @@ -71,7 +72,7 @@ void BKE_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems, struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats, unsigned int **grid_hidden); void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading, struct BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset); - +void BKE_pbvh_set_ccgdm(PBVH *bvh, struct CCGDerivedMesh *ccgdm); void BKE_pbvh_free(PBVH *bvh); void BKE_pbvh_free_layer_disp(PBVH *bvh); @@ -118,6 +119,7 @@ void BKE_pbvh_raycast_project_ray_root( void BKE_pbvh_node_draw(PBVHNode *node, void *data); void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], int (*setMaterial)(int matnr, void *attribs), bool wireframe, bool fast); +void BKE_pbvh_draw_BB(PBVH *bvh); /* PBVH Access */ typedef enum { @@ -141,6 +143,7 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden, /* multires level, only valid for type == PBVH_GRIDS */ void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key); +struct CCGDerivedMesh *BKE_pbvh_get_ccgdm(const PBVH *bvh); /* Only valid for type == PBVH_BMESH */ struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh); diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 02f6c435ee2..f0819c8d79d 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -314,7 +314,7 @@ struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches); void BKE_ptcache_free_mem(struct ListBase *mem_cache); void BKE_ptcache_free(struct PointCache *cache); void BKE_ptcache_free_list(struct ListBase *ptcaches); -struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, bool copy_data); +struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, const int flag); /********************** Baking *********************/ diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h index c72f067a111..3c7274ca3c5 100644 --- a/source/blender/blenkernel/BKE_rigidbody.h +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -49,8 +49,8 @@ void BKE_rigidbody_free_constraint(struct Object *ob); /* ...... */ -struct RigidBodyOb *BKE_rigidbody_copy_object(const struct Object *ob); -struct RigidBodyCon *BKE_rigidbody_copy_constraint(const struct Object *ob); +struct RigidBodyOb *BKE_rigidbody_copy_object(const struct Object *ob, const int flag); +struct RigidBodyCon *BKE_rigidbody_copy_constraint(const struct Object *ob, const int flag); /* Callback format for performing operations on ID-pointers for rigidbody world. */ typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw, struct ID **idpoin, void *userdata, int cb_flag); @@ -66,7 +66,7 @@ struct RigidBodyOb *BKE_rigidbody_create_object(struct Scene *scene, struct Obje struct RigidBodyCon *BKE_rigidbody_create_constraint(struct Scene *scene, struct Object *ob, short type); /* copy */ -struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw); +struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw, const int flag); void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw); /* 'validate' (i.e. make new or replace old) Physics-Engine objects */ diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h index 10cddd7b454..35bcd91a9b1 100644 --- a/source/blender/blenkernel/BKE_sca.h +++ b/source/blender/blenkernel/BKE_sca.h @@ -52,16 +52,16 @@ void free_actuators(struct ListBase *lb); void free_sensor(struct bSensor *sens); void free_sensors(struct ListBase *lb); -struct bSensor *copy_sensor(struct bSensor *sens); -void copy_sensors(struct ListBase *lbn, const struct ListBase *lbo); +struct bSensor *copy_sensor(struct bSensor *sens, const int flag); +void copy_sensors(struct ListBase *lbn, const struct ListBase *lbo, const int flag); void init_sensor(struct bSensor *sens); struct bSensor *new_sensor(int type); -struct bController *copy_controller(struct bController *cont); -void copy_controllers(struct ListBase *lbn, const struct ListBase *lbo); +struct bController *copy_controller(struct bController *cont, const int flag); +void copy_controllers(struct ListBase *lbn, const struct ListBase *lbo, const int flag); void init_controller(struct bController *cont); struct bController *new_controller(int type); -struct bActuator *copy_actuator(struct bActuator *act); -void copy_actuators(struct ListBase *lbn, const struct ListBase *lbo); +struct bActuator *copy_actuator(struct bActuator *act, const int flag); +void copy_actuators(struct ListBase *lbn, const struct ListBase *lbo, const int flag); void init_actuator(struct bActuator *act); struct bActuator *new_actuator(int type); void clear_sca_new_poins_ob(struct Object *ob); @@ -70,7 +70,7 @@ void set_sca_new_poins_ob(struct Object *ob); void set_sca_new_poins(void); void BKE_sca_logic_links_remap(struct Main *bmain, struct Object *ob_old, struct Object *ob_new); -void BKE_sca_logic_copy(struct Object *ob_new, const struct Object *ob); +void BKE_sca_logic_copy(struct Object *ob_new, const struct Object *ob, const int flag); void sca_move_sensor(struct bSensor *sens_to_move, struct Object *ob, int move_up); void sca_move_controller(struct bController *cont_to_move, struct Object *ob, int move_up); diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index d2152950bff..481aff3cfa6 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -42,7 +42,6 @@ struct Base; struct EvaluationContext; struct Main; struct Object; -struct QuicktimeCodecData; struct RenderData; struct SceneRenderLayer; struct Scene; @@ -64,7 +63,6 @@ struct Main; struct Base *_setlooper_base_step(struct Scene **sce_iter, struct Base *base); void free_avicodecdata(struct AviCodecData *acd); -void free_qtcodecdata(struct QuicktimeCodecData *acd); void BKE_scene_free(struct Scene *sce); void BKE_scene_init(struct Scene *sce); @@ -98,6 +96,7 @@ void BKE_scene_base_flag_from_objects(struct Scene *scene); void BKE_scene_set_background(struct Main *bmain, struct Scene *sce); struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name); +void BKE_scene_copy_data(struct Main *bmain, struct Scene *sce_dst, const struct Scene *sce_src, const int flag); struct Scene *BKE_scene_copy(struct Main *bmain, struct Scene *sce, int type); void BKE_scene_groups_relink(struct Scene *sce); @@ -151,6 +150,8 @@ bool BKE_scene_check_rigidbody_active(const struct Scene *scene); int BKE_scene_num_threads(const struct Scene *scene); int BKE_render_num_threads(const struct RenderData *r); +int BKE_render_preview_pixel_size(const struct RenderData *r); + double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value); /* multiview */ @@ -175,4 +176,3 @@ int BKE_scene_multiview_num_videos_get(const struct RenderData *rd); #endif #endif - diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 811e9136fc9..657e99f05d1 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -335,7 +335,8 @@ bool BKE_sequence_base_shuffle( bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, struct Scene *evil_scene); bool BKE_sequence_base_isolated_sel_check(struct ListBase *seqbase); void BKE_sequencer_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render); -struct Sequence *BKE_sequence_dupli_recursive(struct Scene *scene, struct Scene *scene_to, struct Sequence *seq, int dupe_flag); +struct Sequence *BKE_sequence_dupli_recursive( + const struct Scene *scene_src, struct Scene *scene_dst, struct Sequence *seq, int dupe_flag); int BKE_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str); bool BKE_sequence_check_depend(struct Sequence *seq, struct Sequence *cur); @@ -352,8 +353,8 @@ void BKE_sequencer_refresh_sound_length(struct Scene *scene); void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq); void BKE_sequence_base_dupli_recursive( - struct Scene *scene, struct Scene *scene_to, ListBase *nseqbase, ListBase *seqbase, - int dupe_flag); + const struct Scene *scene_src, struct Scene *scene_dst, struct ListBase *nseqbase, const struct ListBase *seqbase, + int dupe_flag, const int flag); bool BKE_sequence_is_valid_check(struct Sequence *seq); void BKE_sequencer_clear_scene_in_allseqs(struct Main *bmain, struct Scene *sce); diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index a5c626e74d7..6f8274fabc8 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -80,6 +80,8 @@ void BKE_sound_load(struct Main *main, struct bSound *sound); void BKE_sound_free(struct bSound *sound); +void BKE_sound_copy_data(struct Main *bmain, struct bSound *sound_dst, const struct bSound *sound_src, const int flag); + void BKE_sound_make_local(struct Main *bmain, struct bSound *sound, const bool lib_local); #if defined(__AUD_C_API_H__) || defined(WITH_SYSTEM_AUDASPACE) diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h index 907558f9203..57f4c37f129 100644 --- a/source/blender/blenkernel/BKE_speaker.h +++ b/source/blender/blenkernel/BKE_speaker.h @@ -33,6 +33,7 @@ struct Speaker; void BKE_speaker_init(struct Speaker *spk); void *BKE_speaker_add(struct Main *bmain, const char *name); +void BKE_speaker_copy_data(struct Main *bmain, struct Speaker *spk_dst, const struct Speaker *spk_src, const int flag); struct Speaker *BKE_speaker_copy(struct Main *bmain, const struct Speaker *spk); void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk, const bool lib_local); void BKE_speaker_free(struct Speaker *spk); diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index c8fb483cdf2..14d3318e059 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -52,6 +52,7 @@ bool BKE_text_reload(struct Text *text); struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const char *relpath, const bool is_internal); struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath); +void BKE_text_copy_data(struct Main *bmain, struct Text *ta_dst, const struct Text *ta_src, const int flag); struct Text *BKE_text_copy (struct Main *bmain, const struct Text *ta); void BKE_text_make_local (struct Main *bmain, struct Text *text, const bool lib_local); void BKE_text_clear (struct Text *text); diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index 190fdeafaec..8a9171673ea 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -70,6 +70,7 @@ void colorband_update_sort(struct ColorBand *coba); void BKE_texture_free(struct Tex *tex); void BKE_texture_default(struct Tex *tex); +void BKE_texture_copy_data(struct Main *bmain, struct Tex *tex_dst, const struct Tex *tex_src, const int flag); struct Tex *BKE_texture_copy(struct Main *bmain, const struct Tex *tex); struct Tex *BKE_texture_add(struct Main *bmain, const char *name); struct Tex *BKE_texture_localize(struct Tex *tex); @@ -114,13 +115,13 @@ void BKE_texture_colormapping_default(struct ColorMapping *color void BKE_texture_envmap_free_data(struct EnvMap *env); void BKE_texture_envmap_free(struct EnvMap *env); struct EnvMap *BKE_texture_envmap_add(void); -struct EnvMap *BKE_texture_envmap_copy(const struct EnvMap *env); +struct EnvMap *BKE_texture_envmap_copy(const struct EnvMap *env, const int flag); void BKE_texture_pointdensity_init_data(struct PointDensity *pd); void BKE_texture_pointdensity_free_data(struct PointDensity *pd); void BKE_texture_pointdensity_free(struct PointDensity *pd); struct PointDensity *BKE_texture_pointdensity_add(void); -struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd); +struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd, const int flag); void BKE_texture_voxeldata_free_data(struct VoxelData *vd); void BKE_texture_voxeldata_free(struct VoxelData *vd); @@ -129,7 +130,7 @@ struct VoxelData *BKE_texture_voxeldata_copy(struct VoxelData *vd); void BKE_texture_ocean_free(struct OceanTex *ot); struct OceanTex *BKE_texture_ocean_add(void); -struct OceanTex *BKE_texture_ocean_copy(const struct OceanTex *ot); +struct OceanTex *BKE_texture_ocean_copy(const struct OceanTex *ot, const int flag); bool BKE_texture_dependsOnTime(const struct Tex *texture); bool BKE_texture_is_image_user(const struct Tex *tex); diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h index b48be382073..d05ed1800fb 100644 --- a/source/blender/blenkernel/BKE_tracking.h +++ b/source/blender/blenkernel/BKE_tracking.h @@ -52,7 +52,7 @@ struct rcti; /* **** Common functions **** */ void BKE_tracking_free(struct MovieTracking *tracking); -void BKE_tracking_copy(struct MovieTracking *tracking_dst, const struct MovieTracking *tracking_src); +void BKE_tracking_copy(struct MovieTracking *tracking_dst, const struct MovieTracking *tracking_src, const int flag); void BKE_tracking_settings_init(struct MovieTracking *tracking); diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h index 18ae61f7653..2a811496bb9 100644 --- a/source/blender/blenkernel/BKE_world.h +++ b/source/blender/blenkernel/BKE_world.h @@ -39,6 +39,7 @@ struct World; void BKE_world_free(struct World *sc); void BKE_world_init(struct World *wrld); struct World *add_world(struct Main *bmian, const char *name); +void BKE_world_copy_data(struct Main *bmain, struct World *wrld_dst, const struct World *wrld_src, const int flag); struct World *BKE_world_copy(struct Main *bmain, const struct World *wrld); struct World *localize_world(struct World *wrld); void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 157c4408d6a..51598ede862 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -385,16 +385,6 @@ if(WITH_CODEC_AVI) add_definitions(-DWITH_AVI) endif() -if(WITH_CODEC_QUICKTIME) - list(APPEND INC - ../quicktime - ) - list(APPEND INC_SYS - ${QUICKTIME_INCLUDE_DIRS} - ) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_CODEC_FFMPEG) list(APPEND SRC intern/writeffmpeg.c diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 7eea8224ba1..9dae4c5eae7 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -93,6 +93,10 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm); # define ASSERT_IS_VALID_DM(dm) #endif + +static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER; + + static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob); static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid); @@ -235,6 +239,30 @@ static int dm_getNumLoopTri(DerivedMesh *dm) return numlooptris; } +static const MLoopTri *dm_getLoopTriArray(DerivedMesh *dm) +{ + MLoopTri *looptri; + + BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_READ); + looptri = dm->looptris.array; + BLI_rw_mutex_unlock(&loops_cache_lock); + + if (looptri != NULL) { + BLI_assert(dm->getNumLoopTri(dm) == dm->looptris.num); + } + else { + BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE); + /* We need to ensure array is still NULL inside mutex-protected code, some other thread might have already + * recomputed those looptris. */ + if (dm->looptris.array == NULL) { + dm->recalcLoopTri(dm); + } + looptri = dm->looptris.array; + BLI_rw_mutex_unlock(&loops_cache_lock); + } + return looptri; +} + static CustomData *dm_getVertCData(DerivedMesh *dm) { return &dm->vertData; @@ -278,6 +306,8 @@ void DM_init_funcs(DerivedMesh *dm) dm->dupLoopArray = dm_dupLoopArray; dm->dupPolyArray = dm_dupPolyArray; + dm->getLoopTriArray = dm_getLoopTriArray; + /* subtypes handle getting actual data */ dm->getNumLoopTri = dm_getNumLoopTri; @@ -471,6 +501,8 @@ void DM_ensure_tessface(DerivedMesh *dm) /** * Ensure the array is large enough + * + * /note This function must always be thread-protected by caller. It should only be used by internal code. */ void DM_ensure_looptri_data(DerivedMesh *dm) { @@ -478,18 +510,22 @@ void DM_ensure_looptri_data(DerivedMesh *dm) const unsigned int totloop = dm->numLoopData; const int looptris_num = poly_to_tri_count(totpoly, totloop); + BLI_assert(dm->looptris.array_wip == NULL); + + SWAP(MLoopTri *, dm->looptris.array, dm->looptris.array_wip); + if ((looptris_num > dm->looptris.num_alloc) || (looptris_num < dm->looptris.num_alloc * 2) || (totpoly == 0)) { - MEM_SAFE_FREE(dm->looptris.array); + MEM_SAFE_FREE(dm->looptris.array_wip); dm->looptris.num_alloc = 0; dm->looptris.num = 0; } if (totpoly) { - if (dm->looptris.array == NULL) { - dm->looptris.array = MEM_mallocN(sizeof(*dm->looptris.array) * looptris_num, __func__); + if (dm->looptris.array_wip == NULL) { + dm->looptris.array_wip = MEM_mallocN(sizeof(*dm->looptris.array_wip) * looptris_num, __func__); dm->looptris.num_alloc = looptris_num; } @@ -497,19 +533,6 @@ void DM_ensure_looptri_data(DerivedMesh *dm) } } -/** - * The purpose of this function is that we can call: - * `dm->getLoopTriArray(dm)` and get the array returned. - */ -void DM_ensure_looptri(DerivedMesh *dm) -{ - const int numPolys = dm->getNumPolys(dm); - - if ((dm->looptris.num == 0) && (numPolys != 0)) { - dm->recalcLoopTri(dm); - } -} - void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num) { int i; @@ -2201,7 +2224,6 @@ static void mesh_calc_modifiers( if (dataMask & CD_MASK_MFACE) { DM_ensure_tessface(finaldm); } - DM_ensure_looptri(finaldm); /* without this, drawing ngon tri's faces will show ugly tessellated face * normals and will also have to calculate normals on the fly, try avoid @@ -2641,7 +2663,7 @@ static void mesh_build_data( ob->lastDataMask = dataMask; ob->lastNeedMapping = need_mapping; - if ((ob->mode & OB_MODE_SCULPT) && ob->sculpt) { + if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) { /* create PBVH immediately (would be created on the fly too, * but this avoids waiting on first stroke) */ @@ -4386,35 +4408,3 @@ MFace *DM_get_tessface_array(DerivedMesh *dm, bool *r_allocated) return mface; } - -const MLoopTri *DM_get_looptri_array( - DerivedMesh *dm, - const MVert *mvert, - const MPoly *mpoly, int mpoly_len, - const MLoop *mloop, int mloop_len, - bool *r_allocated) -{ - const MLoopTri *looptri = dm->getLoopTriArray(dm); - *r_allocated = false; - - if (looptri == NULL) { - if (mpoly_len > 0) { - const int looptris_num = poly_to_tri_count(mpoly_len, mloop_len); - MLoopTri *looptri_data; - - looptri_data = MEM_mallocN(sizeof(MLoopTri) * looptris_num, __func__); - - BKE_mesh_recalc_looptri( - mloop, mpoly, - mvert, - mloop_len, mpoly_len, - looptri_data); - - looptri = looptri_data; - - *r_allocated = true; - } - } - - return looptri; -} diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 885ea36d404..5bd6085c8f5 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -88,7 +88,7 @@ bAction *add_empty_action(Main *bmain, const char name[]) { bAction *act; - act = BKE_libblock_alloc(bmain, ID_AC, name); + act = BKE_libblock_alloc(bmain, ID_AC, name, 0); return act; } @@ -120,46 +120,56 @@ void BKE_action_free(bAction *act) /* .................................. */ -bAction *BKE_action_copy(Main *bmain, const bAction *src) +/** + * Only copy internal data of Action ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_action_copy_data(Main *UNUSED(bmain), bAction *act_dst, const bAction *act_src, const int UNUSED(flag)) { - bAction *dst = NULL; - bActionGroup *dgrp, *sgrp; - FCurve *dfcu, *sfcu; - - if (src == NULL) - return NULL; - dst = BKE_libblock_copy(bmain, &src->id); - + bActionGroup *grp_dst, *grp_src; + FCurve *fcu_dst, *fcu_src; + /* duplicate the lists of groups and markers */ - BLI_duplicatelist(&dst->groups, &src->groups); - BLI_duplicatelist(&dst->markers, &src->markers); - + BLI_duplicatelist(&act_dst->groups, &act_src->groups); + BLI_duplicatelist(&act_dst->markers, &act_src->markers); + /* copy F-Curves, fixing up the links as we go */ - BLI_listbase_clear(&dst->curves); - - for (sfcu = src->curves.first; sfcu; sfcu = sfcu->next) { + BLI_listbase_clear(&act_dst->curves); + + for (fcu_src = act_src->curves.first; fcu_src; fcu_src = fcu_src->next) { /* duplicate F-Curve */ - dfcu = copy_fcurve(sfcu); - BLI_addtail(&dst->curves, dfcu); - + fcu_dst = copy_fcurve(fcu_src); /* XXX TODO pass subdata flag? But surprisingly does not seem to be doing any ID refcounting... */ + BLI_addtail(&act_dst->curves, fcu_dst); + /* fix group links (kindof bad list-in-list search, but this is the most reliable way) */ - for (dgrp = dst->groups.first, sgrp = src->groups.first; dgrp && sgrp; dgrp = dgrp->next, sgrp = sgrp->next) { - if (sfcu->grp == sgrp) { - dfcu->grp = dgrp; - - if (dgrp->channels.first == sfcu) - dgrp->channels.first = dfcu; - if (dgrp->channels.last == sfcu) - dgrp->channels.last = dfcu; - + for (grp_dst = act_dst->groups.first, grp_src = act_src->groups.first; + grp_dst && grp_src; + grp_dst = grp_dst->next, grp_src = grp_src->next) + { + if (fcu_src->grp == grp_src) { + fcu_dst->grp = grp_dst; + + if (grp_dst->channels.first == fcu_src) { + grp_dst->channels.first = fcu_dst; + } + if (grp_dst->channels.last == fcu_src) { + grp_dst->channels.last = fcu_dst; + } break; } } } - - BKE_id_copy_ensure_local(bmain, &src->id, &dst->id); +} - return dst; +bAction *BKE_action_copy(Main *bmain, const bAction *act_src) +{ + bAction *act_copy; + BKE_id_copy_ex(bmain, &act_src->id, (ID **)&act_copy, 0, false); + return act_copy; } /* *************** Action Groups *************** */ @@ -523,7 +533,7 @@ const char *BKE_pose_ikparam_get_name(bPose *pose) * * \param dst Should be freed already, makes entire duplicate. */ -void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constraints) +void BKE_pose_copy_data_ex(bPose **dst, const bPose *src, const int flag, const bool copy_constraints) { bPose *outPose; bPoseChannel *pchan; @@ -553,9 +563,8 @@ void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constrain outPose->avs = src->avs; for (pchan = outPose->chanbase.first; pchan; pchan = pchan->next) { - - if (pchan->custom) { - id_us_plus(&pchan->custom->id); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)pchan->custom); } /* warning, O(n2) here, if done without the hash, but these are rarely used features. */ @@ -570,13 +579,13 @@ void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constrain } if (copy_constraints) { - BKE_constraints_copy(&listb, &pchan->constraints, true); // BKE_constraints_copy NULLs listb + BKE_constraints_copy_ex(&listb, &pchan->constraints, flag, true); // BKE_constraints_copy NULLs listb pchan->constraints = listb; pchan->mpath = NULL; /* motion paths should not get copied yet... */ } if (pchan->prop) { - pchan->prop = IDP_CopyProperty(pchan->prop); + pchan->prop = IDP_CopyProperty_ex(pchan->prop, flag); } } @@ -588,6 +597,11 @@ void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constrain *dst = outPose; } +void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constraints) +{ + BKE_pose_copy_data_ex(dst, src, 0, copy_constraints); +} + void BKE_pose_itasc_init(bItasc *itasc) { if (itasc) { @@ -1115,9 +1129,13 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_ if (fcu->totvert) { float nmin, nmax; - /* get extents for this curve */ - /* TODO: allow enabling/disabling this? */ - calc_fcurve_range(fcu, &nmin, &nmax, false, true); + /* get extents for this curve + * - no "selected only", since this is often used in the backend + * - no "minimum length" (we will apply this later), otherwise + * single-keyframe curves will increase the overall length by + * a phantom frame (T50354) + */ + calc_fcurve_range(fcu, &nmin, &nmax, false, false); /* compare to the running tally */ min = min_ff(min, nmin); @@ -1170,7 +1188,9 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_ } if (foundvert || foundmod) { + /* ensure that action is at least 1 frame long (for NLA strips to have a valid length) */ if (min == max) max += 1.0f; + *start = min; *end = max; } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 539901a59d5..64b33326aa9 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -259,7 +259,7 @@ void BKE_animdata_free(ID *id, const bool do_id_user) /* Copying -------------------------------------------- */ /* Make a copy of the given AnimData - to be used when copying datablocks */ -AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action) +AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action) { AnimData *dadt; @@ -270,8 +270,9 @@ AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action) /* make a copy of action - at worst, user has to delete copies... */ if (do_action) { - dadt->action = BKE_action_copy(G.main, adt->action); - dadt->tmpact = BKE_action_copy(G.main, adt->tmpact); + BLI_assert(bmain != NULL); + BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, 0, false); + BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, 0, false); } else { id_us_plus((ID *)dadt->action); @@ -291,7 +292,7 @@ AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action) return dadt; } -bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action) +bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const bool do_action) { AnimData *adt; @@ -303,7 +304,7 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action) adt = BKE_animdata_from_id(id_from); if (adt) { IdAdtTemplate *iat = (IdAdtTemplate *)id_to; - iat->adt = BKE_animdata_copy(adt, do_action); + iat->adt = BKE_animdata_copy(bmain, adt, do_action); } return true; @@ -623,6 +624,8 @@ char *BKE_animdata_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *p } break; } + default: + break; } /* fix RNA pointer, as we've now changed the ID root by changing the paths */ @@ -1347,7 +1350,7 @@ void BKE_keyingset_free_path(KeyingSet *ks, KS_Path *ksp) } /* Copy all KeyingSets in the given list */ -void BKE_keyingsets_copy(ListBase *newlist, ListBase *list) +void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list) { KeyingSet *ksn; KS_Path *kspn; diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 43fd47981b1..6dd852c7875 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -106,7 +106,8 @@ const char *BKE_appdir_folder_default(void) static char *blender_version_decimal(const int ver) { static char version_str[5]; - sprintf(version_str, "%d.%02d", ver / 100, ver % 100); + BLI_assert(ver < 1000); + BLI_snprintf(version_str, sizeof(version_str), "%d.%02d", ver / 100, ver % 100); return version_str; } @@ -212,8 +213,10 @@ static bool get_path_local( /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */ #ifdef __APPLE__ /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */ - static char osx_resourses[FILE_MAX]; - sprintf(osx_resourses, "%s../Resources", bprogdir); + char osx_resourses[FILE_MAX]; + BLI_snprintf(osx_resourses, sizeof(osx_resourses), "%s../Resources", bprogdir); + /* Remove the '/../' added above. */ + BLI_cleanup_path(NULL, osx_resourses); return test_path(targetpath, targetpath_len, osx_resourses, blender_version_decimal(ver), relfolder); #else return test_path(targetpath, targetpath_len, bprogdir, blender_version_decimal(ver), relfolder); @@ -326,10 +329,12 @@ static bool get_path_system( return true; } } - /* try EXECUTABLE_DIR/release/folder_name */ - if (test_path(targetpath, targetpath_len, bprogdir, "release", relfolder)) + if (test_path(targetpath, targetpath_len, bprogdir, "release", relfolder)) { return true; + } + /* never use if not existing. */ + targetpath[0] = '\0'; /* end developer overrides */ @@ -591,6 +596,9 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name) else { BLI_path_program_search(fullname, maxlen, name); } + /* Remove "/./" and "/../" so string comparisons can be used on the path. */ + BLI_cleanup_path(NULL, fullname); + #if defined(DEBUG) if (!STREQ(name, fullname)) { printf("guessing '%s' == '%s'\n", name, fullname); @@ -683,13 +691,16 @@ bool BKE_appdir_program_python_search( return is_found; } +/** Keep in sync with `bpy.utils.app_template_paths()` */ static const char *app_template_directory_search[2] = { "startup" SEP_STR "bl_app_templates_user", "startup" SEP_STR "bl_app_templates_system", }; static const int app_template_directory_id[2] = { + /* Only 'USER' */ BLENDER_USER_SCRIPTS, + /* Covers 'LOCAL' & 'SYSTEM'. */ BLENDER_SYSTEM_SCRIPTS, }; diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 35b6fe113bd..669344e18d7 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -83,7 +83,7 @@ bArmature *BKE_armature_add(Main *bmain, const char *name) { bArmature *arm; - arm = BKE_libblock_alloc(bmain, ID_AR, name); + arm = BKE_libblock_alloc(bmain, ID_AR, name, 0); arm->deformflag = ARM_DEF_VGROUP | ARM_DEF_ENVELOPE; arm->flag = ARM_COL_CUSTOM; /* custom bone-group colors */ arm->layer = 1; @@ -150,54 +150,70 @@ void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool lib_local) BKE_id_make_local_generic(bmain, &arm->id, true, lib_local); } -static void copy_bonechildren(Bone *newBone, const Bone *oldBone, const Bone *actBone, Bone **newActBone) +static void copy_bonechildren( + Bone *bone_dst, const Bone *bone_src, const Bone *bone_src_act, Bone **r_bone_dst_act, const int flag) { - Bone *curBone, *newChildBone; + Bone *bone_src_child, *bone_dst_child; - if (oldBone == actBone) - *newActBone = newBone; + if (bone_src == bone_src_act) { + *r_bone_dst_act = bone_dst; + } - if (oldBone->prop) - newBone->prop = IDP_CopyProperty(oldBone->prop); + if (bone_src->prop) { + bone_dst->prop = IDP_CopyProperty_ex(bone_src->prop, flag); + } /* Copy this bone's list */ - BLI_duplicatelist(&newBone->childbase, &oldBone->childbase); + BLI_duplicatelist(&bone_dst->childbase, &bone_src->childbase); /* For each child in the list, update it's children */ - newChildBone = newBone->childbase.first; - for (curBone = oldBone->childbase.first; curBone; curBone = curBone->next) { - newChildBone->parent = newBone; - copy_bonechildren(newChildBone, curBone, actBone, newActBone); - newChildBone = newChildBone->next; + for (bone_src_child = bone_src->childbase.first, bone_dst_child = bone_dst->childbase.first; + bone_src_child; + bone_src_child = bone_src_child->next, bone_dst_child = bone_dst_child->next) + { + bone_dst_child->parent = bone_dst; + copy_bonechildren(bone_dst_child, bone_src_child, bone_src_act, r_bone_dst_act, flag); } } -bArmature *BKE_armature_copy(Main *bmain, const bArmature *arm) +/** + * Only copy internal data of Armature ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_armature_copy_data(Main *UNUSED(bmain), bArmature *arm_dst, const bArmature *arm_src, const int flag) { - bArmature *newArm; - Bone *oldBone, *newBone; - Bone *newActBone = NULL; + Bone *bone_src, *bone_dst; + Bone *bone_dst_act = NULL; + + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; - newArm = BKE_libblock_copy(bmain, &arm->id); - BLI_duplicatelist(&newArm->bonebase, &arm->bonebase); + BLI_duplicatelist(&arm_dst->bonebase, &arm_src->bonebase); /* Duplicate the childrens' lists */ - newBone = newArm->bonebase.first; - for (oldBone = arm->bonebase.first; oldBone; oldBone = oldBone->next) { - newBone->parent = NULL; - copy_bonechildren(newBone, oldBone, arm->act_bone, &newActBone); - newBone = newBone->next; + bone_dst = arm_dst->bonebase.first; + for (bone_src = arm_src->bonebase.first; bone_src; bone_src = bone_src->next) { + bone_dst->parent = NULL; + copy_bonechildren(bone_dst, bone_src, arm_src->act_bone, &bone_dst_act, flag_subdata); + bone_dst = bone_dst->next; } - newArm->act_bone = newActBone; - - newArm->edbo = NULL; - newArm->act_edbone = NULL; - newArm->sketch = NULL; + arm_dst->act_bone = bone_dst_act; - BKE_id_copy_ensure_local(bmain, &arm->id, &newArm->id); + arm_dst->edbo = NULL; + arm_dst->act_edbone = NULL; + arm_dst->sketch = NULL; +} - return newArm; +bArmature *BKE_armature_copy(Main *bmain, const bArmature *arm) +{ + bArmature *arm_copy; + BKE_id_copy_ex(bmain, &arm->id, (ID **)&arm_copy, 0, false); + return arm_copy; } static Bone *get_named_bone_bonechildren(ListBase *lb, const char *name) diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index a4714041edf..45d1d36aeca 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -559,11 +559,10 @@ void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_roo /* *************** Depsgraph evaluation callbacks ************ */ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx), - Scene *scene, + Scene *UNUSED(scene), Object *ob, bPose *pose) { - float ctime = BKE_scene_frame_get(scene); /* not accurate... */ bPoseChannel *pchan; DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); @@ -581,6 +580,16 @@ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx), for (pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE); } +} + +void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob, + bPose *UNUSED(pose)) +{ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); /* 2a. construct the IK tree (standard IK) */ BIK_initialize_tree(scene, ob, ctime); diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 05ea7983b8e..980df05aca2 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -114,6 +114,7 @@ static void setup_app_data( const char *filepath, ReportList *reports) { Scene *curscene = NULL; + const bool is_startup = (bfd->filename[0] == '\0'); const bool recover = (G.fileflags & G_FILE_RECOVER) != 0; enum { LOAD_UI = 1, @@ -129,7 +130,7 @@ static void setup_app_data( else if (BLI_listbase_is_empty(&bfd->main->screen)) { mode = LOAD_UNDO; } - else if (G.fileflags & G_FILE_NO_UI) { + else if ((G.fileflags & G_FILE_NO_UI) && (is_startup == false)) { mode = LOAD_UI_OFF; } else { @@ -250,7 +251,9 @@ static void setup_app_data( CTX_data_scene_set(C, curscene); } else { - G.fileflags = bfd->fileflags; + /* Keep state from preferences. */ + const int fileflags_skip = G_FILE_FLAGS_RUNTIME; + G.fileflags = (G.fileflags & fileflags_skip) | (bfd->fileflags & ~fileflags_skip); CTX_wm_manager_set(C, G.main->wm.first); CTX_wm_screen_set(C, bfd->curscreen); CTX_data_scene_set(C, bfd->curscene); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index aae323a5056..03b0710c8fc 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -152,7 +152,7 @@ Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode) { Brush *brush; - brush = BKE_libblock_alloc(bmain, ID_BR, name); + brush = BKE_libblock_alloc(bmain, ID_BR, name, 0); BKE_brush_init(brush); @@ -172,34 +172,38 @@ struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode) return NULL; } -Brush *BKE_brush_copy(Main *bmain, const Brush *brush) +/** + * Only copy internal data of Brush ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_brush_copy_data(Main *UNUSED(bmain), Brush *brush_dst, const Brush *brush_src, const int flag) { - Brush *brushn; - - brushn = BKE_libblock_copy(bmain, &brush->id); - - if (brush->mtex.tex) - id_us_plus((ID *)brush->mtex.tex); - - if (brush->mask_mtex.tex) - id_us_plus((ID *)brush->mask_mtex.tex); - - if (brush->paint_curve) - id_us_plus((ID *)brush->paint_curve); - - if (brush->icon_imbuf) - brushn->icon_imbuf = IMB_dupImBuf(brush->icon_imbuf); + if (brush_src->icon_imbuf) { + brush_dst->icon_imbuf = IMB_dupImBuf(brush_src->icon_imbuf); + } - brushn->preview = NULL; + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&brush_dst->id, &brush_src->id); + } + else { + brush_dst->preview = NULL; + } - brushn->curve = curvemapping_copy(brush->curve); + brush_dst->curve = curvemapping_copy(brush_src->curve); /* enable fake user by default */ - id_fake_user_set(&brushn->id); - - BKE_id_copy_ensure_local(bmain, &brush->id, &brushn->id); + id_fake_user_set(&brush_dst->id); +} - return brushn; +Brush *BKE_brush_copy(Main *bmain, const Brush *brush) +{ + Brush *brush_copy; + BKE_id_copy_ex(bmain, &brush->id, (ID **)&brush_copy, 0, false); + return brush_copy; } /** Free (or release) any data used by this brush (does not free the brush itself). */ diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index c1fad4f80c8..775499304d4 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -1137,7 +1137,6 @@ BVHTree *bvhtree_from_mesh_looptri( const MLoopTri *looptri = NULL; bool vert_allocated = false; bool loop_allocated = false; - bool looptri_allocated = false; BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI); @@ -1150,12 +1149,7 @@ BVHTree *bvhtree_from_mesh_looptri( mpoly = DM_get_poly_array(dm, &poly_allocated); mloop = DM_get_loop_array(dm, &loop_allocated); - looptri = DM_get_looptri_array( - dm, - mvert, - mpoly, dm->getNumPolys(dm), - mloop, dm->getNumLoops(dm), - &looptri_allocated); + looptri = dm->getLoopTriArray(dm); if (poly_allocated) { MEM_freeN(mpoly); @@ -1193,7 +1187,7 @@ BVHTree *bvhtree_from_mesh_looptri( data, tree, true, epsilon, mvert, vert_allocated, mloop, loop_allocated, - looptri, looptri_allocated); + looptri, false); } else { if (vert_allocated) { @@ -1202,9 +1196,6 @@ BVHTree *bvhtree_from_mesh_looptri( if (loop_allocated) { MEM_freeN(mloop); } - if (looptri_allocated) { - MEM_freeN((void *)looptri); - } memset(data, 0, sizeof(*data)); } diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index cf619a32783..1916531b066 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -66,7 +66,7 @@ void BKE_cachefiles_exit(void) void *BKE_cachefile_add(Main *bmain, const char *name) { - CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name); + CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name, 0); BKE_cachefile_init(cache_file); @@ -100,16 +100,26 @@ void BKE_cachefile_free(CacheFile *cache_file) BLI_freelistN(&cache_file->object_paths); } -CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file) +/** + * Only copy internal data of CacheFile ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_cachefile_copy_data( + Main *UNUSED(bmain), CacheFile *cache_file_dst, const CacheFile *UNUSED(cache_file_src), const int UNUSED(flag)) { - CacheFile *new_cache_file = BKE_libblock_copy(bmain, &cache_file->id); - new_cache_file->handle = NULL; - - BLI_listbase_clear(&new_cache_file->object_paths); - - BKE_id_copy_ensure_local(bmain, &cache_file->id, &new_cache_file->id); + cache_file_dst->handle = NULL; + BLI_listbase_clear(&cache_file_dst->object_paths); +} - return new_cache_file; +CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file) +{ + CacheFile *cache_file_copy; + BKE_id_copy_ex(bmain, &cache_file->id, (ID **)&cache_file_copy, 0, false); + return cache_file_copy; } void BKE_cachefile_make_local(Main *bmain, CacheFile *cache_file, const bool lib_local) diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 915c08674a4..719125b3317 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -86,22 +86,31 @@ void *BKE_camera_add(Main *bmain, const char *name) { Camera *cam; - cam = BKE_libblock_alloc(bmain, ID_CA, name); + cam = BKE_libblock_alloc(bmain, ID_CA, name, 0); BKE_camera_init(cam); return cam; } -Camera *BKE_camera_copy(Main *bmain, const Camera *cam) +/** + * Only copy internal data of Camera ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_camera_copy_data(Main *UNUSED(bmain), Camera *UNUSED(cam_dst), const Camera *UNUSED(cam_src), const int UNUSED(flag)) { - Camera *camn; - - camn = BKE_libblock_copy(bmain, &cam->id); - - BKE_id_copy_ensure_local(bmain, &cam->id, &camn->id); + /* Nothing to do! */ +} - return camn; +Camera *BKE_camera_copy(Main *bmain, const Camera *cam) +{ + Camera *cam_copy; + BKE_id_copy_ex(bmain, &cam->id, (ID **)&cam_copy, 0, false); + return cam_copy; } void BKE_camera_make_local(Main *bmain, Camera *cam, const bool lib_local) diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 46a067ea0bc..2ed5cc450a4 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -34,10 +34,12 @@ * \ingroup bke */ +#include "atomic_ops.h" + #include "BLI_math.h" #include "BLI_edgehash.h" #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BKE_pbvh.h" #include "BKE_cdderivedmesh.h" @@ -660,6 +662,11 @@ static void cdDM_drawMappedFaces( const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); + if (cddm->pbvh) { + if (G.debug_value == 14) + BKE_pbvh_draw_BB(cddm->pbvh); + } + /* fist, setup common buffers */ GPU_vertex_setup(dm); GPU_triangle_setup(dm); @@ -745,8 +752,18 @@ static void cdDM_drawMappedFaces( /* avoid buffer problems in following code */ } else if (setDrawOptions == NULL) { + const bool show_alpha = true; + if (show_alpha) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + /* just draw the entire face array */ GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, 0, tot_tri_elem); + + if (show_alpha) { + glDisable(GL_BLEND); + } } else { for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) { @@ -1518,8 +1535,8 @@ static void cdDM_buffer_copy_mcol( for (i = 0; i < totpoly; i++, mpoly++) { for (j = 0; j < mpoly->totloop; j++) { - copy_v3_v3_uchar(&varray[start], &mloopcol[mpoly->loopstart + j].r); - start += 3; + copy_v4_v4_uchar(&varray[start], &mloopcol[mpoly->loopstart + j].r); + start += 4; } } } @@ -1919,25 +1936,17 @@ void CDDM_recalc_looptri(DerivedMesh *dm) const unsigned int totloop = dm->numLoopData; DM_ensure_looptri_data(dm); + BLI_assert(totpoly == 0 || cddm->dm.looptris.array_wip != NULL); BKE_mesh_recalc_looptri( cddm->mloop, cddm->mpoly, cddm->mvert, totloop, totpoly, - cddm->dm.looptris.array); -} - -static const MLoopTri *cdDM_getLoopTriArray(DerivedMesh *dm) -{ - if (dm->looptris.array) { - BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); - } - else { - dm->recalcLoopTri(dm); + cddm->dm.looptris.array_wip); - /* ccdm is an exception here, that recalcLoopTri will fill in the array too */ - } - return dm->looptris.array; + BLI_assert(cddm->dm.looptris.array == NULL); + atomic_cas_ptr((void **)&cddm->dm.looptris.array, cddm->dm.looptris.array, cddm->dm.looptris.array_wip); + cddm->dm.looptris.array_wip = NULL; } static void cdDM_free_internal(CDDerivedMesh *cddm) @@ -1990,8 +1999,6 @@ static CDDerivedMesh *cdDM_create(const char *desc) dm->getEdgeDataArray = DM_get_edge_data_layer; dm->getTessFaceDataArray = DM_get_tessface_data_layer; - dm->getLoopTriArray = cdDM_getLoopTriArray; - dm->calcNormals = CDDM_calc_normals; dm->calcLoopNormals = CDDM_calc_loop_normals; dm->calcLoopNormalsSpaceArray = CDDM_calc_loop_normals_spacearr; @@ -3184,7 +3191,7 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int MPoly *target_poly = cddm->mpoly + *(cddm->pmap[v_target].indices + i_poly); if (cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, +1) || - cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, -1)) + cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, -1)) { found = true; break; diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index ee0fde1ea61..dd93606a67c 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -807,7 +807,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d if ( !dm ) return 0; - DM_ensure_looptri(dm); cloth_from_mesh ( clmd, dm ); // create springs diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 07a6b304dff..7ad2ed91e87 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1019,7 +1019,7 @@ static void vectomat(const float vec[3], const float target_up[3], short axis, s } /* project the up vector onto the plane specified by n */ - project_v3_v3v3(proj, u, n); /* first u onto n... */ + project_v3_v3v3_normalized(proj, u, n); /* first u onto n... */ sub_v3_v3v3(proj, u, proj); /* then onto the plane */ /* proj specifies the transformation of the up axis */ @@ -1930,7 +1930,7 @@ static void samevolume_evaluate(bConstraint *con, bConstraintOb *cob, ListBase * /* calculate normalizing scale factor for non-essential values */ if (obsize[data->flag] != 0) - fac = sqrtf(volume / obsize[data->flag]) / obsize[data->flag]; + fac = sqrtf(volume / obsize[data->flag]); /* apply scaling factor to the channels not being kept */ switch (data->flag) { @@ -4737,29 +4737,30 @@ static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool i } /* duplicate all of the constraints in a constraint stack */ -void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern) +void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern) { bConstraint *con, *srccon; - + BLI_listbase_clear(dst); BLI_duplicatelist(dst, src); - + for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - + /* make a new copy of the constraint's data */ con->data = MEM_dupallocN(con->data); - + /* only do specific constraints if required */ if (cti) { /* perform custom copying operations if needed */ if (cti->copy_data) cti->copy_data(con, srccon); - - /* fix usercounts for all referenced data in referenced data */ - if (cti->id_looper) + + /* Fix usercounts for all referenced data that need it. */ + if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { cti->id_looper(con, con_fix_copied_refs_cb, NULL); - + } + /* for proxies we don't want to make extern */ if (do_extern) { /* go over used ID-links for this constraint to ensure that they are valid for proxies */ @@ -4770,6 +4771,11 @@ void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern) } } +void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern) +{ + BKE_constraints_copy_ex(dst, src, 0, do_extern); +} + /* ......... */ bConstraint *BKE_constraints_find_name(ListBase *list, const char *name) diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 7c22a34c7d1..9c7473f24d1 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -179,7 +179,7 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type) { Curve *cu; - cu = BKE_libblock_alloc(bmain, ID_CU, name); + cu = BKE_libblock_alloc(bmain, ID_CU, name, 0); cu->type = type; BKE_curve_init(cu); @@ -187,42 +187,39 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type) return cu; } -Curve *BKE_curve_copy(Main *bmain, const Curve *cu) +/** + * Only copy internal data of Curve ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const int flag) { - Curve *cun; - int a; + BLI_listbase_clear(&cu_dst->nurb); + BKE_nurbList_duplicate(&(cu_dst->nurb), &(cu_src->nurb)); - cun = BKE_libblock_copy(bmain, &cu->id); + cu_dst->mat = MEM_dupallocN(cu_src->mat); - BLI_listbase_clear(&cun->nurb); - BKE_nurbList_duplicate(&(cun->nurb), &(cu->nurb)); + cu_dst->str = MEM_dupallocN(cu_src->str); + cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo); + cu_dst->tb = MEM_dupallocN(cu_src->tb); + cu_dst->bb = MEM_dupallocN(cu_src->bb); - cun->mat = MEM_dupallocN(cu->mat); - for (a = 0; a < cun->totcol; a++) { - id_us_plus((ID *)cun->mat[a]); + if (cu_src->key) { + BKE_id_copy_ex(bmain, &cu_src->key->id, (ID **)&cu_dst->key, flag, false); } - cun->str = MEM_dupallocN(cu->str); - cun->strinfo = MEM_dupallocN(cu->strinfo); - cun->tb = MEM_dupallocN(cu->tb); - cun->bb = MEM_dupallocN(cu->bb); - - if (cu->key) { - cun->key = BKE_key_copy(bmain, cu->key); - cun->key->from = (ID *)cun; - } - - cun->editnurb = NULL; - cun->editfont = NULL; - - id_us_plus((ID *)cun->vfont); - id_us_plus((ID *)cun->vfontb); - id_us_plus((ID *)cun->vfonti); - id_us_plus((ID *)cun->vfontbi); - - BKE_id_copy_ensure_local(bmain, &cu->id, &cun->id); + cu_dst->editnurb = NULL; + cu_dst->editfont = NULL; +} - return cun; +Curve *BKE_curve_copy(Main *bmain, const Curve *cu) +{ + Curve *cu_copy; + BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, 0, false); + return cu_copy; } void BKE_curve_make_local(Main *bmain, Curve *cu, const bool lib_local) @@ -4042,7 +4039,7 @@ bool BKE_nurb_check_valid_u(struct Nurb *nu) return true; /* not a nurb, lets assume its valid */ if (nu->pntsu < nu->orderu) return false; - if (((nu->flag & CU_NURB_CYCLIC) == 0) && (nu->flagu & CU_NURB_BEZIER)) { /* Bezier U Endpoints */ + if (((nu->flagu & CU_NURB_CYCLIC) == 0) && (nu->flagu & CU_NURB_BEZIER)) { /* Bezier U Endpoints */ if (nu->orderu == 4) { if (nu->pntsu < 5) return false; /* bezier with 4 orderu needs 5 points */ @@ -4063,7 +4060,7 @@ bool BKE_nurb_check_valid_v(struct Nurb *nu) if (nu->pntsv < nu->orderv) return false; - if (((nu->flag & CU_NURB_CYCLIC) == 0) && (nu->flagv & CU_NURB_BEZIER)) { /* Bezier V Endpoints */ + if (((nu->flagv & CU_NURB_CYCLIC) == 0) && (nu->flagv & CU_NURB_BEZIER)) { /* Bezier V Endpoints */ if (nu->orderv == 4) { if (nu->pntsv < 5) return false; /* bezier with 4 orderu needs 5 points */ @@ -4445,7 +4442,9 @@ bool BKE_curve_center_bounds(Curve *cu, float cent[3]) } -void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, const float unit_scale) +void BKE_curve_transform_ex( + Curve *cu, float mat[4][4], + const bool do_keys, const bool do_props, const float unit_scale) { Nurb *nu; BPoint *bp; @@ -4459,7 +4458,9 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons mul_m4_v3(mat, bezt->vec[0]); mul_m4_v3(mat, bezt->vec[1]); mul_m4_v3(mat, bezt->vec[2]); - bezt->radius *= unit_scale; + if (do_props) { + bezt->radius *= unit_scale; + } } BKE_nurb_handles_calc(nu); } @@ -4467,7 +4468,9 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons i = nu->pntsu * nu->pntsv; for (bp = nu->bp; i--; bp++) { mul_m4_v3(mat, bp->vec); - bp->radius *= unit_scale; + if (do_props) { + bp->radius *= unit_scale; + } } } } @@ -4483,10 +4486,12 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons } } -void BKE_curve_transform(Curve *cu, float mat[4][4], const bool do_keys) +void BKE_curve_transform( + Curve *cu, float mat[4][4], + const bool do_keys, const bool do_props) { float unit_scale = mat4_to_scale(mat); - BKE_curve_transform_ex(cu, mat, do_keys, unit_scale); + BKE_curve_transform_ex(cu, mat, do_keys, do_props, unit_scale); } void BKE_curve_translate(Curve *cu, float offset[3], const bool do_keys) @@ -4675,14 +4680,3 @@ void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx), BKE_curve_texspace_calc(curve); } } - -void BKE_curve_eval_path(EvaluationContext *UNUSED(eval_ctx), - Curve *curve) -{ - /* TODO(sergey): This will probably need to be a part of - * the modifier stack still. - */ - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s on %s\n", __func__, curve->id.name); - } -} diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 0939d35ed8d..68acb60f21a 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -828,10 +828,10 @@ static void layerInterp_mloopcol( * although weights should also not cause this situation */ /* also delay writing to the destination incase dest is in sources */ - mc->r = CLAMPIS(iroundf(col.r), 0, 255); - mc->g = CLAMPIS(iroundf(col.g), 0, 255); - mc->b = CLAMPIS(iroundf(col.b), 0, 255); - mc->a = CLAMPIS(iroundf(col.a), 0, 255); + mc->r = round_fl_to_uchar_clamp(col.r); + mc->g = round_fl_to_uchar_clamp(col.g); + mc->b = round_fl_to_uchar_clamp(col.b); + mc->a = round_fl_to_uchar_clamp(col.a); } static int layerMaxNum_mloopcol(void) @@ -1054,10 +1054,10 @@ static void layerInterp_mcol( /* Subdivide smooth or fractal can cause problems without clamping * although weights should also not cause this situation */ - mc[j].a = CLAMPIS(iroundf(col[j].a), 0, 255); - mc[j].r = CLAMPIS(iroundf(col[j].r), 0, 255); - mc[j].g = CLAMPIS(iroundf(col[j].g), 0, 255); - mc[j].b = CLAMPIS(iroundf(col[j].b), 0, 255); + mc[j].a = round_fl_to_uchar_clamp(col[j].a); + mc[j].r = round_fl_to_uchar_clamp(col[j].r); + mc[j].g = round_fl_to_uchar_clamp(col[j].g); + mc[j].b = round_fl_to_uchar_clamp(col[j].b); } } diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 69baaf5e58a..eec8d2478da 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -621,8 +621,17 @@ float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup) */ float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int index, const int defgroup) { - if (defgroup == -1 || dvert == NULL) + /* Invalid defgroup index means the vgroup selected is invalid, does not exist, in that case it is OK to return 1.0 + * (i.e. maximum weight, as if no vgroup was selected). + * But in case of valid defgroup and NULL dvert data pointer, it means that vgroup **is** valid, + * and just totally empty, so we shall return '0.0' value then! + */ + if (defgroup == -1) { return 1.0f; + } + else if (dvert == NULL) { + return 0.0f; + } return defvert_find_weight(dvert + index, defgroup); } diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 019e0df1623..3ddf0f43d30 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -2018,6 +2018,7 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho int lasttime; if (!DEG_depsgraph_use_legacy()) { + DEG_scene_flush_update(bmain, sce); return; } diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 1db69d23607..ae896176b6d 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2060,9 +2060,6 @@ DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scen if (pmd->canvas) { DerivedMesh *ret; - /* For now generate looptris in every case */ - DM_ensure_looptri(dm); - /* Update canvas data for a new frame */ dynamicPaint_frameUpdate(pmd, scene, ob, dm); @@ -2072,9 +2069,6 @@ DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scen return ret; } else { - /* For now generate looptris in every case */ - DM_ensure_looptri(dm); - /* Update canvas data for a new frame */ dynamicPaint_frameUpdate(pmd, scene, ob, dm); diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index ab614b8f460..d810dac7365 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -41,6 +41,8 @@ * is likely to be a little slow. */ +#include "atomic_ops.h" + #include "BLI_math.h" #include "BLI_jitter.h" #include "BLI_bitmap.h" @@ -641,8 +643,9 @@ static void emDM_recalcLoopTri(DerivedMesh *dm) int i; DM_ensure_looptri_data(dm); - mlooptri = dm->looptris.array; + mlooptri = dm->looptris.array_wip; + BLI_assert(tottri == 0 || mlooptri != NULL); BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); BLI_assert(tottri == dm->looptris.num); @@ -659,18 +662,10 @@ static void emDM_recalcLoopTri(DerivedMesh *dm) BM_elem_index_get(ltri[2])); lt->poly = BM_elem_index_get(ltri[0]->f); } -} - -static const MLoopTri *emDM_getLoopTriArray(DerivedMesh *dm) -{ - if (dm->looptris.array) { - BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); - } - else { - dm->recalcLoopTri(dm); - } - return dm->looptris.array; + BLI_assert(dm->looptris.array == NULL); + atomic_cas_ptr((void **)&dm->looptris.array, dm->looptris.array, dm->looptris.array_wip); + dm->looptris.array_wip = NULL; } static void emDM_foreachMappedVert( @@ -2259,8 +2254,6 @@ DerivedMesh *getEditDerivedBMesh( bmdm->dm.getNumLoops = emDM_getNumLoops; bmdm->dm.getNumPolys = emDM_getNumPolys; - bmdm->dm.getLoopTriArray = emDM_getLoopTriArray; - bmdm->dm.getVert = emDM_getVert; bmdm->dm.getVertCo = emDM_getVertCo; bmdm->dm.getVertNo = emDM_getVertNo; diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c index 8247336d915..8e98a9f672d 100644 --- a/source/blender/blenkernel/intern/fluidsim.c +++ b/source/blender/blenkernel/intern/fluidsim.c @@ -80,8 +80,6 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob, dm = mesh_create_derived_index_render(scene, ob, CD_MASK_BAREMESH, modifierIndex); - DM_ensure_looptri(dm); - mvert = dm->getVertArray(dm); mloop = dm->getLoopArray(dm); looptri = dm->getLoopTriArray(dm); diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 401fed74c52..d6b28cfaf70 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -106,6 +106,23 @@ void BKE_vfont_free(struct VFont *vf) } } +void BKE_vfont_copy_data(Main *UNUSED(bmain), VFont *vfont_dst, const VFont *UNUSED(vfont_src), const int flag) +{ + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; + + /* Just to be sure, should not have any value actually after reading time. */ + vfont_dst->temp_pf = NULL; + + if (vfont_dst->packedfile) { + vfont_dst->packedfile = dupPackedFile(vfont_dst->packedfile); + } + + if (vfont_dst->data) { + vfont_dst->data = BLI_vfontdata_copy(vfont_dst->data, flag_subdata); + } +} + static void *builtin_font_data = NULL; static int builtin_font_size = 0; @@ -249,7 +266,7 @@ VFont *BKE_vfont_load(Main *bmain, const char *filepath) vfd = BLI_vfontdata_from_freetypefont(pf); if (vfd) { - vfont = BKE_libblock_alloc(bmain, ID_VF, filename); + vfont = BKE_libblock_alloc(bmain, ID_VF, filename, 0); vfont->data = vfd; /* if there's a font name, use it for the ID name */ diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c index 0a0b023df82..e45a938a4fc 100644 --- a/source/blender/blenkernel/intern/freestyle.c +++ b/source/blender/blenkernel/intern/freestyle.c @@ -44,7 +44,7 @@ // function declarations static FreestyleLineSet *alloc_lineset(void); -static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset); +static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset, const int flag); static FreestyleModuleConfig *alloc_module(void); static void copy_module(FreestyleModuleConfig *new_module, FreestyleModuleConfig *module); @@ -79,7 +79,7 @@ void BKE_freestyle_config_free(FreestyleConfig *config) BLI_freelistN(&config->modules); } -void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config) +void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag) { FreestyleLineSet *lineset, *new_lineset; FreestyleModuleConfig *module, *new_module; @@ -93,7 +93,7 @@ void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *con BLI_listbase_clear(&new_config->linesets); for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) { new_lineset = alloc_lineset(); - copy_lineset(new_lineset, lineset); + copy_lineset(new_lineset, lineset, flag); BLI_addtail(&new_config->linesets, (void *)new_lineset); } @@ -105,11 +105,9 @@ void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *con } } -static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset) +static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset, const int flag) { new_lineset->linestyle = lineset->linestyle; - if (new_lineset->linestyle) - id_us_plus(&new_lineset->linestyle->id); new_lineset->flags = lineset->flags; new_lineset->selection = lineset->selection; new_lineset->qi = lineset->qi; @@ -118,10 +116,12 @@ static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *linese new_lineset->edge_types = lineset->edge_types; new_lineset->exclude_edge_types = lineset->exclude_edge_types; new_lineset->group = lineset->group; - if (new_lineset->group) { - id_us_plus(&new_lineset->group->id); - } strcpy(new_lineset->name, lineset->name); + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)new_lineset->linestyle); + id_us_plus((ID *)new_lineset->group); + } } static FreestyleModuleConfig *alloc_module(void) diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 758438bb051..ee0d0b41898 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -627,7 +627,7 @@ bGPdata *BKE_gpencil_data_addnew(const char name[]) bGPdata *gpd; /* allocate memory for a new block */ - gpd = BKE_libblock_alloc(G.main, ID_GD, name); + gpd = BKE_libblock_alloc(G.main, ID_GD, name, 0); /* initial settings */ gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND); @@ -753,47 +753,62 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) return gpl_dst; } -/* make a copy of a given gpencil datablock */ -bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy) +/** + * Only copy internal data of GreasePencil ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag)) { - const bGPDlayer *gpl_src; - bGPDlayer *gpl_dst; - bGPdata *gpd_dst; + /* copy layers */ + BLI_listbase_clear(&gpd_dst->layers); + for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { + /* make a copy of source layer and its data */ + bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src); /* TODO here too could add unused flags... */ + BLI_addtail(&gpd_dst->layers, gpl_dst); + } - /* error checking */ - if (gpd_src == NULL) { - return NULL; + /* copy palettes */ + BLI_listbase_clear(&gpd_dst->palettes); + for (const bGPDpalette *palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) { + bGPDpalette *palette_dst = BKE_gpencil_palette_duplicate(palette_src); /* TODO here too could add unused flags... */ + BLI_addtail(&gpd_dst->palettes, palette_dst); } - - /* make a copy of the base-data */ +} + +/* make a copy of a given gpencil datablock */ +bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy) +{ + /* Yuck and super-uber-hyper yuck!!! + * Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it, + * so for now keep old code for that one. */ if (internal_copy) { + const bGPDlayer *gpl_src; + bGPDlayer *gpl_dst; + bGPdata *gpd_dst; + /* make a straight copy for undo buffers used during stroke drawing */ gpd_dst = MEM_dupallocN(gpd_src); + + /* copy layers */ + BLI_listbase_clear(&gpd_dst->layers); + for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { + /* make a copy of source layer and its data */ + gpl_dst = BKE_gpencil_layer_duplicate(gpl_src); + BLI_addtail(&gpd_dst->layers, gpl_dst); + } + + /* return new */ + return gpd_dst; } else { - /* make a copy when others use this */ - gpd_dst = BKE_libblock_copy(bmain, &gpd_src->id); - } - - /* copy layers */ - BLI_listbase_clear(&gpd_dst->layers); - for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { - /* make a copy of source layer and its data */ - gpl_dst = BKE_gpencil_layer_duplicate(gpl_src); - BLI_addtail(&gpd_dst->layers, gpl_dst); - } - if (!internal_copy) { - /* copy palettes */ - bGPDpalette *palette_src, *palette_dst; - BLI_listbase_clear(&gpd_dst->palettes); - for (palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) { - palette_dst = BKE_gpencil_palette_duplicate(palette_src); - BLI_addtail(&gpd_dst->palettes, palette_dst); - } + bGPdata *gpd_copy; + BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_copy, 0, false); + return gpd_copy; } - - /* return new */ - return gpd_dst; } void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local) diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index 932f41ac4ba..fd6e9681e64 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -79,7 +79,7 @@ Group *BKE_group_add(Main *bmain, const char *name) { Group *group; - group = BKE_libblock_alloc(bmain, ID_GR, name); + group = BKE_libblock_alloc(bmain, ID_GR, name, 0); id_us_min(&group->id); id_us_ensure_real(&group->id); group->layer = (1 << 20) - 1; @@ -89,19 +89,32 @@ Group *BKE_group_add(Main *bmain, const char *name) return group; } -Group *BKE_group_copy(Main *bmain, const Group *group) +/** + * Only copy internal data of Group ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *group_src, const int flag) { - Group *groupn; - - groupn = BKE_libblock_copy(bmain, &group->id); - BLI_duplicatelist(&groupn->gobject, &group->gobject); + BLI_duplicatelist(&group_dst->gobject, &group_src->gobject); /* Do not copy group's preview (same behavior as for objects). */ - groupn->preview = NULL; - - BKE_id_copy_ensure_local(bmain, &group->id, &groupn->id); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ + BKE_previewimg_id_copy(&group_dst->id, &group_src->id); + } + else { + group_dst->preview = NULL; + } +} - return groupn; +Group *BKE_group_copy(Main *bmain, const Group *group) +{ + Group *group_copy; + BKE_id_copy_ex(bmain, &group->id, (ID **)&group_copy, 0, false); + return group_copy; } void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local) diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index bccf9307912..a98a1b13402 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -253,6 +253,8 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id) ID_PRV_CASE(ID_GR, Group); ID_PRV_CASE(ID_SCE, Scene); #undef ID_PRV_CASE + default: + break; } return NULL; diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index e98181be444..45b41fa01ed 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -90,7 +90,7 @@ IDProperty *IDP_NewIDPArray(const char *name) return prop; } -IDProperty *IDP_CopyIDPArray(const IDProperty *array) +IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) { /* don't use MEM_dupallocN because this may be part of an array */ IDProperty *narray, *tmp; @@ -109,7 +109,7 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array) * then free it. this makes for more maintainable * code than simply reimplementing the copy functions * in this loop.*/ - tmp = IDP_CopyProperty(GETPROP(narray, i)); + tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag); memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty)); MEM_freeN(tmp); } @@ -285,9 +285,9 @@ void IDP_FreeArray(IDProperty *prop) } -static IDProperty *idp_generic_copy(const IDProperty *prop) +static IDProperty *idp_generic_copy(const IDProperty *prop, const int UNUSED(flag)) { - IDProperty *newp = MEM_callocN(sizeof(IDProperty), "IDProperty array dup"); + IDProperty *newp = MEM_callocN(sizeof(IDProperty), __func__); BLI_strncpy(newp->name, prop->name, MAX_IDPROP_NAME); newp->type = prop->type; @@ -298,9 +298,9 @@ static IDProperty *idp_generic_copy(const IDProperty *prop) return newp; } -static IDProperty *IDP_CopyArray(const IDProperty *prop) +static IDProperty *IDP_CopyArray(const IDProperty *prop, const int flag) { - IDProperty *newp = idp_generic_copy(prop); + IDProperty *newp = idp_generic_copy(prop, flag); if (prop->data.pointer) { newp->data.pointer = MEM_dupallocN(prop->data.pointer); @@ -310,7 +310,7 @@ static IDProperty *IDP_CopyArray(const IDProperty *prop) int a; for (a = 0; a < prop->len; a++) - array[a] = IDP_CopyProperty(array[a]); + array[a] = IDP_CopyProperty_ex(array[a], flag); } } newp->len = prop->len; @@ -363,12 +363,12 @@ IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) return prop; } -static IDProperty *IDP_CopyString(const IDProperty *prop) +static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag) { IDProperty *newp; BLI_assert(prop->type == IDP_STRING); - newp = idp_generic_copy(prop); + newp = idp_generic_copy(prop, flag); if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer); @@ -442,15 +442,17 @@ void IDP_FreeString(IDProperty *prop) /** \name IDProperty ID API * \{ */ -static IDProperty *IDP_CopyID(const IDProperty *prop) +static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag) { IDProperty *newp; BLI_assert(prop->type == IDP_ID); - newp = idp_generic_copy(prop); + newp = idp_generic_copy(prop, flag); newp->data.pointer = prop->data.pointer; - id_us_plus(IDP_Id(newp)); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus(IDP_Id(newp)); + } return newp; } @@ -467,16 +469,16 @@ static IDProperty *IDP_CopyID(const IDProperty *prop) /** * Checks if a property with the same name as prop exists, and if so replaces it. */ -static IDProperty *IDP_CopyGroup(const IDProperty *prop) +static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag) { IDProperty *newp, *link; BLI_assert(prop->type == IDP_GROUP); - newp = idp_generic_copy(prop); + newp = idp_generic_copy(prop, flag); newp->len = prop->len; for (link = prop->data.group.first; link; link = link->next) { - BLI_addtail(&newp->data.group, IDP_CopyProperty(link)); + BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag)); } return newp; @@ -730,18 +732,23 @@ static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user) /** \name IDProperty Main API * \{ */ -IDProperty *IDP_CopyProperty(const IDProperty *prop) +IDProperty *IDP_CopyProperty_ex(const IDProperty *prop, const int flag) { switch (prop->type) { - case IDP_GROUP: return IDP_CopyGroup(prop); - case IDP_STRING: return IDP_CopyString(prop); - case IDP_ID: return IDP_CopyID(prop); - case IDP_ARRAY: return IDP_CopyArray(prop); - case IDP_IDPARRAY: return IDP_CopyIDPArray(prop); - default: return idp_generic_copy(prop); + case IDP_GROUP: return IDP_CopyGroup(prop, flag); + case IDP_STRING: return IDP_CopyString(prop, flag); + case IDP_ID: return IDP_CopyID(prop, flag); + case IDP_ARRAY: return IDP_CopyArray(prop, flag); + case IDP_IDPARRAY: return IDP_CopyIDPArray(prop, flag); + default: return idp_generic_copy(prop, flag); } } +IDProperty *IDP_CopyProperty(const IDProperty *prop) +{ + return IDP_CopyProperty_ex(prop, 0); +} + /* Updates ID pointers after an object has been copied */ /* TODO Nuke this once its only user has been correctly converted to use generic ID management from BKE_library! */ void IDP_RelinkProperty(struct IDProperty *prop) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index abe08def197..90f2fe3d547 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -303,8 +303,11 @@ static void image_free_anims(Image *ima) * Simply free the image data from memory, * on display the image can load again (except for render buffers). */ -void BKE_image_free_buffers(Image *ima) +void BKE_image_free_buffers_ex(Image *ima, bool do_lock) { + if (do_lock) { + BLI_spin_lock(&image_spin); + } image_free_cached_frames(ima); image_free_anims(ima); @@ -323,6 +326,15 @@ void BKE_image_free_buffers(Image *ima) } ima->ok = IMA_OK; + + if (do_lock) { + BLI_spin_unlock(&image_spin); + } +} + +void BKE_image_free_buffers(Image *ima) +{ + BKE_image_free_buffers_ex(ima, false); } /** Free (or release) any data used by this image (does not free the image itself). */ @@ -382,7 +394,7 @@ static Image *image_alloc(Main *bmain, const char *name, short source, short typ { Image *ima; - ima = BKE_libblock_alloc(bmain, ID_IM, name); + ima = BKE_libblock_alloc(bmain, ID_IM, name, 0); if (ima) { image_init(ima, source, type); } @@ -433,39 +445,53 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src) } } -/* empty image block, of similar type and filename */ -Image *BKE_image_copy(Main *bmain, const Image *ima) +/** + * Only copy internal data of Image ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_image_copy_data(Main *UNUSED(bmain), Image *ima_dst, const Image *ima_src, const int flag) { - Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type); - - BLI_strncpy(nima->name, ima->name, sizeof(ima->name)); - - nima->flag = ima->flag; - nima->tpageflag = ima->tpageflag; - - nima->gen_x = ima->gen_x; - nima->gen_y = ima->gen_y; - nima->gen_type = ima->gen_type; - copy_v4_v4(nima->gen_color, ima->gen_color); + BKE_color_managed_colorspace_settings_copy(&ima_dst->colorspace_settings, &ima_src->colorspace_settings); - nima->animspeed = ima->animspeed; + copy_image_packedfiles(&ima_dst->packedfiles, &ima_src->packedfiles); - nima->aspx = ima->aspx; - nima->aspy = ima->aspy; + ima_dst->stereo3d_format = MEM_dupallocN(ima_src->stereo3d_format); + BLI_duplicatelist(&ima_dst->views, &ima_src->views); - BKE_color_managed_colorspace_settings_copy(&nima->colorspace_settings, &ima->colorspace_settings); - - copy_image_packedfiles(&nima->packedfiles, &ima->packedfiles); + /* Cleanup stuff that cannot be copied. */ + ima_dst->cache = NULL; + ima_dst->rr = NULL; + for (int i = 0; i < IMA_MAX_RENDER_SLOT; i++) { + ima_dst->renders[i] = NULL; + } - /* nima->stere3d_format is already allocated by image_alloc... */ - *nima->stereo3d_format = *ima->stereo3d_format; - BLI_duplicatelist(&nima->views, &ima->views); + BLI_listbase_clear(&ima_dst->anims); - BKE_previewimg_id_copy(&nima->id, &ima->id); + ima_dst->totbind = 0; + for (int i = 0; i < TEXTARGET_COUNT; i++) { + ima_dst->bindcode[i] = 0; + ima_dst->gputexture[i] = NULL; + } + ima_dst->repbind = NULL; - BKE_id_copy_ensure_local(bmain, &ima->id, &nima->id); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&ima_dst->id, &ima_src->id); + } + else { + ima_dst->preview = NULL; + } +} - return nima; +/* empty image block, of similar type and filename */ +Image *BKE_image_copy(Main *bmain, const Image *ima) +{ + Image *ima_copy; + BKE_id_copy_ex(bmain, &ima->id, (ID **)&ima_copy, 0, false); + return ima_copy; } void BKE_image_make_local(Main *bmain, Image *ima, const bool lib_local) @@ -1177,7 +1203,6 @@ bool BKE_imtype_is_movie(const char imtype) switch (imtype) { case R_IMF_IMTYPE_AVIRAW: case R_IMF_IMTYPE_AVIJPEG: - case R_IMF_IMTYPE_QUICKTIME: case R_IMF_IMTYPE_FFMPEG: case R_IMF_IMTYPE_H264: case R_IMF_IMTYPE_THEORA: @@ -1249,7 +1274,6 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file) case R_IMF_IMTYPE_MULTILAYER: case R_IMF_IMTYPE_DDS: case R_IMF_IMTYPE_JP2: - case R_IMF_IMTYPE_QUICKTIME: case R_IMF_IMTYPE_DPX: chan_flag |= IMA_CHAN_FLAG_ALPHA; break; @@ -1312,7 +1336,6 @@ char BKE_imtype_from_arg(const char *imtype_arg) else if (STREQ(imtype_arg, "AVIRAW")) return R_IMF_IMTYPE_AVIRAW; else if (STREQ(imtype_arg, "AVIJPEG")) return R_IMF_IMTYPE_AVIJPEG; else if (STREQ(imtype_arg, "PNG")) return R_IMF_IMTYPE_PNG; - else if (STREQ(imtype_arg, "QUICKTIME")) return R_IMF_IMTYPE_QUICKTIME; else if (STREQ(imtype_arg, "BMP")) return R_IMF_IMTYPE_BMP; #ifdef WITH_HDR else if (STREQ(imtype_arg, "HDR")) return R_IMF_IMTYPE_RADHDR; @@ -1423,7 +1446,7 @@ static bool do_add_image_extension(char *string, const char imtype, const ImageF } } #endif - else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90, R_IMF_IMTYPE_QUICKTIME etc + else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90 etc if (!(BLI_testextensie_n(string, extension_test = ".jpg", ".jpeg", NULL))) extension = extension_test; } @@ -1431,8 +1454,7 @@ static bool do_add_image_extension(char *string, const char imtype, const ImageF if (extension) { /* prefer this in many cases to avoid .png.tga, but in certain cases it breaks */ /* remove any other known image extension */ - if (BLI_testextensie_array(string, imb_ext_image) || - (G.have_quicktime && BLI_testextensie_array(string, imb_ext_image_qt))) + if (BLI_testextensie_array(string, imb_ext_image)) { return BLI_replace_extension(string, FILE_MAX, extension); } @@ -1709,7 +1731,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d } { - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); RenderStats *stats = re ? RE_GetStats(re) : NULL; if (stats && (scene->r.stamp & R_STAMP_RENDERTIME)) { @@ -2903,7 +2925,7 @@ RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima) } else if (ima->type == IMA_TYPE_R_RESULT) { if (ima->render_slot == ima->last_render_slot) - rr = RE_AcquireResultRead(RE_GetRender(scene->id.name)); + rr = RE_AcquireResultRead(RE_GetSceneRender(scene)); else rr = ima->renders[ima->render_slot]; @@ -2921,7 +2943,7 @@ void BKE_image_release_renderresult(Scene *scene, Image *ima) } else if (ima->type == IMA_TYPE_R_RESULT) { if (ima->render_slot == ima->last_render_slot) - RE_ReleaseResult(RE_GetRender(scene->id.name)); + RE_ReleaseResult(RE_GetSceneRender(scene)); } } @@ -2941,7 +2963,7 @@ void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot) { /* called right before rendering, ima->renders contains render * result pointers for everything but the current render */ - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); int slot = ima->render_slot, last = ima->last_render_slot; if (slot != last) { @@ -3666,7 +3688,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc if (!r_lock) return NULL; - re = RE_GetRender(iuser->scene->id.name); + re = RE_GetSceneRender(iuser->scene); channels = 4; layer = iuser->layer; diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c index 2c8399adece..1f1f4c9d341 100644 --- a/source/blender/blenkernel/intern/image_gen.c +++ b/source/blender/blenkernel/intern/image_gen.c @@ -132,7 +132,7 @@ static void image_buf_fill_checker_slice(unsigned char *rect, float hsv[3] = {0.0f, 0.9f, 0.9f}; float rgb[3]; - float dark_linear_color, bright_linear_color; + float dark_linear_color = 0.0f, bright_linear_color = 0.0f; if (rect_float != NULL) { dark_linear_color = srgb_to_linearrgb(0.25f); bright_linear_color = srgb_to_linearrgb(0.58f); diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 98b251294ae..fd42556067e 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -107,7 +107,7 @@ Key *BKE_key_add(ID *id) /* common function */ Key *key; char *el; - key = BKE_libblock_alloc(G.main, ID_KE, "Key"); + key = BKE_libblock_alloc(G.main, ID_KE, "Key", 0); key->type = KEY_NORMAL; key->from = id; @@ -146,36 +146,48 @@ Key *BKE_key_add(ID *id) /* common function */ key->elemsize = 16; break; + + default: + break; } return key; } -Key *BKE_key_copy(Main *bmain, const Key *key) +/** + * Only copy internal data of ShapeKey ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_key_copy_data(Main *UNUSED(bmain), Key *key_dst, const Key *key_src, const int UNUSED(flag)) { - Key *keyn; - KeyBlock *kbn, *kb; - - keyn = BKE_libblock_copy(bmain, &key->id); - - BLI_duplicatelist(&keyn->block, &key->block); - - kb = key->block.first; - kbn = keyn->block.first; - while (kbn) { - - if (kbn->data) kbn->data = MEM_dupallocN(kbn->data); - if (kb == key->refkey) keyn->refkey = kbn; - - kbn = kbn->next; - kb = kb->next; - } + BLI_duplicatelist(&key_dst->block, &key_src->block); - BKE_id_copy_ensure_local(bmain, &key->id, &keyn->id); + KeyBlock *kb_dst, *kb_src; + for (kb_src = key_src->block.first, kb_dst = key_dst->block.first; + kb_dst; + kb_src = kb_src->next, kb_dst = kb_dst->next) + { + if (kb_dst->data) { + kb_dst->data = MEM_dupallocN(kb_dst->data); + } + if (kb_src == key_src->refkey) { + key_dst->refkey = kb_dst; + } + } +} - return keyn; +Key *BKE_key_copy(Main *bmain, const Key *key) +{ + Key *key_copy; + BKE_id_copy_ex(bmain, &key->id, (ID **)&key_copy, 0, false); + return key_copy; } +/* XXX TODO get rid of this! */ Key *BKE_key_copy_nolib(Key *key) { Key *keyn; @@ -1397,6 +1409,8 @@ Key **BKE_key_from_id_p(ID *id) Lattice *lt = (Lattice *)id; return <->key; } + default: + break; } return NULL; diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 2242ba379fb..e8ef346927e 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -109,42 +109,60 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name) { Lamp *la; - la = BKE_libblock_alloc(bmain, ID_LA, name); + la = BKE_libblock_alloc(bmain, ID_LA, name, 0); BKE_lamp_init(la); return la; } -Lamp *BKE_lamp_copy(Main *bmain, const Lamp *la) +/** + * Only copy internal data of Lamp ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_lamp_copy_data(Main *bmain, Lamp *la_dst, const Lamp *la_src, const int flag) { - Lamp *lan; - int a; - - lan = BKE_libblock_copy(bmain, &la->id); - - for (a = 0; a < MAX_MTEX; a++) { - if (lan->mtex[a]) { - lan->mtex[a] = MEM_mallocN(sizeof(MTex), "copylamptex"); - memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex)); - id_us_plus((ID *)lan->mtex[a]->tex); + for (int a = 0; a < MAX_MTEX; a++) { + if (la_dst->mtex[a]) { + la_dst->mtex[a] = MEM_mallocN(sizeof(*la_dst->mtex[a]), __func__); + *la_dst->mtex[a] = *la_src->mtex[a]; } } - - lan->curfalloff = curvemapping_copy(la->curfalloff); - if (la->nodetree) - lan->nodetree = ntreeCopyTree(bmain, la->nodetree); + la_dst->curfalloff = curvemapping_copy(la_src->curfalloff); - BKE_previewimg_id_copy(&lan->id, &la->id); + if (la_src->nodetree) { + BKE_id_copy_ex(bmain, (ID *)la_src->nodetree, (ID **)&la_dst->nodetree, flag, false); + } - BKE_id_copy_ensure_local(bmain, &la->id, &lan->id); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&la_dst->id, &la_src->id); + } + else { + la_dst->preview = NULL; + } +} - return lan; +Lamp *BKE_lamp_copy(Main *bmain, const Lamp *la) +{ + Lamp *la_copy; + BKE_id_copy_ex(bmain, &la->id, (ID **)&la_copy, 0, false); + return la_copy; } Lamp *localize_lamp(Lamp *la) { + /* TODO replace with something like + * Lamp *la_copy; + * BKE_id_copy_ex(bmain, &la->id, (ID **)&la_copy, LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT, false); + * return la_copy; + * + * ... Once f*** nodes are fully converted to that too :( */ + Lamp *lan; int a; diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index c9d7dddf25a..ea4c3f380ff 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -270,39 +270,46 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name) { Lattice *lt; - lt = BKE_libblock_alloc(bmain, ID_LT, name); + lt = BKE_libblock_alloc(bmain, ID_LT, name, 0); BKE_lattice_init(lt); return lt; } -Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt) +/** + * Only copy internal data of Lattice ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src, const int flag) { - Lattice *ltn; - - ltn = BKE_libblock_copy(bmain, <->id); - ltn->def = MEM_dupallocN(lt->def); + lt_dst->def = MEM_dupallocN(lt_src->def); - if (lt->key) { - ltn->key = BKE_key_copy(bmain, ltn->key); - ltn->key->from = (ID *)ltn; - } - - if (lt->dvert) { - int tot = lt->pntsu * lt->pntsv * lt->pntsw; - ltn->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); - BKE_defvert_array_copy(ltn->dvert, lt->dvert, tot); + if (lt_src->key) { + BKE_id_copy_ex(bmain, <_src->key->id, (ID **)<_dst->key, flag, false); } - ltn->editlatt = NULL; + if (lt_src->dvert) { + int tot = lt_src->pntsu * lt_src->pntsv * lt_src->pntsw; + lt_dst->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); + BKE_defvert_array_copy(lt_dst->dvert, lt_src->dvert, tot); + } - BKE_id_copy_ensure_local(bmain, <->id, <n->id); + lt_dst->editlatt = NULL; +} - return ltn; +Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt) +{ + Lattice *lt_copy; + BKE_id_copy_ex(bmain, <->id, (ID **)<_copy, 0, false); + return lt_copy; } -/** Free (or release) any data used by this lattice (does not free the lattice itself). */ + /** Free (or release) any data used by this lattice (does not free the lattice itself). */ void BKE_lattice_free(Lattice *lt) { BKE_animdata_free(<->id, false); diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 2ea7342ff34..d5dfc63b317 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -383,7 +383,6 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) switch ((ID_Type)GS(id->name)) { case ID_SCE: - /* Partially implemented (has no copy...). */ if (!test) BKE_scene_make_local(bmain, (Scene *)id, lib_local); return true; case ID_OB: @@ -423,14 +422,12 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) if (!test) BKE_world_make_local(bmain, (World *)id, lib_local); return true; case ID_VF: - /* Partially implemented (has no copy...). */ if (!test) BKE_vfont_make_local(bmain, (VFont *)id, lib_local); return true; case ID_TXT: if (!test) BKE_text_make_local(bmain, (Text *)id, lib_local); return true; case ID_SO: - /* Partially implemented (has no copy...). */ if (!test) BKE_sound_make_local(bmain, (bSound *)id, lib_local); return true; case ID_GR: @@ -484,114 +481,189 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) return false; } +struct IDCopyLibManagementData { + const ID *id_src; + ID *id_dst; + int flag; +}; + +/* Increases usercount as required, and remap self ID pointers. */ +static int id_copy_libmanagement_cb(void *user_data, ID *UNUSED(id_self), ID **id_pointer, int cb_flag) +{ + struct IDCopyLibManagementData *data = user_data; + ID *id = *id_pointer; + + /* Remap self-references to new copied ID. */ + if (id == data->id_src) { + /* We cannot use id_self here, it is not *always* id_dst (thanks to $£!+@#&/? nodetrees). */ + id = *id_pointer = data->id_dst; + } + + /* Increase used IDs refcount if needed and required. */ + if ((data->flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0 && (cb_flag & IDWALK_CB_USER)) { + id_us_plus(id); + } + + return IDWALK_RET_NOP; +} + /** - * Invokes the appropriate copy method for the block and returns the result in - * newid, unless test. Returns true if the block can be copied. + * Generic entry point for copying a datablock (new API). + * + * \note Copy is only affecting given data-block (no ID used by copied one will be affected, besides usercount). + * There is only one exception, if LIB_ID_COPY_ACTIONS is defined, actions used by animdata will be duplicated. + * + * \note Usercount of new copy is always set to 1. + * + * \param bmain Main database, may be NULL only if LIB_ID_COPY_NO_MAIN is specified. + * \param id Source datablock. + * \param r_newid Pointer to new (copied) ID pointer. + * \param flag Set of copy options, see DNA_ID.h enum for details (leave to zero for default, full copy). + * \param test If set, do not do any copy, just test whether copy is supported. + * \return False when copying that ID type is not supported, true otherwise. */ -bool id_copy(Main *bmain, const ID *id, ID **newid, bool test) +/* XXX TODO remove test thing, *all* IDs should be copyable that way! */ +bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, const bool test) { - if (!test) { - *newid = NULL; +#define LIB_ID_TYPES_NOCOPY ID_LI, ID_SCR, ID_WM, /* Not supported */ \ + ID_IP /* Deprecated */ + + BLI_assert(test || (r_newid != NULL)); + if (r_newid != NULL) { + *r_newid = NULL; + } + if (id == NULL) { + return false; + } + + if (ELEM(GS(id->name), LIB_ID_TYPES_NOCOPY)) { + return false; + } + else if (test) { + return true; } - /* conventions: - * - make shallow copy, only this ID block - * - id.us of the new ID is set to 1 */ + BKE_libblock_copy_ex(bmain, id, r_newid, flag); + switch ((ID_Type)GS(id->name)) { + case ID_SCE: + BKE_scene_copy_data(bmain, (Scene *)*r_newid, (Scene *)id, flag); + break; case ID_OB: - if (!test) *newid = (ID *)BKE_object_copy(bmain, (Object *)id); - return true; + BKE_object_copy_data(bmain, (Object *)*r_newid, (Object *)id, flag); + break; case ID_ME: - if (!test) *newid = (ID *)BKE_mesh_copy(bmain, (Mesh *)id); - return true; + BKE_mesh_copy_data(bmain, (Mesh *)*r_newid, (Mesh *)id, flag); + break; case ID_CU: - if (!test) *newid = (ID *)BKE_curve_copy(bmain, (Curve *)id); - return true; + BKE_curve_copy_data(bmain, (Curve *)*r_newid, (Curve *)id, flag); + break; case ID_MB: - if (!test) *newid = (ID *)BKE_mball_copy(bmain, (MetaBall *)id); - return true; + BKE_mball_copy_data(bmain, (MetaBall *)*r_newid, (MetaBall *)id, flag); + break; case ID_MA: - if (!test) *newid = (ID *)BKE_material_copy(bmain, (Material *)id); - return true; + BKE_material_copy_data(bmain, (Material *)*r_newid, (Material *)id, flag); + break; case ID_TE: - if (!test) *newid = (ID *)BKE_texture_copy(bmain, (Tex *)id); - return true; + BKE_texture_copy_data(bmain, (Tex *)*r_newid, (Tex *)id, flag); + break; case ID_IM: - if (!test) *newid = (ID *)BKE_image_copy(bmain, (Image *)id); - return true; + BKE_image_copy_data(bmain, (Image *)*r_newid, (Image *)id, flag); + break; case ID_LT: - if (!test) *newid = (ID *)BKE_lattice_copy(bmain, (Lattice *)id); - return true; + BKE_lattice_copy_data(bmain, (Lattice *)*r_newid, (Lattice *)id, flag); + break; case ID_LA: - if (!test) *newid = (ID *)BKE_lamp_copy(bmain, (Lamp *)id); - return true; + BKE_lamp_copy_data(bmain, (Lamp *)*r_newid, (Lamp *)id, flag); + break; case ID_SPK: - if (!test) *newid = (ID *)BKE_speaker_copy(bmain, (Speaker *)id); - return true; + BKE_speaker_copy_data(bmain, (Speaker *)*r_newid, (Speaker *)id, flag); + break; case ID_CA: - if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id); - return true; + BKE_camera_copy_data(bmain, (Camera *)*r_newid, (Camera *)id, flag); + break; case ID_KE: - if (!test) *newid = (ID *)BKE_key_copy(bmain, (Key *)id); - return true; + BKE_key_copy_data(bmain, (Key *)*r_newid, (Key *)id, flag); + break; case ID_WO: - if (!test) *newid = (ID *)BKE_world_copy(bmain, (World *)id); - return true; + BKE_world_copy_data(bmain, (World *)*r_newid, (World *)id, flag); + break; case ID_TXT: - if (!test) *newid = (ID *)BKE_text_copy(bmain, (Text *)id); - return true; + BKE_text_copy_data(bmain, (Text *)*r_newid, (Text *)id, flag); + break; case ID_GR: - if (!test) *newid = (ID *)BKE_group_copy(bmain, (Group *)id); - return true; + BKE_group_copy_data(bmain, (Group *)*r_newid, (Group *)id, flag); + break; case ID_AR: - if (!test) *newid = (ID *)BKE_armature_copy(bmain, (bArmature *)id); - return true; + BKE_armature_copy_data(bmain, (bArmature *)*r_newid, (bArmature *)id, flag); + break; case ID_AC: - if (!test) *newid = (ID *)BKE_action_copy(bmain, (bAction *)id); - return true; + BKE_action_copy_data(bmain, (bAction *)*r_newid, (bAction *)id, flag); + break; case ID_NT: - if (!test) *newid = (ID *)ntreeCopyTree(bmain, (bNodeTree *)id); - return true; + BKE_node_tree_copy_data(bmain, (bNodeTree *)*r_newid, (bNodeTree *)id, flag); + break; case ID_BR: - if (!test) *newid = (ID *)BKE_brush_copy(bmain, (Brush *)id); - return true; + BKE_brush_copy_data(bmain, (Brush *)*r_newid, (Brush *)id, flag); + break; case ID_PA: - if (!test) *newid = (ID *)BKE_particlesettings_copy(bmain, (ParticleSettings *)id); - return true; + BKE_particlesettings_copy_data(bmain, (ParticleSettings *)*r_newid, (ParticleSettings *)id, flag); + break; case ID_GD: - if (!test) *newid = (ID *)BKE_gpencil_data_duplicate(bmain, (bGPdata *)id, false); - return true; + BKE_gpencil_copy_data(bmain, (bGPdata *)*r_newid, (bGPdata *)id, flag); + break; case ID_MC: - if (!test) *newid = (ID *)BKE_movieclip_copy(bmain, (MovieClip *)id); - return true; + BKE_movieclip_copy_data(bmain, (MovieClip *)*r_newid, (MovieClip *)id, flag); + break; case ID_MSK: - if (!test) *newid = (ID *)BKE_mask_copy(bmain, (Mask *)id); - return true; + BKE_mask_copy_data(bmain, (Mask *)*r_newid, (Mask *)id, flag); + break; case ID_LS: - if (!test) *newid = (ID *)BKE_linestyle_copy(bmain, (FreestyleLineStyle *)id); - return true; + BKE_linestyle_copy_data(bmain, (FreestyleLineStyle *)*r_newid, (FreestyleLineStyle *)id, flag); + break; case ID_PAL: - if (!test) *newid = (ID *)BKE_palette_copy(bmain, (Palette *)id); - return true; + BKE_palette_copy_data(bmain, (Palette *)*r_newid, (Palette *)id, flag); + break; case ID_PC: - if (!test) *newid = (ID *)BKE_paint_curve_copy(bmain, (PaintCurve *)id); - return true; + BKE_paint_curve_copy_data(bmain, (PaintCurve *)*r_newid, (PaintCurve *)id, flag); + break; case ID_CF: - if (!test) *newid = (ID *)BKE_cachefile_copy(bmain, (CacheFile *)id); - return true; - case ID_SCE: + BKE_cachefile_copy_data(bmain, (CacheFile *)*r_newid, (CacheFile *)id, flag); + break; + case ID_SO: + BKE_sound_copy_data(bmain, (bSound *)*r_newid, (bSound *)id, flag); + break; + case ID_VF: + BKE_vfont_copy_data(bmain, (VFont *)*r_newid, (VFont *)id, flag); + break; case ID_LI: case ID_SCR: case ID_WM: - return false; /* can't be copied from here */ - case ID_VF: - case ID_SO: - return false; /* not implemented */ case ID_IP: - return false; /* deprecated */ + BLI_assert(0); /* Should have been rejected at start of function! */ + break; } - - return false; + + /* Update ID refcount, remap pointers to self in new ID. */ + struct IDCopyLibManagementData data = {.id_src = id, .id_dst = *r_newid, .flag = flag}; + BKE_library_foreach_ID_link(bmain, *r_newid, id_copy_libmanagement_cb, &data, IDWALK_NOP); + + /* Do not make new copy local in case we are copying outside of main... + * XXX TODO: is this behavior OK, or should we need own flag to control that? */ + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + BKE_id_copy_ensure_local(bmain, id, *r_newid); + } + + return true; +} + +/** + * Invokes the appropriate copy method for the block and returns the result in + * newid, unless test. Returns true if the block can be copied. + */ +bool id_copy(Main *bmain, const ID *id, ID **newid, bool test) +{ + return BKE_id_copy_ex(bmain, id, newid, 0, test); } /** Does *not* set ID->newid pointer. */ @@ -623,6 +695,101 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) return false; } +static int libblock_management_us_plus(void *UNUSED(user_data), ID *UNUSED(id_self), ID **id_pointer, int cb_flag) +{ + if (cb_flag & IDWALK_CB_USER) { + id_us_plus(*id_pointer); + } + if (cb_flag & IDWALK_CB_USER_ONE) { + id_us_ensure_real(*id_pointer); + } + + return IDWALK_RET_NOP; +} + +static int libblock_management_us_min(void *UNUSED(user_data), ID *UNUSED(id_self), ID **id_pointer, int cb_flag) +{ + if (cb_flag & IDWALK_CB_USER) { + id_us_min(*id_pointer); + } + /* We can do nothing in IDWALK_CB_USER_ONE case! */ + + return IDWALK_RET_NOP; +} + +/** Add a 'NO_MAIN' datablock to given main (also sets usercounts of its IDs if needed). */ +void BKE_libblock_management_main_add(Main *bmain, void *idv) +{ + ID *id = idv; + + BLI_assert(bmain != NULL); + if ((id->tag & LIB_TAG_NO_MAIN) == 0) { + return; + } + + if ((id->tag & LIB_TAG_NOT_ALLOCATED) != 0) { + /* We cannot add non-allocated ID to Main! */ + return; + } + + /* We cannot allow non-userrefcounting IDs in Main database! */ + if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0) { + BKE_library_foreach_ID_link(bmain, id, libblock_management_us_plus, NULL, IDWALK_NOP); + } + + ListBase *lb = which_libbase(bmain, GS(id->name)); + BKE_main_lock(bmain); + BLI_addtail(lb, id); + new_id(lb, id, NULL); + /* alphabetic insertion: is in new_id */ + id->tag &= ~(LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT); + BKE_main_unlock(bmain); +} + +/** Remove a datablock from given main (set it to 'NO_MAIN' status). */ +void BKE_libblock_management_main_remove(Main *bmain, void *idv) +{ + ID *id = idv; + + BLI_assert(bmain != NULL); + if ((id->tag & LIB_TAG_NO_MAIN) != 0) { + return; + } + + /* For now, allow userrefcounting IDs to get out of Main - can be handy in some cases... */ + + ListBase *lb = which_libbase(bmain, GS(id->name)); + BKE_main_lock(bmain); + BLI_remlink(lb, id); + id->tag |= LIB_TAG_NO_MAIN; + BKE_main_unlock(bmain); +} + +void BKE_libblock_management_usercounts_set(Main *bmain, void *idv) +{ + ID *id = idv; + + if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) == 0) { + return; + } + + BKE_library_foreach_ID_link(bmain, id, libblock_management_us_plus, NULL, IDWALK_NOP); + id->tag &= ~LIB_TAG_NO_USER_REFCOUNT; +} + +void BKE_libblock_management_usercounts_clear(Main *bmain, void *idv) +{ + ID *id = idv; + + /* We do not allow IDs in Main database to not be userrefcounting. */ + if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0 || (id->tag & LIB_TAG_NO_MAIN) != 0) { + return; + } + + BKE_library_foreach_ID_link(bmain, id, libblock_management_us_min, NULL, IDWALK_NOP); + id->tag |= LIB_TAG_NO_USER_REFCOUNT; +} + ListBase *which_libbase(Main *mainlib, short type) { switch ((ID_Type)type) { @@ -932,23 +1099,44 @@ void *BKE_libblock_alloc_notest(short type) * The user count is set to 1, all other content (apart from name and links) being * initialized to zero. */ -void *BKE_libblock_alloc(Main *bmain, short type, const char *name) +void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int flag) { - ID *id = NULL; - ListBase *lb = which_libbase(bmain, type); - - id = BKE_libblock_alloc_notest(type); + BLI_assert((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0); + + ID *id = BKE_libblock_alloc_notest(type); + if (id) { - BKE_main_lock(bmain); - BLI_addtail(lb, id); - id->us = 1; + if ((flag & LIB_ID_CREATE_NO_MAIN) != 0) { + id->tag |= LIB_TAG_NO_MAIN; + } + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0) { + id->tag |= LIB_TAG_NO_USER_REFCOUNT; + } + id->icon_id = 0; - *( (short *)id->name) = type; - new_id(lb, id, name); - /* alphabetic insertion: is in new_id */ - BKE_main_unlock(bmain); + *((short *)id->name) = type; + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id->us = 1; + } + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + ListBase *lb = which_libbase(bmain, type); + + BKE_main_lock(bmain); + BLI_addtail(lb, id); + new_id(lb, id, name); + /* alphabetic insertion: is in new_id */ + BKE_main_unlock(bmain); + + /* TODO to be removed from here! */ + if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) { + DAG_id_type_tag(bmain, type); + } + } + else { + BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2); + } } - DAG_id_type_tag(bmain, type); + return id; } @@ -1071,70 +1259,80 @@ void BKE_libblock_init_empty(ID *id) /* by spec, animdata is first item after ID */ /* and, trust that BKE_animdata_from_id() will only find AnimData for valid ID-types */ -static void id_copy_animdata(ID *id, const bool do_action) +static void id_copy_animdata(Main *bmain, ID *id, const bool do_action) { AnimData *adt = BKE_animdata_from_id(id); if (adt) { IdAdtTemplate *iat = (IdAdtTemplate *)id; - iat->adt = BKE_animdata_copy(iat->adt, do_action); /* could be set to false, need to investigate */ + iat->adt = BKE_animdata_copy(bmain, iat->adt, do_action); /* could be set to false, need to investigate */ } } -/* material nodes use this since they are not treated as libdata */ -void BKE_libblock_copy_data(ID *id, const ID *id_from, const bool do_action) +void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag) { - if (id_from->properties) - id->properties = IDP_CopyProperty(id_from->properties); + ID *new_id = *r_newid; + + /* Grrrrrrrrr... Not adding 'root' nodetrees to bmain.... grrrrrrrrrrrrrrrrrrrr! */ + /* This is taken from original ntree copy code, might be weak actually? */ + const bool use_nodetree_alloc_exception = ((GS(id->name) == ID_NT) && (bmain != NULL) && + (BLI_findindex(&bmain->nodetree, id) < 0)); + + BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL); + BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0); + BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0); + + if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) { + /* r_newid already contains pointer to allocated memory. */ + /* TODO do we want to memset(0) whole mem before filling it? */ + BLI_strncpy(new_id->name, id->name, sizeof(new_id->name)); + new_id->us = 0; + new_id->tag |= LIB_TAG_NOT_ALLOCATED | LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT; + /* TODO Do we want/need to copy more from ID struct itself? */ + } + else { + new_id = BKE_libblock_alloc(bmain, GS(id->name), id->name + 2, flag | (use_nodetree_alloc_exception ? LIB_ID_CREATE_NO_MAIN : 0)); + } + BLI_assert(new_id != NULL); + + const size_t id_len = BKE_libblock_get_alloc_info(GS(new_id->name), NULL); + const size_t id_offset = sizeof(ID); + if ((int)id_len - (int)id_offset > 0) { /* signed to allow neg result */ /* XXX ????? */ + const char *cp = (const char *)id; + char *cpn = (char *)new_id; + + memcpy(cpn + id_offset, cp + id_offset, id_len - id_offset); + } + + if (id->properties) { + new_id->properties = IDP_CopyProperty_ex(id->properties, flag); + } /* the duplicate should get a copy of the animdata */ - id_copy_animdata(id, do_action); + id_copy_animdata(bmain, new_id, (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0); + + if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0) { + DAG_id_type_tag(bmain, GS(new_id->name)); + } + + *r_newid = new_id; } /* used everywhere in blenkernel */ void *BKE_libblock_copy(Main *bmain, const ID *id) { ID *idn; - size_t idn_len; - - idn = BKE_libblock_alloc(bmain, GS(id->name), id->name + 2); - assert(idn != NULL); + BKE_libblock_copy_ex(bmain, id, &idn, 0); - idn_len = MEM_allocN_len(idn); - if ((int)idn_len - (int)sizeof(ID) > 0) { /* signed to allow neg result */ - const char *cp = (const char *)id; - char *cpn = (char *)idn; - - memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID)); - } - - BKE_libblock_copy_data(idn, id, false); - return idn; } void *BKE_libblock_copy_nolib(const ID *id, const bool do_action) { ID *idn; - size_t idn_len; - - idn = BKE_libblock_alloc_notest(GS(id->name)); - assert(idn != NULL); - - BLI_strncpy(idn->name, id->name, sizeof(idn->name)); - - idn_len = MEM_allocN_len(idn); - if ((int)idn_len - (int)sizeof(ID) > 0) { /* signed to allow neg result */ - const char *cp = (const char *)id; - char *cpn = (char *)idn; - - memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID)); - } - - idn->us = 1; - BKE_libblock_copy_data(idn, id, do_action); + BKE_libblock_copy_ex(NULL, id, &idn, LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | (do_action ? LIB_ID_COPY_ACTIONS : 0)); return idn; } diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 5e5ba44f039..f8c193fe108 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -186,8 +186,8 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0; #ifdef DEBUG_PRINT - printf("In %s: Remapping %s (%p) to %s (%p) (skip_indirect: %d)\n", - id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, skip_indirect); + printf("In %s: Remapping %s (%p) to %s (%p) (is_indirect: %d, skip_indirect: %d)\n", + id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, is_indirect, skip_indirect); #endif if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) { @@ -201,6 +201,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id { if (is_indirect) { id_remap_data->skipped_indirect++; + if (is_obj) { + Object *ob = (Object *)id; + if (ob->data == *id_p && ob->proxy != NULL) { + /* And another 'Proudly brought to you by Proxy Hell' hack! + * This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */ + id_remap_data->skipped_direct++; + } + } } else if (is_never_null || is_obj_editmode) { id_remap_data->skipped_direct++; @@ -241,7 +249,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id return IDWALK_RET_NOP; } -/* Some reamapping unfortunately require extra and/or specific handling, tackle those here. */ +/* Some remapping unfortunately require extra and/or specific handling, tackle those here. */ static void libblock_remap_data_preprocess_scene_base_unlink( IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect) { @@ -318,7 +326,7 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) } } -static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, Object *old_ob, Object *new_ob) +static void libblock_remap_data_postprocess_object_update(Main *bmain, Object *old_ob, Object *new_ob) { if (old_ob->flag & OB_FROMGROUP) { /* Note that for Scene's BaseObject->flag, either we: @@ -337,6 +345,13 @@ static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, new_ob->flag |= OB_FROMGROUP; } } + if (old_ob->type == OB_MBALL) { + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + if (ob->type == OB_MBALL && BKE_mball_is_basis_for(ob, old_ob)) { + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + } + } } static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmain), Scene *sce, ID *old_id) @@ -547,7 +562,7 @@ void BKE_libblock_remap_locked( */ switch (GS(old_id->name)) { case ID_OB: - libblock_remap_data_postprocess_object_fromgroup_update(bmain, (Object *)old_id, (Object *)new_id); + libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id); break; case ID_GR: if (!new_id) { /* Only affects us in case group was unlinked. */ @@ -657,8 +672,7 @@ void BKE_libblock_relink_ex( switch (GS(old_id->name)) { case ID_OB: { - libblock_remap_data_postprocess_object_fromgroup_update( - bmain, (Object *)old_id, (Object *)new_id); + libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id); break; } case ID_GR: @@ -673,7 +687,7 @@ void BKE_libblock_relink_ex( else { /* No choice but to check whole objects/groups. */ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { - libblock_remap_data_postprocess_object_fromgroup_update(bmain, ob, NULL); + libblock_remap_data_postprocess_object_update(bmain, ob, NULL); } for (Group *grp = bmain->group.first; grp; grp = grp->id.next) { libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL); @@ -730,9 +744,11 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user) IDP_FreeProperty_ex(id->properties, do_id_user); MEM_freeN(id->properties); } + + /* XXX TODO remove animdata handling from each type's freeing func, and do it here, like for copy! */ } -void BKE_libblock_free_datablock(ID *id) +void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag)) { const short type = GS(id->name); switch (type) { @@ -842,6 +858,90 @@ void BKE_libblock_free_datablock(ID *id) } } + +void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_idtag) +{ + ID *id = idv; + + if (use_flag_from_idtag) { + if ((id->tag & LIB_TAG_NO_MAIN) != 0) { + flag |= LIB_ID_FREE_NO_MAIN; + } + else { + flag &= ~LIB_ID_FREE_NO_MAIN; + } + + if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0) { + flag |= LIB_ID_FREE_NO_USER_REFCOUNT; + } + else { + flag &= ~LIB_ID_FREE_NO_USER_REFCOUNT; + } + + if ((id->tag & LIB_TAG_NOT_ALLOCATED) != 0) { + flag |= LIB_ID_FREE_NOT_ALLOCATED; + } + else { + flag &= ~LIB_ID_FREE_NOT_ALLOCATED; + } + } + + BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || bmain != NULL); + BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || (flag & LIB_ID_FREE_NOT_ALLOCATED) == 0); + BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0); + + const short type = GS(id->name); + + if (bmain && (flag & LIB_ID_FREE_NO_DEG_TAG) == 0) { + DAG_id_type_tag(bmain, type); + } + +#ifdef WITH_PYTHON + BPY_id_release(id); +#endif + + if ((flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0) { + BKE_libblock_relink_ex(bmain, id, NULL, NULL, true); + } + + BKE_libblock_free_datablock(id, flag); + + /* avoid notifying on removed data */ + if (bmain) { + BKE_main_lock(bmain); + } + + if ((flag & LIB_ID_FREE_NO_UI_USER) == 0) { + if (free_notifier_reference_cb) { + free_notifier_reference_cb(id); + } + + if (remap_editor_id_reference_cb) { + remap_editor_id_reference_cb(id, NULL); + } + } + + if ((flag & LIB_ID_FREE_NO_MAIN) == 0) { + ListBase *lb = which_libbase(bmain, type); + BLI_remlink(lb, id); + } + + BKE_libblock_free_data(id, (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0); + + if (bmain) { + BKE_main_unlock(bmain); + } + + if ((flag & LIB_ID_FREE_NOT_ALLOCATED) == 0) { + MEM_freeN(id); + } +} + +void BKE_id_free(Main *bmain, void *idv) +{ + BKE_id_free_ex(bmain, idv, 0, true); +} + /** * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c * @@ -866,7 +966,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b BKE_libblock_relink_ex(bmain, id, NULL, NULL, true); } - BKE_libblock_free_datablock(id); + BKE_libblock_free_datablock(id, 0); /* avoid notifying on removed data */ BKE_main_lock(bmain); diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 771e81ddc4f..1b1a12e702a 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -119,7 +119,7 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name) { FreestyleLineStyle *linestyle; - linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name); + linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name, 0); BKE_linestyle_init(linestyle); @@ -155,73 +155,54 @@ void BKE_linestyle_free(FreestyleLineStyle *linestyle) BKE_linestyle_geometry_modifier_remove(linestyle, m); } -FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineStyle *linestyle) +/** + * Only copy internal data of Linestyle ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_linestyle_copy_data( + struct Main *bmain, FreestyleLineStyle *linestyle_dst, const FreestyleLineStyle *linestyle_src, const int flag) { - FreestyleLineStyle *new_linestyle; - LineStyleModifier *m; - int a; + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; - new_linestyle = BKE_linestyle_new(bmain, linestyle->id.name + 2); - BKE_linestyle_free(new_linestyle); - - for (a = 0; a < MAX_MTEX; a++) { - if (linestyle->mtex[a]) { - new_linestyle->mtex[a] = MEM_mallocN(sizeof(MTex), "BKE_linestyle_copy"); - memcpy(new_linestyle->mtex[a], linestyle->mtex[a], sizeof(MTex)); - id_us_plus((ID *)new_linestyle->mtex[a]->tex); + for (int a = 0; a < MAX_MTEX; a++) { + if (linestyle_src->mtex[a]) { + linestyle_dst->mtex[a] = MEM_mallocN(sizeof(*linestyle_dst->mtex[a]), __func__); + *linestyle_dst->mtex[a] = *linestyle_src->mtex[a]; } } - if (linestyle->nodetree) { - new_linestyle->nodetree = ntreeCopyTree(bmain, linestyle->nodetree); + if (linestyle_src->nodetree) { + BKE_id_copy_ex(bmain, (ID *)linestyle_src->nodetree, (ID **)&linestyle_dst->nodetree, flag, false); } - new_linestyle->r = linestyle->r; - new_linestyle->g = linestyle->g; - new_linestyle->b = linestyle->b; - new_linestyle->alpha = linestyle->alpha; - new_linestyle->thickness = linestyle->thickness; - new_linestyle->thickness_position = linestyle->thickness_position; - new_linestyle->thickness_ratio = linestyle->thickness_ratio; - new_linestyle->flag = linestyle->flag; - new_linestyle->caps = linestyle->caps; - new_linestyle->chaining = linestyle->chaining; - new_linestyle->rounds = linestyle->rounds; - new_linestyle->split_length = linestyle->split_length; - new_linestyle->min_angle = linestyle->min_angle; - new_linestyle->max_angle = linestyle->max_angle; - new_linestyle->min_length = linestyle->min_length; - new_linestyle->max_length = linestyle->max_length; - new_linestyle->chain_count = linestyle->chain_count; - new_linestyle->split_dash1 = linestyle->split_dash1; - new_linestyle->split_gap1 = linestyle->split_gap1; - new_linestyle->split_dash2 = linestyle->split_dash2; - new_linestyle->split_gap2 = linestyle->split_gap2; - new_linestyle->split_dash3 = linestyle->split_dash3; - new_linestyle->split_gap3 = linestyle->split_gap3; - new_linestyle->dash1 = linestyle->dash1; - new_linestyle->gap1 = linestyle->gap1; - new_linestyle->dash2 = linestyle->dash2; - new_linestyle->gap2 = linestyle->gap2; - new_linestyle->dash3 = linestyle->dash3; - new_linestyle->gap3 = linestyle->gap3; - new_linestyle->panel = linestyle->panel; - new_linestyle->sort_key = linestyle->sort_key; - new_linestyle->integration_type = linestyle->integration_type; - new_linestyle->texstep = linestyle->texstep; - new_linestyle->pr_texture = linestyle->pr_texture; - new_linestyle->use_nodes = linestyle->use_nodes; - for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) - BKE_linestyle_color_modifier_copy(new_linestyle, m); - for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) - BKE_linestyle_alpha_modifier_copy(new_linestyle, m); - for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) - BKE_linestyle_thickness_modifier_copy(new_linestyle, m); - for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next) - BKE_linestyle_geometry_modifier_copy(new_linestyle, m); - - BKE_id_copy_ensure_local(bmain, &linestyle->id, &new_linestyle->id); - - return new_linestyle; + LineStyleModifier *m; + BLI_listbase_clear(&linestyle_dst->color_modifiers); + for (m = (LineStyleModifier *)linestyle_src->color_modifiers.first; m; m = m->next) { + BKE_linestyle_color_modifier_copy(linestyle_dst, m, flag_subdata); + } + BLI_listbase_clear(&linestyle_dst->alpha_modifiers); + for (m = (LineStyleModifier *)linestyle_src->alpha_modifiers.first; m; m = m->next) { + BKE_linestyle_alpha_modifier_copy(linestyle_dst, m, flag_subdata); + } + BLI_listbase_clear(&linestyle_dst->thickness_modifiers); + for (m = (LineStyleModifier *)linestyle_src->thickness_modifiers.first; m; m = m->next) { + BKE_linestyle_thickness_modifier_copy(linestyle_dst, m, flag_subdata); + } + BLI_listbase_clear(&linestyle_dst->geometry_modifiers); + for (m = (LineStyleModifier *)linestyle_src->geometry_modifiers.first; m; m = m->next) { + BKE_linestyle_geometry_modifier_copy(linestyle_dst, m, flag_subdata); + } +} + +FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineStyle *linestyle) +{ + FreestyleLineStyle *linestyle_copy; + BKE_id_copy_ex(bmain, &linestyle->id, (ID **)&linestyle_copy, 0, false); + return linestyle_copy; } void BKE_linestyle_make_local(struct Main *bmain, FreestyleLineStyle *linestyle, const bool lib_local) @@ -355,7 +336,8 @@ LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyl return m; } -LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m) +LineStyleModifier *BKE_linestyle_color_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag) { LineStyleModifier *new_m; @@ -388,9 +370,10 @@ LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linesty { LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)m; LineStyleColorModifier_DistanceFromObject *q = (LineStyleColorModifier_DistanceFromObject *)new_m; - if (p->target) - id_us_plus(&p->target->id); q->target = p->target; + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)q->target); + } q->color_ramp = MEM_dupallocN(p->color_ramp); q->range_min = p->range_min; q->range_max = p->range_max; @@ -594,7 +577,8 @@ LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyl return m; } -LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m) +LineStyleModifier *BKE_linestyle_alpha_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int UNUSED(flag)) { LineStyleModifier *new_m; @@ -863,7 +847,8 @@ LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *line return m; } -LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m) +LineStyleModifier *BKE_linestyle_thickness_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag) { LineStyleModifier *new_m; @@ -901,9 +886,10 @@ LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *lin { LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)m; LineStyleThicknessModifier_DistanceFromObject *q = (LineStyleThicknessModifier_DistanceFromObject *)new_m; - if (p->target) - id_us_plus(&p->target->id); q->target = p->target; + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)q->target); + } q->curve = curvemapping_copy(p->curve); q->flags = p->flags; q->range_min = p->range_min; @@ -1195,7 +1181,8 @@ LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *lines return m; } -LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m) +LineStyleModifier *BKE_linestyle_geometry_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int UNUSED(flag)) { LineStyleModifier *new_m; diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index ae27e9bcd34..8b8b48db279 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -51,6 +51,7 @@ #include "BKE_animsys.h" #include "BKE_curve.h" +#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" @@ -794,7 +795,7 @@ static Mask *mask_alloc(Main *bmain, const char *name) { Mask *mask; - mask = BKE_libblock_alloc(bmain, ID_MSK, name); + mask = BKE_libblock_alloc(bmain, ID_MSK, name, 0); id_fake_user_set(&mask->id); @@ -817,10 +818,13 @@ Mask *BKE_mask_new(Main *bmain, const char *name) mask->sfra = 1; mask->efra = 100; + DAG_relations_tag_update(bmain); + return mask; } /* TODO(sergey): Use generic BKE_libblock_copy_nolib() instead. */ +/* TODO(bastien): Use new super cool & generic BKE_id_copy_ex() instead! */ Mask *BKE_mask_copy_nolib(Mask *mask) { Mask *mask_new; @@ -840,22 +844,29 @@ Mask *BKE_mask_copy_nolib(Mask *mask) return mask_new; } -Mask *BKE_mask_copy(Main *bmain, const Mask *mask) +/** + * Only copy internal data of Mask ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_mask_copy_data(Main *UNUSED(bmain), Mask *mask_dst, const Mask *mask_src, const int UNUSED(flag)) { - Mask *mask_new; + BLI_listbase_clear(&mask_dst->masklayers); - mask_new = BKE_libblock_copy(bmain, &mask->id); - - BLI_listbase_clear(&mask_new->masklayers); - - BKE_mask_layer_copy_list(&mask_new->masklayers, &mask->masklayers); + BKE_mask_layer_copy_list(&mask_dst->masklayers, &mask_src->masklayers); /* TODO add unused flag to those as well. */ /* enable fake user by default */ - id_fake_user_set(&mask_new->id); - - BKE_id_copy_ensure_local(bmain, &mask->id, &mask_new->id); + id_fake_user_set(&mask_dst->id); +} - return mask_new; +Mask *BKE_mask_copy(Main *bmain, const Mask *mask) +{ + Mask *mask_copy; + BKE_id_copy_ex(bmain, &mask->id, (ID **)&mask_copy, 0, false); + return mask_copy; } void BKE_mask_make_local(Main *bmain, Mask *mask, const bool lib_local) @@ -1171,17 +1182,6 @@ void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point, float ctime, float } } -static void mask_evaluate_apply_point_parent(MaskSplinePoint *point, float ctime) -{ - float parent_matrix[3][3]; - - BKE_mask_point_parent_matrix_get(point, ctime, parent_matrix); - - mul_m3_v2(parent_matrix, point->bezt.vec[0]); - mul_m3_v2(parent_matrix, point->bezt.vec[1]); - mul_m3_v2(parent_matrix, point->bezt.vec[2]); -} - static void mask_calc_point_handle(MaskSplinePoint *point, MaskSplinePoint *point_prev, MaskSplinePoint *point_next) { BezTriple *bezt = &point->bezt; @@ -1397,80 +1397,12 @@ void BKE_mask_spline_ensure_deform(MaskSpline *spline) void BKE_mask_layer_evaluate(MaskLayer *masklay, const float ctime, const bool do_newframe) { - /* animation if available */ + /* Animation if available. */ if (do_newframe) { - MaskLayerShape *masklay_shape_a; - MaskLayerShape *masklay_shape_b; - int found; - - if ((found = BKE_mask_layer_shape_find_frame_range(masklay, ctime, - &masklay_shape_a, &masklay_shape_b))) - { - if (found == 1) { -#if 0 - printf("%s: exact %d %d (%d)\n", __func__, (int)ctime, BLI_listbase_count(&masklay->splines_shapes), - masklay_shape_a->frame); -#endif - - BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a); - } - else if (found == 2) { - float w = masklay_shape_b->frame - masklay_shape_a->frame; -#if 0 - printf("%s: tween %d %d (%d %d)\n", __func__, (int)ctime, BLI_listbase_count(&masklay->splines_shapes), - masklay_shape_a->frame, masklay_shape_b->frame); -#endif - BKE_mask_layer_shape_to_mask_interp(masklay, masklay_shape_a, masklay_shape_b, - (ctime - masklay_shape_a->frame) / w); - } - else { - /* always fail, should never happen */ - BLI_assert(found == 2); - } - } - } - /* animation done... */ - - BKE_mask_layer_calc_handles(masklay); - - /* update deform */ - { - MaskSpline *spline; - - for (spline = masklay->splines.first; spline; spline = spline->next) { - int i; - bool need_handle_recalc = false; - - BKE_mask_spline_ensure_deform(spline); - - for (i = 0; i < spline->tot_point; i++) { - MaskSplinePoint *point = &spline->points[i]; - MaskSplinePoint *point_deform = &spline->points_deform[i]; - - BKE_mask_point_free(point_deform); - - *point_deform = *point; - point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL; - - mask_evaluate_apply_point_parent(point_deform, ctime); - - if (ELEM(point->bezt.h1, HD_AUTO, HD_VECT)) { - need_handle_recalc = true; - } - } - - /* if the spline has auto or vector handles, these need to be recalculated after deformation */ - if (need_handle_recalc) { - for (i = 0; i < spline->tot_point; i++) { - MaskSplinePoint *point_deform = &spline->points_deform[i]; - if (ELEM(point_deform->bezt.h1, HD_AUTO, HD_VECT)) { - BKE_mask_calc_handle_point(spline, point_deform); - } - } - } - /* end extra calc handles loop */ - } + BKE_mask_layer_evaluate_animation(masklay, ctime); } + /* Update deform. */ + BKE_mask_layer_evaluate_deform(masklay, ctime); } void BKE_mask_evaluate(Mask *mask, const float ctime, const bool do_newframe) diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c index 1b275f455f4..0d71cc548c7 100644 --- a/source/blender/blenkernel/intern/mask_evaluate.c +++ b/source/blender/blenkernel/intern/mask_evaluate.c @@ -42,6 +42,8 @@ #include "DNA_mask_types.h" #include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" #include "BKE_mask.h" @@ -810,3 +812,111 @@ float *BKE_mask_point_segment_diff(MaskSpline *spline, MaskSplinePoint *point, return diff_points; } + +static void mask_evaluate_apply_point_parent(MaskSplinePoint *point, float ctime) +{ + float parent_matrix[3][3]; + BKE_mask_point_parent_matrix_get(point, ctime, parent_matrix); + mul_m3_v2(parent_matrix, point->bezt.vec[0]); + mul_m3_v2(parent_matrix, point->bezt.vec[1]); + mul_m3_v2(parent_matrix, point->bezt.vec[2]); +} + +void BKE_mask_layer_evaluate_animation(MaskLayer *masklay, const float ctime) +{ + /* animation if available */ + MaskLayerShape *masklay_shape_a; + MaskLayerShape *masklay_shape_b; + int found; + if ((found = BKE_mask_layer_shape_find_frame_range( + masklay, ctime, &masklay_shape_a, &masklay_shape_b))) + { + if (found == 1) { +#if 0 + printf("%s: exact %d %d (%d)\n", + __func__, + (int)ctime, + BLI_listbase_count(&masklay->splines_shapes), + masklay_shape_a->frame); +#endif + BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a); + } + else if (found == 2) { + float w = masklay_shape_b->frame - masklay_shape_a->frame; +#if 0 + printf("%s: tween %d %d (%d %d)\n", + __func__, + (int)ctime, + BLI_listbase_count(&masklay->splines_shapes), + masklay_shape_a->frame, masklay_shape_b->frame); +#endif + BKE_mask_layer_shape_to_mask_interp( + masklay, + masklay_shape_a, masklay_shape_b, + (ctime - masklay_shape_a->frame) / w); + } + else { + /* always fail, should never happen */ + BLI_assert(found == 2); + } + } +} + +void BKE_mask_layer_evaluate_deform(MaskLayer *masklay, const float ctime) +{ + BKE_mask_layer_calc_handles(masklay); + for (MaskSpline *spline = masklay->splines.first; + spline != NULL; + spline = spline->next) + { + bool need_handle_recalc = false; + BKE_mask_spline_ensure_deform(spline); + for (int i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + MaskSplinePoint *point_deform = &spline->points_deform[i]; + BKE_mask_point_free(point_deform); + *point_deform = *point; + point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL; + mask_evaluate_apply_point_parent(point_deform, ctime); + if (ELEM(point->bezt.h1, HD_AUTO, HD_VECT)) { + need_handle_recalc = true; + } + } + /* if the spline has auto or vector handles, these need to be + * recalculated after deformation. + */ + if (need_handle_recalc) { + for (int i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point_deform = &spline->points_deform[i]; + if (ELEM(point_deform->bezt.h1, HD_AUTO, HD_VECT)) { + BKE_mask_calc_handle_point(spline, point_deform); + } + } + } + /* end extra calc handles loop */ + } +} + +#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf + +void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask) +{ + DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask); + for (MaskLayer *mask_layer = mask->masklayers.first; + mask_layer != NULL; + mask_layer = mask_layer->next) + { + BKE_mask_layer_evaluate_animation(mask_layer, eval_ctx->ctime); + } +} + +void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, Mask *mask) +{ + DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask); + for (MaskLayer *mask_layer = mask->masklayers.first; + mask_layer != NULL; + mask_layer = mask_layer->next) + { + BKE_mask_layer_evaluate_deform(mask_layer, eval_ctx->ctime); + } +} diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index f21efb71180..f5be72c6b4d 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -212,50 +212,68 @@ Material *BKE_material_add(Main *bmain, const char *name) { Material *ma; - ma = BKE_libblock_alloc(bmain, ID_MA, name); + ma = BKE_libblock_alloc(bmain, ID_MA, name, 0); BKE_material_init(ma); return ma; } -/* XXX keep synced with next function */ -Material *BKE_material_copy(Main *bmain, const Material *ma) +/** + * Only copy internal data of Material ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_src, const int flag) { - Material *man; - int a; - - man = BKE_libblock_copy(bmain, &ma->id); - - id_lib_extern((ID *)man->group); - - for (a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a]) { - man->mtex[a] = MEM_mallocN(sizeof(MTex), "copymaterial"); - memcpy(man->mtex[a], ma->mtex[a], sizeof(MTex)); - id_us_plus((ID *)man->mtex[a]->tex); + for (int a = 0; a < MAX_MTEX; a++) { + if (ma_src->mtex[a]) { + ma_dst->mtex[a] = MEM_mallocN(sizeof(*ma_dst->mtex[a]), __func__); + *ma_dst->mtex[a] = *ma_src->mtex[a]; } } - - if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col); - if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec); - - if (ma->nodetree) { - man->nodetree = ntreeCopyTree(bmain, ma->nodetree); + + if (ma_src->ramp_col) { + ma_dst->ramp_col = MEM_dupallocN(ma_src->ramp_col); + } + if (ma_src->ramp_spec) { + ma_dst->ramp_spec = MEM_dupallocN(ma_src->ramp_spec); } - BKE_previewimg_id_copy(&man->id, &ma->id); + if (ma_src->nodetree) { + BKE_id_copy_ex(bmain, (ID *)ma_src->nodetree, (ID **)&ma_dst->nodetree, flag, false); + } - BLI_listbase_clear(&man->gpumaterial); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&ma_dst->id, &ma_src->id); + } + else { + ma_dst->preview = NULL; + } - BKE_id_copy_ensure_local(bmain, &ma->id, &man->id); + BLI_listbase_clear(&ma_dst->gpumaterial); +} - return man; +Material *BKE_material_copy(Main *bmain, const Material *ma) +{ + Material *ma_copy; + BKE_id_copy_ex(bmain, &ma->id, (ID **)&ma_copy, 0, false); + return ma_copy; } /* XXX (see above) material copy without adding to main dbase */ Material *localize_material(Material *ma) { + /* TODO replace with something like + * Material *ma_copy; + * BKE_id_copy_ex(bmain, &ma->id, (ID **)&ma_copy, LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT, false); + * return ma_copy; + * + * ... Once f*** nodes are fully converted to that too :( */ + Material *man; int a; @@ -343,6 +361,8 @@ Material ***give_matarar_id(ID *id) return &(((Curve *)id)->mat); case ID_MB: return &(((MetaBall *)id)->mat); + default: + break; } return NULL; } @@ -359,6 +379,8 @@ short *give_totcolp_id(ID *id) return &(((Curve *)id)->totcol); case ID_MB: return &(((MetaBall *)id)->totcol); + default: + break; } return NULL; } @@ -378,6 +400,8 @@ static void material_data_index_remove_id(ID *id, short index) case ID_MB: /* meta-elems don't have materials atm */ break; + default: + break; } } @@ -396,6 +420,8 @@ static void material_data_index_clear_id(ID *id) case ID_MB: /* meta-elems don't have materials atm */ break; + default: + break; } } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index b80579014d6..dfc49c996b1 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -96,33 +96,36 @@ MetaBall *BKE_mball_add(Main *bmain, const char *name) { MetaBall *mb; - mb = BKE_libblock_alloc(bmain, ID_MB, name); + mb = BKE_libblock_alloc(bmain, ID_MB, name, 0); BKE_mball_init(mb); return mb; } -MetaBall *BKE_mball_copy(Main *bmain, const MetaBall *mb) +/** + * Only copy internal data of MetaBall ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_mball_copy_data(Main *UNUSED(bmain), MetaBall *mb_dst, const MetaBall *mb_src, const int UNUSED(flag)) { - MetaBall *mbn; - int a; - - mbn = BKE_libblock_copy(bmain, &mb->id); + BLI_duplicatelist(&mb_dst->elems, &mb_src->elems); - BLI_duplicatelist(&mbn->elems, &mb->elems); - - mbn->mat = MEM_dupallocN(mb->mat); - for (a = 0; a < mbn->totcol; a++) { - id_us_plus((ID *)mbn->mat[a]); - } + mb_dst->mat = MEM_dupallocN(mb_src->mat); - mbn->editelems = NULL; - mbn->lastelem = NULL; - - BKE_id_copy_ensure_local(bmain, &mb->id, &mbn->id); + mb_dst->editelems = NULL; + mb_dst->lastelem = NULL; +} - return mbn; +MetaBall *BKE_mball_copy(Main *bmain, const MetaBall *mb) +{ + MetaBall *mb_copy; + BKE_id_copy_ex(bmain, &mb->id, (ID **)&mb_copy, 0, false); + return mb_copy; } void BKE_mball_make_local(Main *bmain, MetaBall *mb, const bool lib_local) @@ -470,7 +473,7 @@ bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3]) return false; } -void BKE_mball_transform(MetaBall *mb, float mat[4][4]) +void BKE_mball_transform(MetaBall *mb, float mat[4][4], const bool do_props) { MetaElem *me; float quat[4]; @@ -482,14 +485,17 @@ void BKE_mball_transform(MetaBall *mb, float mat[4][4]) for (me = mb->elems.first; me; me = me->next) { mul_m4_v3(mat, &me->x); mul_qt_qtqt(me->quat, quat, me->quat); - me->rad *= scale; - /* hrmf, probably elems shouldn't be - * treating scale differently - campbell */ - if (!MB_TYPE_SIZE_SQUARED(me->type)) { - mul_v3_fl(&me->expx, scale); - } - else { - mul_v3_fl(&me->expx, scale_sqrt); + + if (do_props) { + me->rad *= scale; + /* hrmf, probably elems shouldn't be + * treating scale differently - campbell */ + if (!MB_TYPE_SIZE_SQUARED(me->type)) { + mul_v3_fl(&me->expx, scale); + } + else { + mul_v3_fl(&me->expx, scale_sqrt); + } } } } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 6233caa43fa..0d01fe77453 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -494,53 +494,56 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) { Mesh *me; - me = BKE_libblock_alloc(bmain, ID_ME, name); + me = BKE_libblock_alloc(bmain, ID_ME, name, 0); BKE_mesh_init(me); return me; } -Mesh *BKE_mesh_copy(Main *bmain, const Mesh *me) +/** + * Only copy internal data of Mesh ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int flag) { - Mesh *men; - int a; - const int do_tessface = ((me->totface != 0) && (me->totpoly == 0)); /* only do tessface if we have no polys */ - - men = BKE_libblock_copy(bmain, &me->id); - - men->mat = MEM_dupallocN(me->mat); - for (a = 0; a < men->totcol; a++) { - id_us_plus((ID *)men->mat[a]); - } - id_us_plus((ID *)men->texcomesh); + const bool do_tessface = ((me_src->totface != 0) && (me_src->totpoly == 0)); /* only do tessface if we have no polys */ + + me_dst->mat = MEM_dupallocN(me_src->mat); - CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert); - CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge); - CustomData_copy(&me->ldata, &men->ldata, CD_MASK_MESH, CD_DUPLICATE, men->totloop); - CustomData_copy(&me->pdata, &men->pdata, CD_MASK_MESH, CD_DUPLICATE, men->totpoly); + CustomData_copy(&me_src->vdata, &me_dst->vdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totvert); + CustomData_copy(&me_src->edata, &me_dst->edata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totedge); + CustomData_copy(&me_src->ldata, &me_dst->ldata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totloop); + CustomData_copy(&me_src->pdata, &me_dst->pdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totpoly); if (do_tessface) { - CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface); + CustomData_copy(&me_src->fdata, &me_dst->fdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totface); } else { - mesh_tessface_clear_intern(men, false); + mesh_tessface_clear_intern(me_dst, false); } - BKE_mesh_update_customdata_pointers(men, do_tessface); + BKE_mesh_update_customdata_pointers(me_dst, do_tessface); - men->edit_btmesh = NULL; + me_dst->edit_btmesh = NULL; - men->mselect = MEM_dupallocN(men->mselect); - men->bb = MEM_dupallocN(men->bb); + me_dst->mselect = MEM_dupallocN(me_dst->mselect); + me_dst->bb = MEM_dupallocN(me_dst->bb); - if (me->key) { - men->key = BKE_key_copy(bmain, me->key); - men->key->from = (ID *)men; + /* TODO Do we want to add flag to prevent this? */ + if (me_src->key) { + BKE_id_copy_ex(bmain, &me_src->key->id, (ID **)&me_dst->key, flag, false); } +} - BKE_id_copy_ensure_local(bmain, &me->id, &men->id); - - return men; +Mesh *BKE_mesh_copy(Main *bmain, const Mesh *me) +{ + Mesh *me_copy; + BKE_id_copy_ex(bmain, &me->id, (ID **)&me_copy, 0, false); + return me_copy; } BMesh *BKE_mesh_to_bmesh( @@ -2056,6 +2059,12 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type) (me->mselect[me->totselect - 1].type == type)); } +/** + * Compute 'split' (aka loop, or per face corner's) normals. + * + * \param r_lnors_spacearr Allows to get computed loop normal space array. That data, among other things, + * contains 'smooth fan' info, useful e.g. to split geometry along sharp edges... + */ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr) { float (*r_loopnors)[3]; @@ -2063,6 +2072,11 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac short (*clnors)[2] = NULL; bool free_polynors = false; + /* Note that we enforce computing clnors when the clnor space array is requested by caller here. + * However, we obviously only use the autosmooth angle threshold only in case autosmooth is enabled. */ + const bool use_split_normals = (r_lnors_spacearr != NULL) || ((mesh->flag & ME_AUTOSMOOTH) != 0); + const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI; + if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop); @@ -2091,7 +2105,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac BKE_mesh_normals_loop_split( mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge, mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly, - (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, r_lnors_spacearr, clnors, NULL); + use_split_normals, split_angle, r_lnors_spacearr, clnors, NULL); if (free_polynors) { MEM_freeN(polynors); @@ -2123,118 +2137,70 @@ typedef struct SplitFaceNewEdge { /* Detect needed new vertices, and update accordingly loops' vertex indices. * WARNING! Leaves mesh in invalid state. */ static int split_faces_prepare_new_verts( - const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert **new_verts, MemArena *memarena, - bool *r_need_vnors_recalc) + const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert **new_verts, MemArena *memarena) { - /* Note: if lnors_spacearr is NULL, ther is no autosmooth handling, and we only split out flat polys. */ + /* This is now mandatory, 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. */ + BLI_assert(lnors_spacearr != NULL); + const int num_loops = mesh->totloop; int num_verts = mesh->totvert; MVert *mvert = mesh->mvert; MLoop *mloop = mesh->mloop; BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__); + BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__); - if (lnors_spacearr) { - BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__); - - MLoop *ml = mloop; - MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr; - for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) { - if (!BLI_BITMAP_TEST(done_loops, loop_idx)) { - const int vert_idx = ml->v; - const bool vert_used = BLI_BITMAP_TEST_BOOL(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 ? num_verts++ : vert_idx; - - BLI_assert(*lnor_space); - - if ((*lnor_space)->loops) { - for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) { - const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link); - BLI_BITMAP_ENABLE(done_loops, ml_fan_idx); - if (vert_used) { - mloop[ml_fan_idx].v = new_vert_idx; - } - } - } - else { - /* Single loop in this fan... */ - BLI_BITMAP_ENABLE(done_loops, loop_idx); + MLoop *ml = mloop; + MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr; + + for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) { + if (!BLI_BITMAP_TEST(done_loops, loop_idx)) { + const int vert_idx = ml->v; + const bool vert_used = BLI_BITMAP_TEST_BOOL(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 ? num_verts++ : vert_idx; + + BLI_assert(*lnor_space); + + if ((*lnor_space)->loops) { + for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) { + const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link); + BLI_BITMAP_ENABLE(done_loops, ml_fan_idx); if (vert_used) { - ml->v = new_vert_idx; + mloop[ml_fan_idx].v = new_vert_idx; } } - - if (!vert_used) { - BLI_BITMAP_ENABLE(verts_used, vert_idx); - /* 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. ;) */ - normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor); - } - else { - /* Add new vert to list. */ - SplitFaceNewVert *new_vert = 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; - } } - } - - MEM_freeN(done_loops); - } - else { - /* No loop normal spaces available, we only split out flat polys. */ - const int num_polys = mesh->totpoly; - const MPoly *mpoly = mesh->mpoly; - - /* We do that in two loops, to keep original edges/verts to smooth polys preferencially. */ - const MPoly *mp = mpoly; - for (int i = 0; i < num_polys; i++, mp++) { - if (mp->flag & ME_SMOOTH) { - const MLoop *ml = &mloop[mp->loopstart]; - for (int j = 0; j < mp->totloop; j++, ml++) { - /* Just mark the vertex as used/reserved, that way neighbor flat polys, if any, - * will have to create their own. */ - BLI_BITMAP_ENABLE(verts_used, ml->v); + else { + /* Single loop in this fan... */ + BLI_BITMAP_ENABLE(done_loops, loop_idx); + if (vert_used) { + ml->v = new_vert_idx; } } - } - mp = mpoly; - for (int i = 0; i < num_polys; i++, mp++) { - if (!(mp->flag & ME_SMOOTH)) { - MLoop *ml = &mloop[mp->loopstart]; - for (int j = 0; j < mp->totloop; j++, ml++) { - const int vert_idx = ml->v; - - if (BLI_BITMAP_TEST(verts_used, vert_idx)) { - /* Add new vert to list. */ - const int new_vert_idx = num_verts++; - ml->v = new_vert_idx; - - SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert)); - new_vert->orig_index = vert_idx; - new_vert->new_index = new_vert_idx; - new_vert->vnor = NULL; /* See note below about normals. */ - new_vert->next = *new_verts; - *new_verts = new_vert; - } - else { - BLI_BITMAP_ENABLE(verts_used, vert_idx); - } - } - /* Note: there is no way to get new normals for smooth vertices here (and we don't have direct access - * to poly normals either for flat ones), so we'll have to recompute all vnors at the end... */ - *r_need_vnors_recalc = true; + if (!vert_used) { + BLI_BITMAP_ENABLE(verts_used, vert_idx); + /* 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. ;) */ + normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor); + } + else { + /* Add new vert to list. */ + SplitFaceNewVert *new_vert = 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; } } } + MEM_freeN(done_loops); MEM_freeN(verts_used); return num_verts - mesh->totvert; @@ -2353,27 +2319,17 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) } BKE_mesh_tessface_clear(mesh); - MLoopNorSpaceArray *lnors_spacearr = NULL; - MemArena *memarena; - bool need_vnors_recalc = false; - - if (mesh->flag & ME_AUTOSMOOTH) { - lnors_spacearr = MEM_callocN(sizeof(*lnors_spacearr), __func__); - /* 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); - /* Stealing memarena from loop normals space array. */ - memarena = lnors_spacearr->mem; - } - else { - /* We still have to split out flat faces... */ - memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - } + MLoopNorSpaceArray lnors_spacearr = {NULL}; + /* 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); + /* Stealing memarena from loop normals space array. */ + MemArena *memarena = lnors_spacearr.mem; SplitFaceNewVert *new_verts = NULL; SplitFaceNewEdge *new_edges = NULL; /* 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, &need_vnors_recalc); + 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 @@ -2385,9 +2341,9 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) /* Reallocate all vert and edge related data. */ mesh->totvert += num_new_verts; - mesh->totedge += num_new_edges; CustomData_realloc(&mesh->vdata, mesh->totvert); if (do_edges) { + mesh->totedge += num_new_edges; CustomData_realloc(&mesh->edata, mesh->totedge); } /* Update pointers to a newly allocated memory. */ @@ -2407,18 +2363,9 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop); } - if (lnors_spacearr) { - /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */ - BKE_lnor_spacearr_free(lnors_spacearr); - MEM_freeN(lnors_spacearr); - } - else { - BLI_memarena_free(memarena); - } + /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */ + BKE_lnor_spacearr_free(&lnors_spacearr); - if (need_vnors_recalc) { - BKE_mesh_calc_normals(mesh); - } #ifdef VALIDATE_MESH BKE_mesh_validate(mesh, true, true); #endif @@ -2447,7 +2394,9 @@ Mesh *BKE_mesh_new_from_object( int uv_from_orco; /* copies object and modifiers (but not the data) */ - Object *tmpobj = BKE_object_copy_ex(bmain, ob, true); + Object *tmpobj; + /* TODO: make it temp copy outside bmain! */ + BKE_id_copy_ex(bmain, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_CACHES, false); tmpcu = (Curve *)tmpobj->data; id_us_min(&tmpcu->id); diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 5dfcef9f9bf..643ca3ee536 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -2002,11 +2002,14 @@ float BKE_mesh_calc_poly_area( * - http://forums.cgsociety.org/archive/index.php?t-756235.html * - http://www.globalspec.com/reference/52702/203279/4-8-the-centroid-of-a-tetrahedron * - * \note volume is 6x actual volume, and centroid is 4x actual volume-weighted centroid - * (so division can be done once at the end) - * \note results will have bias if polygon is non-planar. + * \note + * - Volume is 6x actual volume, and centroid is 4x actual volume-weighted centroid + * (so division can be done once at the end). + * - Results will have bias if polygon is non-planar. + * - The resulting volume will only be correct if the mesh is manifold and has consistent face winding + * (non-contiguous face normals or holes in the mesh surface). */ -static float mesh_calc_poly_volume_and_weighted_centroid( +static float mesh_calc_poly_volume_centroid( const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray, float r_cent[3]) { @@ -2043,6 +2046,43 @@ static float mesh_calc_poly_volume_and_weighted_centroid( return total_volume; } +/** + * \note + * - Results won't be correct if polygon is non-planar. + * - This has the advantage over #mesh_calc_poly_volume_centroid + * that it doesn't depend on solid geometry, instead it weights the surface by volume. + */ +static float mesh_calc_poly_area_centroid( + const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray, + float r_cent[3]) +{ + int i; + float tri_area; + float total_area = 0.0f; + float v1[3], v2[3], v3[3], normal[3], tri_cent[3]; + + BKE_mesh_calc_poly_normal(mpoly, loopstart, mvarray, normal); + copy_v3_v3(v1, mvarray[loopstart[0].v].co); + copy_v3_v3(v2, mvarray[loopstart[1].v].co); + zero_v3(r_cent); + + for (i = 2; i < mpoly->totloop; i++) { + copy_v3_v3(v3, mvarray[loopstart[i].v].co); + + tri_area = area_tri_signed_v3(v1, v2, v3, normal); + total_area += tri_area; + + mid_v3_v3v3v3(tri_cent, v1, v2, v3); + madd_v3_v3fl(r_cent, tri_cent, tri_area); + + copy_v3_v3(v2, v3); + } + + mul_v3_fl(r_cent, 1.0f / total_area); + + return total_area; +} + #if 0 /* slow version of the function below */ void BKE_mesh_calc_poly_angles(MPoly *mpoly, MLoop *loopstart, MVert *mvarray, float angles[]) @@ -2157,7 +2197,40 @@ bool BKE_mesh_center_bounds(const Mesh *me, float r_cent[3]) return false; } -bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3]) +bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3]) +{ + int i = me->totpoly; + MPoly *mpoly; + float poly_area; + float total_area = 0.0f; + float poly_cent[3]; + + zero_v3(r_cent); + + /* calculate a weighted average of polygon centroids */ + for (mpoly = me->mpoly; i--; mpoly++) { + poly_area = mesh_calc_poly_area_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent); + + madd_v3_v3fl(r_cent, poly_cent, poly_area); + total_area += poly_area; + } + /* otherwise we get NAN for 0 polys */ + if (me->totpoly) { + mul_v3_fl(r_cent, 1.0f / total_area); + } + + /* zero area faces cause this, fallback to median */ + if (UNLIKELY(!is_finite_v3(r_cent))) { + return BKE_mesh_center_median(me, r_cent); + } + + return (me->totpoly != 0); +} + +/** + * \note Mesh must be manifold with consistent face-winding, see #mesh_calc_poly_volume_centroid for details. + */ +bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3]) { int i = me->totpoly; MPoly *mpoly; @@ -2169,7 +2242,7 @@ bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3]) /* calculate a weighted average of polyhedron centroids */ for (mpoly = me->mpoly; i--; mpoly++) { - poly_volume = mesh_calc_poly_volume_and_weighted_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent); + poly_volume = mesh_calc_poly_volume_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent); /* poly_cent is already volume-weighted, so no need to multiply by the volume */ add_v3_v3(r_cent, poly_cent); @@ -2189,6 +2262,7 @@ bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3]) return (me->totpoly != 0); } + /** \} */ diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index c5fa9b15896..d2fe8f27f4a 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -1184,7 +1184,6 @@ void BKE_mesh_remap_calc_loops_from_dm( bool polys_allocated_src; MPoly *polys_src = DM_get_poly_array(dm_src, &polys_allocated_src); const int num_polys_src = dm_src->getNumPolys(dm_src); - bool looptri_allocated_src = false; const MLoopTri *looptri_src = NULL; int num_looptri_src = 0; @@ -1374,17 +1373,11 @@ void BKE_mesh_remap_calc_loops_from_dm( if (dirty_tess_flag) { dm_src->dirty &= ~dirty_tess_flag; } - DM_ensure_looptri(dm_src); if (dirty_tess_flag) { dm_src->dirty |= dirty_tess_flag; } - looptri_src = DM_get_looptri_array( - dm_src, - verts_src, - polys_src, num_polys_src, - loops_src, num_loops_src, - &looptri_allocated_src); + looptri_src = dm_src->getLoopTriArray(dm_src); num_looptri_src = dm_src->getNumLoopTri(dm_src); looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__); @@ -1403,7 +1396,7 @@ void BKE_mesh_remap_calc_loops_from_dm( &treedata[tindex], verts_src, verts_allocated_src, loops_src, loops_allocated_src, - looptri_src, num_looptri_src, looptri_allocated_src, + looptri_src, num_looptri_src, false, looptri_active, num_looptri_active, bvh_epsilon, 2, 6); if (verts_allocated_src) { verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */ @@ -1411,9 +1404,6 @@ void BKE_mesh_remap_calc_loops_from_dm( if (loops_allocated_src) { loops_allocated_src = false; /* Only 'give' our loops once, to first tree! */ } - if (looptri_allocated_src) { - looptri_allocated_src = false; /* Only 'give' our looptri once, to first tree! */ - } } MEM_freeN(looptri_active); @@ -1928,9 +1918,6 @@ void BKE_mesh_remap_calc_loops_from_dm( if (polys_allocated_src) { MEM_freeN(polys_src); } - if (looptri_allocated_src) { - MEM_freeN((void *)looptri_src); - } if (vert_to_loop_map_src) { MEM_freeN(vert_to_loop_map_src); } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 2276d56b9c6..118bafa94d2 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -59,6 +59,8 @@ #include "BKE_appdir.h" #include "BKE_key.h" +#include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_multires.h" #include "BKE_DerivedMesh.h" @@ -269,14 +271,37 @@ void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst) memcpy(md_dst_data, md_src_data, (size_t)mti->structSize - data_size); } -void modifier_copyData(ModifierData *md, ModifierData *target) +static void modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag) +{ + ID *id = *idpoin; + if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + id_us_plus(id); + } +} + +void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); target->mode = md->mode; - if (mti->copyData) + if (mti->copyData) { mti->copyData(md, target); + } + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + if (mti->foreachIDLink) { + mti->foreachIDLink(target, NULL, modifier_copy_data_id_us_cb, NULL); + } + else if (mti->foreachObjectLink) { + mti->foreachObjectLink(target, NULL, (ObjectWalkFunc)modifier_copy_data_id_us_cb, NULL); + } + } +} + +void modifier_copyData(ModifierData *md, ModifierData *target) +{ + modifier_copyData_ex(md, target, 0); } diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index dfa8742a295..16d597e25fa 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -588,7 +588,7 @@ static MovieClip *movieclip_alloc(Main *bmain, const char *name) { MovieClip *clip; - clip = BKE_libblock_alloc(bmain, ID_MC, name); + clip = BKE_libblock_alloc(bmain, ID_MC, name, 0); clip->aspx = clip->aspy = 1.0f; @@ -1488,25 +1488,33 @@ void BKE_movieclip_free(MovieClip *clip) BKE_animdata_free((ID *) clip, false); } -MovieClip *BKE_movieclip_copy(Main *bmain, const MovieClip *clip) +/** + * Only copy internal data of MovieClip ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_movieclip_copy_data(Main *UNUSED(bmain), MovieClip *clip_dst, const MovieClip *clip_src, const int flag) { - MovieClip *clip_new; - - clip_new = BKE_libblock_copy(bmain, &clip->id); + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; - clip_new->anim = NULL; - clip_new->cache = NULL; + clip_dst->anim = NULL; + clip_dst->cache = NULL; - BKE_tracking_copy(&clip_new->tracking, &clip->tracking); - clip_new->tracking_context = NULL; + BKE_tracking_copy(&clip_dst->tracking, &clip_src->tracking, flag_subdata); + clip_dst->tracking_context = NULL; - id_us_plus((ID *)clip_new->gpd); - - BKE_color_managed_colorspace_settings_copy(&clip_new->colorspace_settings, &clip->colorspace_settings); - - BKE_id_copy_ensure_local(bmain, &clip->id, &clip_new->id); + BKE_color_managed_colorspace_settings_copy(&clip_dst->colorspace_settings, &clip_src->colorspace_settings); +} - return clip_new; +MovieClip *BKE_movieclip_copy(Main *bmain, const MovieClip *clip) +{ + MovieClip *clip_copy; + BKE_id_copy_ex(bmain, &clip->id, (ID **)&clip_copy, 0, false); + return clip_copy; } void BKE_movieclip_make_local(Main *bmain, MovieClip *clip, const bool lib_local) diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 5acfe4a0aa4..54afe76ec07 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -902,80 +902,100 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) return nodeAddNode(C, ntree, idname); } -static void node_socket_copy(bNodeSocket *dst, bNodeSocket *src) +static void node_socket_copy(bNodeSocket *sock_dst, bNodeSocket *sock_src, const int flag) { - src->new_sock = dst; - - if (src->prop) - dst->prop = IDP_CopyProperty(src->prop); - - if (src->default_value) - dst->default_value = MEM_dupallocN(src->default_value); - - dst->stack_index = 0; + sock_src->new_sock = sock_dst; + + if (sock_src->prop) { + sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag); + } + + if (sock_src->default_value) { + sock_dst->default_value = MEM_dupallocN(sock_src->default_value); + } + + sock_dst->stack_index = 0; /* XXX some compositor node (e.g. image, render layers) still store * some persistent buffer data here, need to clear this to avoid dangling pointers. */ - dst->cache = NULL; + sock_dst->cache = NULL; } /* keep socket listorder identical, for copying links */ /* ntree is the target tree */ -bNode *nodeCopyNode(bNodeTree *ntree, bNode *node) +bNode *BKE_node_copy_ex(bNodeTree *ntree, bNode *node_src, const int flag) { - bNode *nnode = MEM_callocN(sizeof(bNode), "dupli node"); - bNodeSocket *sock, *oldsock; - bNodeLink *link, *oldlink; + bNode *node_dst = MEM_callocN(sizeof(bNode), "dupli node"); + bNodeSocket *sock_dst, *sock_src; + bNodeLink *link_dst, *link_src; - *nnode = *node; + *node_dst = *node_src; /* can be called for nodes outside a node tree (e.g. clipboard) */ if (ntree) { - nodeUniqueName(ntree, nnode); + nodeUniqueName(ntree, node_dst); - BLI_addtail(&ntree->nodes, nnode); + BLI_addtail(&ntree->nodes, node_dst); } - BLI_duplicatelist(&nnode->inputs, &node->inputs); - oldsock = node->inputs.first; - for (sock = nnode->inputs.first; sock; sock = sock->next, oldsock = oldsock->next) - node_socket_copy(sock, oldsock); - - BLI_duplicatelist(&nnode->outputs, &node->outputs); - oldsock = node->outputs.first; - for (sock = nnode->outputs.first; sock; sock = sock->next, oldsock = oldsock->next) - node_socket_copy(sock, oldsock); - - if (node->prop) - nnode->prop = IDP_CopyProperty(node->prop); - - BLI_duplicatelist(&nnode->internal_links, &node->internal_links); - oldlink = node->internal_links.first; - for (link = nnode->internal_links.first; link; link = link->next, oldlink = oldlink->next) { - link->fromnode = nnode; - link->tonode = nnode; - link->fromsock = link->fromsock->new_sock; - link->tosock = link->tosock->new_sock; + BLI_duplicatelist(&node_dst->inputs, &node_src->inputs); + for (sock_dst = node_dst->inputs.first, sock_src = node_src->inputs.first; + sock_dst != NULL; + sock_dst = sock_dst->next, sock_src = sock_src->next) + { + node_socket_copy(sock_dst, sock_src, flag); } - - /* don't increase node->id users, freenode doesn't decrement either */ - - if (node->typeinfo->copyfunc) - node->typeinfo->copyfunc(ntree, nnode, node); - - node->new_node = nnode; - nnode->new_node = NULL; - - if (nnode->typeinfo->copyfunc_api) { + + BLI_duplicatelist(&node_dst->outputs, &node_src->outputs); + for (sock_dst = node_dst->outputs.first, sock_src = node_src->outputs.first; + sock_dst != NULL; + sock_dst = sock_dst->next, sock_src = sock_src->next) + { + node_socket_copy(sock_dst, sock_src, flag); + } + + if (node_src->prop) { + node_dst->prop = IDP_CopyProperty_ex(node_src->prop, flag); + } + + BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links); + for (link_dst = node_dst->internal_links.first, link_src = node_src->internal_links.first; + link_dst != NULL; + link_dst = link_dst->next, link_src = link_src->next) + { + link_dst->fromnode = node_dst; + link_dst->tonode = node_dst; + link_dst->fromsock = link_dst->fromsock->new_sock; + link_dst->tosock = link_dst->tosock->new_sock; + } + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus(node_dst->id); + } + + if (node_src->typeinfo->copyfunc) { + node_src->typeinfo->copyfunc(ntree, node_dst, node_src); + } + + node_src->new_node = node_dst; + node_dst->new_node = NULL; + + if (node_dst->typeinfo->copyfunc_api) { PointerRNA ptr; - RNA_pointer_create((ID *)ntree, &RNA_Node, nnode, &ptr); - - nnode->typeinfo->copyfunc_api(&ptr, node); + RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr); + + node_dst->typeinfo->copyfunc_api(&ptr, node_src); } - - if (ntree) + + if (ntree) { ntree->update |= NTREE_UPDATE_NODES; - - return nnode; + } + + return node_dst; +} + +bNode *nodeCopyNode(bNodeTree *ntree, bNode *node) +{ + return BKE_node_copy_ex(ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT); } /* also used via rna api, so we check for proper input output direction */ @@ -1172,7 +1192,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) * node groups and other tree types are created as library data. */ if (bmain) { - ntree = BKE_libblock_alloc(bmain, ID_NT, name); + ntree = BKE_libblock_alloc(bmain, ID_NT, name, 0); } else { ntree = MEM_callocN(sizeof(bNodeTree), "new node tree"); @@ -1191,119 +1211,96 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) return ntree; } -/* Warning: this function gets called during some rather unexpected times - * - this gets called when executing compositing updates (for threaded previews) - * - when the nodetree datablock needs to be copied (i.e. when users get copied) - * - for scene duplication use ntreeSwapID() after so we don't have stale pointers. +/** + * Only copy internal data of NodeTree ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! * - * do_make_extern: keep enabled for general use, only reason _not_ to enable is when - * copying for internal use (threads for eg), where you wont want it to modify the - * scene data. + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ -static bNodeTree *ntreeCopyTree_internal( - const bNodeTree *ntree, Main *bmain, - bool skip_database, bool do_id_user, bool do_make_extern, bool copy_previews) +void BKE_node_tree_copy_data(Main *UNUSED(bmain), bNodeTree *ntree_dst, const bNodeTree *ntree_src, const int flag) { - bNodeTree *newtree; - bNode *node /*, *nnode */ /* UNUSED */, *last; - bNodeSocket *sock, *oldsock; - bNodeLink *link; - - if (ntree == NULL) return NULL; - - /* is ntree part of library? */ - if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) { - newtree = BKE_libblock_copy(bmain, &ntree->id); - } - else { - newtree = BKE_libblock_copy_nolib(&ntree->id, true); - } + bNodeSocket *sock_dst, *sock_src; + bNodeLink *link_dst; - id_us_plus((ID *)newtree->gpd); + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; /* in case a running nodetree is copied */ - newtree->execdata = NULL; - - newtree->duplilock = NULL; - - BLI_listbase_clear(&newtree->nodes); - BLI_listbase_clear(&newtree->links); - - last = ntree->nodes.last; - for (node = ntree->nodes.first; node; node = node->next) { + ntree_dst->execdata = NULL; - /* ntreeUserDecrefID inline */ - if (do_id_user) { - id_us_plus(node->id); - } + ntree_dst->duplilock = NULL; - if (do_make_extern) { - id_lib_extern(node->id); - } + BLI_listbase_clear(&ntree_dst->nodes); + BLI_listbase_clear(&ntree_dst->links); - node->new_node = NULL; - /* nnode = */ nodeCopyNode(newtree, node); /* sets node->new */ - - /* make sure we don't copy new nodes again! */ - if (node == last) - break; + for (bNode *node_src = ntree_src->nodes.first; node_src; node_src = node_src->next) { + BKE_node_copy_ex(ntree_dst, node_src, flag_subdata); } - + /* copy links */ - BLI_duplicatelist(&newtree->links, &ntree->links); - for (link = newtree->links.first; link; link = link->next) { - link->fromnode = (link->fromnode ? link->fromnode->new_node : NULL); - link->fromsock = (link->fromsock ? link->fromsock->new_sock : NULL); - link->tonode = (link->tonode ? link->tonode->new_node : NULL); - link->tosock = (link->tosock ? link->tosock->new_sock : NULL); + BLI_duplicatelist(&ntree_dst->links, &ntree_src->links); + for (link_dst = ntree_dst->links.first; link_dst; link_dst = link_dst->next) { + link_dst->fromnode = (link_dst->fromnode ? link_dst->fromnode->new_node : NULL); + link_dst->fromsock = (link_dst->fromsock ? link_dst->fromsock->new_sock : NULL); + link_dst->tonode = (link_dst->tonode ? link_dst->tonode->new_node : NULL); + link_dst->tosock = (link_dst->tosock ? link_dst->tosock->new_sock : NULL); /* update the link socket's pointer */ - if (link->tosock) - link->tosock->link = link; + if (link_dst->tosock) { + link_dst->tosock->link = link_dst; + } } - + /* copy interface sockets */ - BLI_duplicatelist(&newtree->inputs, &ntree->inputs); - oldsock = ntree->inputs.first; - for (sock = newtree->inputs.first; sock; sock = sock->next, oldsock = oldsock->next) - node_socket_copy(sock, oldsock); - - BLI_duplicatelist(&newtree->outputs, &ntree->outputs); - oldsock = ntree->outputs.first; - for (sock = newtree->outputs.first; sock; sock = sock->next, oldsock = oldsock->next) - node_socket_copy(sock, oldsock); - + BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs); + for (sock_dst = ntree_dst->inputs.first, sock_src = ntree_src->inputs.first; + sock_dst != NULL; + sock_dst = sock_dst->next, sock_src = sock_src->next) + { + node_socket_copy(sock_dst, sock_src, flag_subdata); + } + + BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs); + for (sock_dst = ntree_dst->outputs.first, sock_src = ntree_src->outputs.first; + sock_dst != NULL; + sock_dst = sock_dst->next, sock_src = sock_src->next) + { + node_socket_copy(sock_dst, sock_src, flag_subdata); + } + /* copy preview hash */ - if (ntree->previews && copy_previews) { + if (ntree_src->previews && (flag & LIB_ID_COPY_NO_PREVIEW) == 0) { bNodeInstanceHashIterator iter; - - newtree->previews = BKE_node_instance_hash_new("node previews"); - - NODE_INSTANCE_HASH_ITER(iter, ntree->previews) { + + ntree_dst->previews = BKE_node_instance_hash_new("node previews"); + + NODE_INSTANCE_HASH_ITER(iter, ntree_src->previews) { bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter); - BKE_node_instance_hash_insert(newtree->previews, key, BKE_node_preview_copy(preview)); + BKE_node_instance_hash_insert(ntree_dst->previews, key, BKE_node_preview_copy(preview)); } } - else - newtree->previews = NULL; - + else { + ntree_dst->previews = NULL; + } + /* update node->parent pointers */ - for (node = newtree->nodes.first; node; node = node->next) { - if (node->parent) - node->parent = node->parent->new_node; + for (bNode *node_dst = ntree_dst->nodes.first, *node_src = ntree_src->nodes.first; node_dst; node_dst = node_dst->next, node_src = node_src->next) { + if (node_dst->parent) { + node_dst->parent = node_dst->parent->new_node; + } } - - /* node tree will generate its own interface type */ - newtree->interface_type = NULL; - - BKE_id_copy_ensure_local(bmain, &ntree->id, &newtree->id); - return newtree; + /* node tree will generate its own interface type */ + ntree_dst->interface_type = NULL; } bNodeTree *ntreeCopyTree_ex(const bNodeTree *ntree, Main *bmain, const bool do_id_user) { - return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true); + bNodeTree *ntree_copy; + BKE_id_copy_ex(bmain, (ID *)ntree, (ID **)&ntree_copy, do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT, false); + return ntree_copy; } bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree) { @@ -1994,10 +1991,11 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) adt->tmpact = NULL; } - /* Make full copy. + /* Make full copy outside of Main database. * Note: previews are not copied here. */ - ltree = ntreeCopyTree_internal(ntree, G.main, true, false, false, false); + BKE_id_copy_ex(G.main, (ID *)ntree, (ID **)<ree, + LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_COPY_NO_PREVIEW, false); ltree->flag |= NTREE_IS_LOCALIZED; for (node = ltree->nodes.first; node; node = node->next) { @@ -2237,7 +2235,7 @@ static void ntree_interface_type_create(bNodeTree *ntree) /* register a subtype of PropertyGroup */ srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_PropertyGroup); RNA_def_struct_ui_text(srna, name, description); - RNA_def_struct_duplicate_pointers(srna); + RNA_def_struct_duplicate_pointers(&BLENDER_RNA, srna); /* associate the RNA type with the node tree */ ntree->interface_type = srna; @@ -2276,10 +2274,10 @@ StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, int create) ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description); /* rename the RNA type */ - RNA_def_struct_free_pointers(srna); - RNA_def_struct_identifier(srna, identifier); + RNA_def_struct_free_pointers(&BLENDER_RNA, srna); + RNA_def_struct_identifier(&BLENDER_RNA, srna, identifier); RNA_def_struct_ui_text(srna, name, description); - RNA_def_struct_duplicate_pointers(srna); + RNA_def_struct_duplicate_pointers(&BLENDER_RNA, srna); } } else if (create) { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index f3086396c3a..44058c989ff 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -312,7 +312,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr modifier_unique_name(&ob_dst->modifiers, nmd); } - BKE_object_copy_particlesystems(ob_dst, ob_src); + BKE_object_copy_particlesystems(ob_dst, ob_src, 0); /* TODO: smoke?, cloth? */ } @@ -330,14 +330,14 @@ void BKE_object_free_derived_caches(Object *ob) Mesh *me = ob->data; if (me && me->bb) { - atomic_fetch_and_or_uint32((uint*)&me->bb->flag, BOUNDBOX_DIRTY); + atomic_fetch_and_or_uint32((uint *)&me->bb->flag, BOUNDBOX_DIRTY); } } else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { Curve *cu = ob->data; if (cu && cu->bb) { - atomic_fetch_and_or_uint32((uint*)&cu->bb->flag, BOUNDBOX_DIRTY); + atomic_fetch_and_or_uint32((uint *)&cu->bb->flag, BOUNDBOX_DIRTY); } } @@ -670,7 +670,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) if (!name) name = get_obdata_defname(type); - ob = BKE_libblock_alloc(bmain, ID_OB, name); + ob = BKE_libblock_alloc(bmain, ID_OB, name, 0); /* default object vars */ ob->type = type; @@ -837,7 +837,7 @@ struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene) #endif /* WITH_GAMEENGINE */ -SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches) +SoftBody *copy_softbody(const SoftBody *sb, const int flag) { SoftBody *sbn; @@ -845,7 +845,7 @@ SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches) sbn = MEM_dupallocN(sb); - if (copy_caches == false) { + if ((flag & LIB_ID_COPY_CACHES) == 0) { sbn->totspring = sbn->totpoint = 0; sbn->bpoint = NULL; sbn->bspring = NULL; @@ -874,7 +874,7 @@ SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches) sbn->scratch = NULL; - sbn->pointcache = BKE_ptcache_copy_list(&sbn->ptcaches, &sb->ptcaches, copy_caches); + sbn->pointcache = BKE_ptcache_copy_list(&sbn->ptcaches, &sb->ptcaches, flag); if (sb->effector_weights) sbn->effector_weights = MEM_dupallocN(sb->effector_weights); @@ -882,7 +882,7 @@ SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches) return sbn; } -BulletSoftBody *copy_bulletsoftbody(const BulletSoftBody *bsb) +BulletSoftBody *copy_bulletsoftbody(const BulletSoftBody *bsb, const int UNUSED(flag)) { BulletSoftBody *bsbn; @@ -893,7 +893,7 @@ BulletSoftBody *copy_bulletsoftbody(const BulletSoftBody *bsb) return bsbn; } -ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) +ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int flag) { ParticleSystem *psysn; ParticleData *pa; @@ -930,7 +930,7 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) if (psys->clmd) { psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth); - modifier_copyData((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd); + modifier_copyData_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag); psys->hair_in_dm = psys->hair_out_dm = NULL; } @@ -948,7 +948,8 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) BLI_listbase_clear(&psysn->childcachebufs); psysn->renderdata = NULL; - psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, false); + /* XXX Never copy caches here? */ + psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag & ~LIB_ID_COPY_CACHES); /* XXX - from reading existing code this seems correct but intended usage of * pointcache should /w cloth should be added in 'ParticleSystem' - campbell */ @@ -956,12 +957,14 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) psysn->clmd->point_cache = psysn->pointcache; } - id_us_plus((ID *)psysn->part); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)psysn->part); + } return psysn; } -void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src) +void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const int flag) { ParticleSystem *psys, *npsys; ModifierData *md; @@ -973,7 +976,7 @@ void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src) BLI_listbase_clear(&ob_dst->particlesystem); for (psys = ob_src->particlesystem.first; psys; psys = psys->next) { - npsys = BKE_object_copy_particlesystem(psys); + npsys = BKE_object_copy_particlesystem(psys, flag); BLI_addtail(&ob_dst->particlesystem, npsys); @@ -1010,23 +1013,25 @@ void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src) { if (ob_src->soft) { ob_dst->softflag = ob_src->softflag; - ob_dst->soft = copy_softbody(ob_src->soft, false); + ob_dst->soft = copy_softbody(ob_src->soft, 0); } } -static void copy_object_pose(Object *obn, const Object *ob) +static void copy_object_pose(Object *obn, const Object *ob, const int flag) { bPoseChannel *chan; /* note: need to clear obn->pose pointer first, so that BKE_pose_copy_data works (otherwise there's a crash) */ obn->pose = NULL; - BKE_pose_copy_data(&obn->pose, ob->pose, 1); /* 1 = copy constraints */ + BKE_pose_copy_data_ex(&obn->pose, ob->pose, flag, true); /* true = copy constraints */ for (chan = obn->pose->chanbase.first; chan; chan = chan->next) { bConstraint *con; chan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE); + /* XXX Remapping object pointing onto itself should be handled by generic BKE_library_remap stuff, but... + * the flush_constraint_targets callback am not sure about, so will delay that for now. */ for (con = chan->constraints.first; con; con = con->next) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; @@ -1047,13 +1052,10 @@ static void copy_object_pose(Object *obn, const Object *ob) } } -static void copy_object_lod(Object *obn, const Object *ob) +static void copy_object_lod(Object *obn, const Object *ob, const int UNUSED(flag)) { BLI_duplicatelist(&obn->lodlevels, &ob->lodlevels); - if (obn->lodlevels.first) - ((LodLevel *)obn->lodlevels.first)->source = obn; - obn->currentlod = (LodLevel *)obn->lodlevels.first; } @@ -1098,98 +1100,99 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src) copy_v3_v3(ob_tar->size, ob_src->size); } -Object *BKE_object_copy_ex(Main *bmain, const Object *ob, bool copy_caches) +/** + * Only copy internal data of Object ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_src, const int flag) { - Object *obn; ModifierData *md; - int a; - obn = BKE_libblock_copy(bmain, &ob->id); - - if (ob->totcol) { - obn->mat = MEM_dupallocN(ob->mat); - obn->matbits = MEM_dupallocN(ob->matbits); - obn->totcol = ob->totcol; + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; + + if (ob_src->totcol) { + ob_dst->mat = MEM_dupallocN(ob_src->mat); + ob_dst->matbits = MEM_dupallocN(ob_src->matbits); + ob_dst->totcol = ob_src->totcol; } - if (ob->iuser) obn->iuser = MEM_dupallocN(ob->iuser); + if (ob_src->iuser) ob_dst->iuser = MEM_dupallocN(ob_src->iuser); - if (ob->bb) obn->bb = MEM_dupallocN(ob->bb); - obn->flag &= ~OB_FROMGROUP; + if (ob_src->bb) ob_dst->bb = MEM_dupallocN(ob_src->bb); + ob_dst->flag &= ~OB_FROMGROUP; - BLI_listbase_clear(&obn->modifiers); + BLI_listbase_clear(&ob_dst->modifiers); - for (md = ob->modifiers.first; md; md = md->next) { + for (md = ob_src->modifiers.first; md; md = md->next) { ModifierData *nmd = modifier_new(md->type); BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); - modifier_copyData(md, nmd); - BLI_addtail(&obn->modifiers, nmd); + modifier_copyData_ex(md, nmd, flag_subdata); + BLI_addtail(&ob_dst->modifiers, nmd); } - BLI_listbase_clear(&obn->prop); - BKE_bproperty_copy_list(&obn->prop, &ob->prop); + BLI_listbase_clear(&ob_dst->prop); + BKE_bproperty_copy_list(&ob_dst->prop, &ob_src->prop); - BKE_sca_logic_copy(obn, ob); + BKE_sca_logic_copy(ob_dst, ob_src, flag_subdata); - if (ob->pose) { - copy_object_pose(obn, ob); + if (ob_src->pose) { + copy_object_pose(ob_dst, ob_src, flag_subdata); /* backwards compat... non-armatures can get poses in older files? */ - if (ob->type == OB_ARMATURE) - BKE_pose_rebuild(obn, obn->data); + if (ob_src->type == OB_ARMATURE) + BKE_pose_rebuild(ob_dst, ob_dst->data); } - defgroup_copy_list(&obn->defbase, &ob->defbase); - BKE_constraints_copy(&obn->constraints, &ob->constraints, true); - - obn->mode = OB_MODE_OBJECT; - obn->sculpt = NULL; + defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase); + BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true); - /* increase user numbers */ - id_us_plus((ID *)obn->data); - id_us_plus((ID *)obn->poselib); - id_us_plus((ID *)obn->gpd); - id_us_plus((ID *)obn->dup_group); + ob_dst->mode = OB_MODE_OBJECT; + ob_dst->sculpt = NULL; - for (a = 0; a < obn->totcol; a++) id_us_plus((ID *)obn->mat[a]); - - if (ob->pd) { - obn->pd = MEM_dupallocN(ob->pd); - if (obn->pd->tex) - id_us_plus(&(obn->pd->tex->id)); - if (obn->pd->rng) - obn->pd->rng = MEM_dupallocN(ob->pd->rng); + if (ob_src->pd) { + ob_dst->pd = MEM_dupallocN(ob_src->pd); + if (ob_dst->pd->rng) { + ob_dst->pd->rng = MEM_dupallocN(ob_src->pd->rng); + } } - obn->soft = copy_softbody(ob->soft, copy_caches); - obn->bsoft = copy_bulletsoftbody(ob->bsoft); - obn->rigidbody_object = BKE_rigidbody_copy_object(ob); - obn->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob); + ob_dst->soft = copy_softbody(ob_src->soft, flag_subdata); + ob_dst->bsoft = copy_bulletsoftbody(ob_src->bsoft, flag_subdata); + ob_dst->rigidbody_object = BKE_rigidbody_copy_object(ob_src, flag_subdata); + ob_dst->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob_src, flag_subdata); - BKE_object_copy_particlesystems(obn, ob); + BKE_object_copy_particlesystems(ob_dst, ob_src, flag_subdata); - obn->derivedDeform = NULL; - obn->derivedFinal = NULL; + ob_dst->derivedDeform = NULL; + ob_dst->derivedFinal = NULL; - BLI_listbase_clear(&obn->gpulamp); - BLI_listbase_clear(&obn->pc_ids); + BLI_listbase_clear(&ob_dst->gpulamp); + BLI_listbase_clear(&ob_dst->pc_ids); - obn->mpath = NULL; + ob_dst->mpath = NULL; - copy_object_lod(obn, ob); + copy_object_lod(ob_dst, ob_src, flag_subdata); - /* Copy runtime surve data. */ - obn->curve_cache = NULL; - - BKE_id_copy_ensure_local(bmain, &ob->id, &obn->id); + /* Do not copy runtime curve data. */ + ob_dst->curve_cache = NULL; /* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */ - obn->preview = NULL; - - return obn; + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ + BKE_previewimg_id_copy(&ob_dst->id, &ob_src->id); + } + else { + ob_dst->preview = NULL; + } } /* copy objects, will re-initialize cached simulation data */ Object *BKE_object_copy(Main *bmain, const Object *ob) { - return BKE_object_copy_ex(bmain, ob, false); + Object *ob_copy; + BKE_id_copy_ex(bmain, &ob->id, (ID **)&ob_copy, 0, false); + return ob_copy; } void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, const bool clear_proxy) @@ -1387,7 +1390,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) /* type conversions */ if (target->type == OB_ARMATURE) { - copy_object_pose(ob, target); /* data copy, object pointers in constraints */ + copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */ BKE_pose_rest(ob->pose); /* clear all transforms in channels */ BKE_pose_rebuild(ob, ob->data); /* set all internal links */ @@ -2679,7 +2682,7 @@ void BKE_object_sculpt_modifiers_changed(Object *ob) { SculptSession *ss = ob->sculpt; - if (ss) { + if (ss && ss->building_vp_handle == false) { if (!ss->cache) { /* we free pbvh on changes, except during sculpt since it can't deal with * changing PVBH node organization, we hope topology does not change in @@ -2690,6 +2693,9 @@ void BKE_object_sculpt_modifiers_changed(Object *ob) } BKE_sculptsession_free_deformMats(ob->sculpt); + + /* In vertex/weight paint, force maps to be rebuilt. */ + BKE_sculptsession_free_vwpaint_data(ob->sculpt); } else { PBVHNode **nodes; diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index ccf2aec5c7a..d387e30050c 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -481,6 +481,8 @@ bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_t *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw; return true; } + default: + break; } } diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 076bef71875..b49e481b068 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -343,7 +343,7 @@ static void make_duplis_group(const DupliContext *ctx) } } -const DupliGenerator gen_dupli_group = { +static const DupliGenerator gen_dupli_group = { OB_DUPLIGROUP, /* type */ make_duplis_group /* make_duplis */ }; @@ -421,7 +421,7 @@ static void make_duplis_frames(const DupliContext *ctx) *ob = copyob; } -const DupliGenerator gen_dupli_frames = { +static const DupliGenerator gen_dupli_frames = { OB_DUPLIFRAMES, /* type */ make_duplis_frames /* make_duplis */ }; @@ -571,7 +571,7 @@ static void make_duplis_verts(const DupliContext *ctx) vdd.dm->release(vdd.dm); } -const DupliGenerator gen_dupli_verts = { +static const DupliGenerator gen_dupli_verts = { OB_DUPLIVERTS, /* type */ make_duplis_verts /* make_duplis */ }; @@ -684,7 +684,7 @@ static void make_duplis_font(const DupliContext *ctx) MEM_freeN(chartransdata); } -const DupliGenerator gen_dupli_verts_font = { +static const DupliGenerator gen_dupli_verts_font = { OB_DUPLIVERTS, /* type */ make_duplis_font /* make_duplis */ }; @@ -847,7 +847,7 @@ static void make_duplis_faces(const DupliContext *ctx) fdd.dm->release(fdd.dm); } -const DupliGenerator gen_dupli_faces = { +static const DupliGenerator gen_dupli_faces = { OB_DUPLIFACES, /* type */ make_duplis_faces /* make_duplis */ }; @@ -1168,7 +1168,7 @@ static void make_duplis_particles(const DupliContext *ctx) } } -const DupliGenerator gen_dupli_particles = { +static const DupliGenerator gen_dupli_particles = { OB_DUPLIPARTS, /* type */ make_duplis_particles /* make_duplis */ }; diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 64f90ef5c52..89f25136caf 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -522,6 +522,8 @@ static void unpack_generate_paths( case ID_IM: BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname); break; + default: + break; } { @@ -712,6 +714,8 @@ bool BKE_pack_check(ID *id) Library *li = (Library *)id; return li->packedfile != NULL; } + default: + break; } return false; } @@ -750,5 +754,7 @@ void BKE_unpack_id(Main *bmain, ID *id, ReportList *reports, int how) BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->name); break; } + default: + break; } } diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index c7cfe55f659..849fb5c6b5a 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -309,24 +309,31 @@ PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name) { PaintCurve *pc; - pc = BKE_libblock_alloc(bmain, ID_PC, name); + pc = BKE_libblock_alloc(bmain, ID_PC, name, 0); return pc; } -PaintCurve *BKE_paint_curve_copy(Main *bmain, const PaintCurve *pc) +/** + * Only copy internal data of PaintCurve ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_paint_curve_copy_data(Main *UNUSED(bmain), PaintCurve *pc_dst, const PaintCurve *pc_src, const int UNUSED(flag)) { - PaintCurve *pc_new; - - pc_new = BKE_libblock_copy(bmain, &pc->id); - - if (pc->tot_points != 0) { - pc_new->points = MEM_dupallocN(pc->points); + if (pc_src->tot_points != 0) { + pc_dst->points = MEM_dupallocN(pc_src->points); } +} - BKE_id_copy_ensure_local(bmain, &pc->id, &pc_new->id); - - return pc_new; +PaintCurve *BKE_paint_curve_copy(Main *bmain, const PaintCurve *pc) +{ + PaintCurve *pc_copy; + BKE_id_copy_ex(bmain, &pc->id, (ID **)&pc_copy, 0, false); + return pc_copy; } void BKE_paint_curve_make_local(Main *bmain, PaintCurve *pc, const bool lib_local) @@ -388,7 +395,7 @@ Palette *BKE_palette_add(Main *bmain, const char *name) { Palette *palette; - palette = BKE_libblock_alloc(bmain, ID_PAL, name); + palette = BKE_libblock_alloc(bmain, ID_PAL, name, 0); /* enable fake user by default */ id_fake_user_set(&palette->id); @@ -396,17 +403,24 @@ Palette *BKE_palette_add(Main *bmain, const char *name) return palette; } -Palette *BKE_palette_copy(Main *bmain, const Palette *palette) +/** + * Only copy internal data of Palette ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_palette_copy_data(Main *UNUSED(bmain), Palette *palette_dst, const Palette *palette_src, const int UNUSED(flag)) { - Palette *palette_new; - - palette_new = BKE_libblock_copy(bmain, &palette->id); - - BLI_duplicatelist(&palette_new->colors, &palette->colors); - - BKE_id_copy_ensure_local(bmain, &palette->id, &palette_new->id); + BLI_duplicatelist(&palette_dst->colors, &palette_src->colors); +} - return palette_new; +Palette *BKE_palette_copy(Main *bmain, const Palette *palette) +{ + Palette *palette_copy; + BKE_id_copy_ex(bmain, &palette->id, (ID **)&palette_copy, 0, false); + return palette_copy; } void BKE_palette_make_local(Main *bmain, Palette *palette, const bool lib_local) @@ -452,7 +466,7 @@ bool BKE_paint_select_vert_test(Object *ob) (ob->type == OB_MESH) && (ob->data != NULL) && (((Mesh *)ob->data)->editflag & ME_EDIT_PAINT_VERT_SEL) && - (ob->mode & OB_MODE_WEIGHT_PAINT) + (ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT) ); } @@ -537,12 +551,15 @@ void BKE_paint_free(Paint *paint) * still do a id_us_plus(), rather then if we were copying between 2 existing * scenes where a matching value should decrease the existing user count as * with paint_brush_set() */ -void BKE_paint_copy(Paint *src, Paint *tar) +void BKE_paint_copy(Paint *src, Paint *tar, const int flag) { tar->brush = src->brush; - id_us_plus((ID *)tar->brush); - id_us_plus((ID *)tar->palette); tar->cavity_curve = curvemapping_copy(src->cavity_curve); + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)tar->brush); + id_us_plus((ID *)tar->palette); + } } void BKE_paint_stroke_get_average(Scene *scene, Object *ob, float stroke[3]) @@ -656,6 +673,31 @@ void BKE_sculptsession_free_deformMats(SculptSession *ss) MEM_SAFE_FREE(ss->deform_imats); } +void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss) +{ + struct SculptVertexPaintGeomMap *gmap = NULL; + if (ss->mode_type == OB_MODE_VERTEX_PAINT) { + gmap = &ss->mode.vpaint.gmap; + + MEM_SAFE_FREE(ss->mode.vpaint.previous_color); + MEM_SAFE_FREE(ss->mode.vpaint.previous_accum); + } + else if (ss->mode_type == OB_MODE_WEIGHT_PAINT) { + gmap = &ss->mode.wpaint.gmap; + + MEM_SAFE_FREE(ss->mode.wpaint.alpha_weight); + MEM_SAFE_FREE(ss->mode.wpaint.previous_weight); + MEM_SAFE_FREE(ss->mode.wpaint.previous_accum); + } + else { + return; + } + MEM_SAFE_FREE(gmap->vert_to_loop); + MEM_SAFE_FREE(gmap->vert_map_mem); + MEM_SAFE_FREE(gmap->vert_to_poly); + MEM_SAFE_FREE(gmap->poly_map_mem); +} + /* Write out the sculpt dynamic-topology BMesh to the Mesh */ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder) { @@ -747,6 +789,8 @@ void BKE_sculptsession_free(Object *ob) if (ss->deform_imats) MEM_freeN(ss->deform_imats); + BKE_sculptsession_free_vwpaint_data(ob->sculpt); + MEM_freeN(ss); ob->sculpt = NULL; @@ -831,6 +875,8 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob); ss->show_diffuse_color = (sd->flags & SCULPT_SHOW_DIFFUSE) != 0; + ss->building_vp_handle = false; + if (need_mask) { if (mmd == NULL) { if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) { @@ -859,7 +905,8 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - if (mmd) { + /* VWPaint require mesh info for loop lookup, so require sculpt mode here */ + if (mmd && ob->mode & OB_MODE_SCULPT) { ss->multires = mmd; ss->totvert = dm->getNumVerts(dm); ss->totpoly = dm->getNumPolys(dm); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 416d63cfefb..8c94cdfe784 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3300,7 +3300,7 @@ ParticleSettings *psys_new_settings(const char *name, Main *main) if (main == NULL) main = G.main; - part = BKE_libblock_alloc(main, ID_PA, name); + part = BKE_libblock_alloc(main, ID_PA, name, 0); default_particle_settings(part); @@ -3331,38 +3331,45 @@ void BKE_particlesettings_rough_curve_init(ParticleSettings *part) part->roughcurve = cumap; } -ParticleSettings *BKE_particlesettings_copy(Main *bmain, const ParticleSettings *part) +/** + * Only copy internal data of ParticleSettings ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_particlesettings_copy_data( + Main *UNUSED(bmain), ParticleSettings *part_dst, const ParticleSettings *part_src, const int UNUSED(flag)) { - ParticleSettings *partn; - int a; + part_dst->pd = MEM_dupallocN(part_src->pd); + part_dst->pd2 = MEM_dupallocN(part_src->pd2); + part_dst->effector_weights = MEM_dupallocN(part_src->effector_weights); + part_dst->fluid = MEM_dupallocN(part_src->fluid); - partn = BKE_libblock_copy(bmain, &part->id); + if (part_src->clumpcurve) { + part_dst->clumpcurve = curvemapping_copy(part_src->clumpcurve); + } + if (part_src->roughcurve) { + part_dst->roughcurve = curvemapping_copy(part_src->roughcurve); + } - partn->pd = MEM_dupallocN(part->pd); - partn->pd2 = MEM_dupallocN(part->pd2); - partn->effector_weights = MEM_dupallocN(part->effector_weights); - partn->fluid = MEM_dupallocN(part->fluid); + part_dst->boids = boid_copy_settings(part_src->boids); - if (part->clumpcurve) - partn->clumpcurve = curvemapping_copy(part->clumpcurve); - if (part->roughcurve) - partn->roughcurve = curvemapping_copy(part->roughcurve); - - partn->boids = boid_copy_settings(part->boids); - - for (a = 0; a < MAX_MTEX; a++) { - if (part->mtex[a]) { - partn->mtex[a] = MEM_mallocN(sizeof(MTex), "psys_copy_tex"); - memcpy(partn->mtex[a], part->mtex[a], sizeof(MTex)); - id_us_plus((ID *)partn->mtex[a]->tex); + for (int a = 0; a < MAX_MTEX; a++) { + if (part_src->mtex[a]) { + part_dst->mtex[a] = MEM_dupallocN(part_src->mtex[a]); } } - BLI_duplicatelist(&partn->dupliweights, &part->dupliweights); - - BKE_id_copy_ensure_local(bmain, &part->id, &partn->id); + BLI_duplicatelist(&part_dst->dupliweights, &part_src->dupliweights); +} - return partn; +ParticleSettings *BKE_particlesettings_copy(Main *bmain, const ParticleSettings *part) +{ + ParticleSettings *part_copy; + BKE_id_copy_ex(bmain, &part->id, (ID **)&part_copy, 0, false); + return part_copy; } void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const bool lib_local) diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 4f758bde7f9..9a7980827ad 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -39,6 +39,7 @@ #include "BLI_jitter.h" #include "BLI_kdtree.h" #include "BLI_math.h" +#include "BLI_math_geom.h" #include "BLI_rand.h" #include "BLI_sort.h" #include "BLI_task.h" @@ -213,14 +214,22 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) copy_v3_v3(co2, co1); co2[a] += delta[a] + 0.001f*d; co1[a] -= 0.001f*d; - + + struct IsectRayPrecalc isect_precalc; + float ray_direction[3]; + sub_v3_v3v3(ray_direction, co2, co1); + isect_ray_tri_watertight_v3_precalc(&isect_precalc, ray_direction); + /* lets intersect the faces */ for (i=0; i<totface; i++,mface++) { copy_v3_v3(v1, mvert[mface->v1].co); copy_v3_v3(v2, mvert[mface->v2].co); copy_v3_v3(v3, mvert[mface->v3].co); - bool intersects_tri = isect_axial_line_segment_tri_v3(a, co1, co2, v2, v3, v1, &lambda); + bool intersects_tri = isect_ray_tri_watertight_v3(co1, + &isect_precalc, + v1, v2, v3, + &lambda, NULL); if (intersects_tri) { if (from==PART_FROM_FACE) (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST; @@ -231,7 +240,10 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) if (mface->v4 && (!intersects_tri || from==PART_FROM_VOLUME)) { copy_v3_v3(v4, mvert[mface->v4].co); - if (isect_axial_line_segment_tri_v3(a, co1, co2, v4, v1, v3, &lambda)) { + if (isect_ray_tri_watertight_v3(co1, + &isect_precalc, + v1, v3, v4, + &lambda, NULL)) { if (from==PART_FROM_FACE) (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST; else @@ -429,7 +441,6 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i ParticleThreadContext *ctx= thread->ctx; MFace *mface; - DM_ensure_tessface(ctx->dm); mface = ctx->dm->getTessFaceDataArray(ctx->dm, CD_MFACE); int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */ @@ -899,10 +910,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti else dm= CDDM_from_mesh((Mesh*)ob->data); - /* BMESH ONLY, for verts we don't care about tessfaces */ - if (from != PART_FROM_VERT) { - DM_ensure_tessface(dm); - } + DM_ensure_tessface(dm); /* we need orco for consistent distributions */ if (!CustomData_has_layer(&dm->vertData, CD_ORCO)) @@ -1096,13 +1104,10 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti /* This is to address tricky issues with vertex-emitting when user tries (and expects) exact 1-1 vert/part * distribution (see T47983 and its two example files). It allows us to consider pos as * 'midpoint between v and v+1' (or 'p and p+1', depending whether we have more vertices than particles or not), - * and avoid stumbling over float imprecisions in element_sum. */ - if (from == PART_FROM_VERT) { - pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5; /* We choose the smaller step. */ - } - else { - pos = 0.0; - } + * and avoid stumbling over float imprecisions in element_sum. + * Note: moved face and volume distribution to this as well (instead of starting at zero), + * for the same reasons, see T52682. */ + pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5; /* We choose the smaller step. */ for (i = 0, p = 0; p < totpart; p++, pos += step) { for ( ; (i < totmapped - 1) && (pos > (double)element_sum[i]); i++); @@ -1141,7 +1146,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti if (jitlevel == 0) { jitlevel= totpart/totelem; - if (part->flag & PART_EDISTR) jitlevel*= 2; /* looks better in general, not very scietific */ + if (part->flag & PART_EDISTR) jitlevel*= 2; /* looks better in general, not very scientific */ if (jitlevel<3) jitlevel= 3; } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 3f9a92a5577..38eb861599a 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2319,21 +2319,21 @@ static void collision_point_on_surface(float p[3], ParticleCollisionElement *pce } case 3: { - float p0[3], e1[3], e2[3], nor[3]; + float p0[3], e1[3], e2[3], nor[3]; - sub_v3_v3v3(e1, pce->x1, pce->x0); - sub_v3_v3v3(e2, pce->x2, pce->x0); - sub_v3_v3v3(p0, p, pce->x0); + sub_v3_v3v3(e1, pce->x1, pce->x0); + sub_v3_v3v3(e2, pce->x2, pce->x0); + sub_v3_v3v3(p0, p, pce->x0); - cross_v3_v3v3(nor, e1, e2); - normalize_v3(nor); + cross_v3_v3v3(nor, e1, e2); + normalize_v3(nor); - if (pce->inv_nor == 1) - negate_v3(nor); + if (pce->inv_nor == 1) + negate_v3(nor); - madd_v3_v3v3fl(co, pce->x0, nor, col->radius); - madd_v3_v3fl(co, e1, pce->uv[0]); - madd_v3_v3fl(co, e2, pce->uv[1]); + madd_v3_v3v3fl(co, pce->x0, nor, col->radius); + madd_v3_v3fl(co, e1, pce->uv[0]); + madd_v3_v3fl(co, e2, pce->uv[1]); break; } } @@ -3042,10 +3042,12 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int /* calculate maximum segment length */ max_length = 0.0f; LOOP_PARTICLES { - for (k=1, key=pa->hair+1; k<pa->totkey; k++,key++) { - float length = len_v3v3(key->co, (key-1)->co); - if (max_length < length) - max_length = length; + if (!(pa->flag & PARS_UNEXIST)) { + for (k=1, key=pa->hair+1; k<pa->totkey; k++,key++) { + float length = len_v3v3(key->co, (key-1)->co); + if (max_length < length) + max_length = length; + } } } @@ -3057,76 +3059,78 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int /* make vgroup for pin roots etc.. */ hair_index = 1; LOOP_PARTICLES { - float root_mat[4][4]; - float bending_stiffness; - bool use_hair; - - pa->hair_index = hair_index; - use_hair = psys_hair_use_simulation(pa, max_length); - - psys_mat_hair_to_object(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat); - mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat); - normalize_m4(root_mat); - - bending_stiffness = CLAMPIS(1.0f - part->bending_random * psys_frand(psys, p + 666), 0.0f, 1.0f); - - for (k=0, key=pa->hair; k<pa->totkey; k++,key++) { - ClothHairData *hair; - float *co, *co_next; - - co = key->co; - co_next = (key+1)->co; - - /* create fake root before actual root to resist bending */ - if (k==0) { - hair = &psys->clmd->hairdata[pa->hair_index - 1]; + if (!(pa->flag & PARS_UNEXIST)) { + float root_mat[4][4]; + float bending_stiffness; + bool use_hair; + + pa->hair_index = hair_index; + use_hair = psys_hair_use_simulation(pa, max_length); + + psys_mat_hair_to_object(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat); + mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat); + normalize_m4(root_mat); + + bending_stiffness = CLAMPIS(1.0f - part->bending_random * psys_frand(psys, p + 666), 0.0f, 1.0f); + + for (k=0, key=pa->hair; k<pa->totkey; k++,key++) { + ClothHairData *hair; + float *co, *co_next; + + co = key->co; + co_next = (key+1)->co; + + /* create fake root before actual root to resist bending */ + if (k==0) { + hair = &psys->clmd->hairdata[pa->hair_index - 1]; + copy_v3_v3(hair->loc, root_mat[3]); + copy_m3_m4(hair->rot, root_mat); + + hair->radius = hair_radius; + hair->bending_stiffness = bending_stiffness; + + add_v3_v3v3(mvert->co, co, co); + sub_v3_v3(mvert->co, co_next); + mul_m4_v3(hairmat, mvert->co); + + medge->v1 = pa->hair_index - 1; + medge->v2 = pa->hair_index; + + dvert = hair_set_pinning(dvert, 1.0f); + + mvert++; + medge++; + } + + /* store root transform in cloth data */ + hair = &psys->clmd->hairdata[pa->hair_index + k]; copy_v3_v3(hair->loc, root_mat[3]); copy_m3_m4(hair->rot, root_mat); - + hair->radius = hair_radius; hair->bending_stiffness = bending_stiffness; - - add_v3_v3v3(mvert->co, co, co); - sub_v3_v3(mvert->co, co_next); + + copy_v3_v3(mvert->co, co); mul_m4_v3(hairmat, mvert->co); - - medge->v1 = pa->hair_index - 1; - medge->v2 = pa->hair_index; - - dvert = hair_set_pinning(dvert, 1.0f); - + + if (k) { + medge->v1 = pa->hair_index + k - 1; + medge->v2 = pa->hair_index + k; + } + + /* roots and disabled hairs should be 1.0, the rest can be anything from 0.0 to 1.0 */ + if (use_hair) + dvert = hair_set_pinning(dvert, key->weight); + else + dvert = hair_set_pinning(dvert, 1.0f); + mvert++; - medge++; + if (k) + medge++; } - - /* store root transform in cloth data */ - hair = &psys->clmd->hairdata[pa->hair_index + k]; - copy_v3_v3(hair->loc, root_mat[3]); - copy_m3_m4(hair->rot, root_mat); - - hair->radius = hair_radius; - hair->bending_stiffness = bending_stiffness; - - copy_v3_v3(mvert->co, co); - mul_m4_v3(hairmat, mvert->co); - - if (k) { - medge->v1 = pa->hair_index + k - 1; - medge->v2 = pa->hair_index + k; - } - - /* roots and disabled hairs should be 1.0, the rest can be anything from 0.0 to 1.0 */ - if (use_hair) - dvert = hair_set_pinning(dvert, key->weight); - else - dvert = hair_set_pinning(dvert, 1.0f); - - mvert++; - if (k) - medge++; + + hair_index += pa->totkey + 1; } - - hair_index += pa->totkey + 1; } } @@ -3152,9 +3156,11 @@ static void do_hair_dynamics(ParticleSimulationData *sim) totpoint = 0; totedge = 0; LOOP_PARTICLES { - /* "out" dm contains all hairs */ - totedge += pa->totkey; - totpoint += pa->totkey + 1; /* +1 for virtual root point */ + if (!(pa->flag & PARS_UNEXIST)) { + /* "out" dm contains all hairs */ + totedge += pa->totkey; + totpoint += pa->totkey + 1; /* +1 for virtual root point */ + } } realloc_roots = false; /* whether hair root info array has to be reallocated */ @@ -4350,13 +4356,12 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, /* **** Depsgraph evaluation **** */ -void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx), - Scene *scene, - Object *ob, - ParticleSystem *psys) +void BKE_particle_system_eval_init(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob) { if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s on %s:%s\n", __func__, ob->id.name, psys->name); + printf("%s on %s\n", __func__, ob->id.name); } BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH); } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 53dfffe2b97..4b154d3301c 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -34,6 +34,7 @@ #include "BKE_pbvh.h" #include "BKE_ccg.h" +#include "BKE_subsurf.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_mesh.h" /* for BKE_mesh_calc_normals */ @@ -606,6 +607,10 @@ void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, MEM_freeN(prim_bbc); } +void BKE_pbvh_set_ccgdm(PBVH *bvh, CCGDerivedMesh *ccgdm) { + bvh->ccgdm = ccgdm; +} + PBVH *BKE_pbvh_new(void) { PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh"); @@ -1156,7 +1161,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) } } -static void pbvh_draw_BB(PBVH *bvh) +void BKE_pbvh_draw_BB(PBVH *bvh) { GPU_pbvh_BB_draw_init(); @@ -1329,6 +1334,11 @@ void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key) *key = bvh->gridkey; } +CCGDerivedMesh *BKE_pbvh_get_ccgdm(const PBVH *bvh) { + return bvh->ccgdm; +} + + BMesh *BKE_pbvh_get_bmesh(PBVH *bvh) { BLI_assert(bvh->type == PBVH_BMESH); @@ -1860,7 +1870,7 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3], } if (G.debug_value == 14) - pbvh_draw_BB(bvh); + BKE_pbvh_draw_BB(bvh); } void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces, diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 19d3b31bd31..01057318568 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -149,6 +149,8 @@ struct PBVH { * objects in sculpt mode with different sizes at the same time, so now storing that common gpu buffer * in an opaque pointer per pbvh. See T47637. */ struct GridCommonGPUBuffer *grid_common_gpu_buffer; + /* The ccgdm is required for CD_ORIGINDEX lookup in vertex paint + multires */ + struct CCGDerivedMesh *ccgdm; /* Only used during BVH build and update, * don't need to remain valid after */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index a7e00a8103a..7a1b378b3c4 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -3449,7 +3449,7 @@ void BKE_ptcache_free_list(ListBase *ptcaches) } } -static PointCache *ptcache_copy(PointCache *cache, bool copy_data) +static PointCache *ptcache_copy(PointCache *cache, const bool copy_data) { PointCache *ncache; @@ -3492,14 +3492,15 @@ static PointCache *ptcache_copy(PointCache *cache, bool copy_data) } /* returns first point cache */ -PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, bool copy_data) +PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, const int flag) { PointCache *cache = ptcaches_old->first; BLI_listbase_clear(ptcaches_new); - for (; cache; cache=cache->next) - BLI_addtail(ptcaches_new, ptcache_copy(cache, copy_data)); + for (; cache; cache=cache->next) { + BLI_addtail(ptcaches_new, ptcache_copy(cache, (flag & LIB_ID_COPY_CACHES) != 0)); + } return ptcaches_new->first; } @@ -3618,7 +3619,13 @@ void BKE_ptcache_bake(PTCacheBaker *baker) psys_get_pointcache_start_end(scene, pid->calldata, &cache->startframe, &cache->endframe); } - if (((cache->flag & PTCACHE_BAKED) == 0) && (render || bake)) { + // XXX workaround for regression inroduced in ee3fadd, needs looking into + if (pid->type == PTCACHE_TYPE_RIGIDBODY) { + if ((cache->flag & PTCACHE_REDO_NEEDED || (cache->flag & PTCACHE_SIMULATION_VALID)==0) && (render || bake)) { + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + } + } + else if (((cache->flag & PTCACHE_BAKED) == 0) && (render || bake)) { BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); } diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index e8c0cf53d0b..03eb83376e7 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -184,7 +184,7 @@ void BKE_rigidbody_free_constraint(Object *ob) * be added to relevant groups later... */ -RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob) +RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int UNUSED(flag)) { RigidBodyOb *rboN = NULL; @@ -204,7 +204,7 @@ RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob) return rboN; } -RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob) +RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(flag)) { RigidBodyCon *rbcN = NULL; @@ -291,8 +291,6 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob) if (dm == NULL) return NULL; - DM_ensure_looptri(dm); - mvert = dm->getVertArray(dm); totvert = dm->getNumVerts(dm); looptri = dm->getLoopTriArray(dm); @@ -524,8 +522,6 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) if (dm == NULL) return; - DM_ensure_looptri(dm); - mvert = dm->getVertArray(dm); totvert = dm->getNumVerts(dm); lt = dm->getLoopTriArray(dm); @@ -609,8 +605,6 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) if (dm == NULL) return; - DM_ensure_looptri(dm); - mvert = dm->getVertArray(dm); totvert = dm->getNumVerts(dm); looptri = dm->getLoopTriArray(dm); @@ -945,24 +939,26 @@ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) return rbw; } -RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw) +RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag) { - RigidBodyWorld *rbwn = MEM_dupallocN(rbw); + RigidBodyWorld *rbw_copy = MEM_dupallocN(rbw); - if (rbw->effector_weights) - rbwn->effector_weights = MEM_dupallocN(rbw->effector_weights); - if (rbwn->group) - id_us_plus(&rbwn->group->id); - if (rbwn->constraints) - id_us_plus(&rbwn->constraints->id); + if (rbw->effector_weights) { + rbw_copy->effector_weights = MEM_dupallocN(rbw->effector_weights); + } + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)rbw_copy->group); + id_us_plus((ID *)rbw_copy->constraints); + } - rbwn->pointcache = BKE_ptcache_copy_list(&rbwn->ptcaches, &rbw->ptcaches, false); + /* XXX Never copy caches here? */ + rbw_copy->pointcache = BKE_ptcache_copy_list(&rbw_copy->ptcaches, &rbw->ptcaches, flag & ~LIB_ID_COPY_CACHES); - rbwn->objects = NULL; - rbwn->physics_world = NULL; - rbwn->numbodies = 0; + rbw_copy->objects = NULL; + rbw_copy->physics_world = NULL; + rbw_copy->numbodies = 0; - return rbwn; + return rbw_copy; } void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw) @@ -1600,8 +1596,12 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL); cache = rbw->pointcache; + if (ctime <= startframe) { + rbw->ltime = startframe; + return; + } /* make sure we don't go out of cache frame range */ - if (ctime > endframe) { + else if (ctime > endframe) { ctime = endframe; } @@ -1615,12 +1615,9 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) // RB_TODO deal with interpolated, old and baked results bool can_simulate = (ctime == rbw->ltime + 1) && !(cache->flag & PTCACHE_BAKED); - if (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0) { - rbw->ltime = cache->startframe; - } - - if (BKE_ptcache_read(&pid, ctime, can_simulate)) { + if (BKE_ptcache_read(&pid, ctime, can_simulate) == PTCACHE_READ_EXACT) { BKE_ptcache_validate(cache, (int)ctime); + rbw->ltime = ctime; return; } @@ -1658,13 +1655,13 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) # pragma GCC diagnostic ignored "-Wunused-parameter" #endif -struct RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob) { return NULL; } -struct RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob) { return NULL; } +struct RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag) { return NULL; } +struct RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int flag) { return NULL; } void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild) {} void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) { if (r_vol) *r_vol = 0.0f; } void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) { zero_v3(r_center); } struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) { return NULL; } -struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw) { return NULL; } +struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag) { return NULL; } void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw) {} void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata) {} struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { return NULL; } diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index 19d646daf9f..fb81ed4d47f 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -72,7 +72,7 @@ void free_sensors(ListBase *lb) } } -bSensor *copy_sensor(bSensor *sens) +bSensor *copy_sensor(bSensor *sens, const int UNUSED(flag)) { bSensor *sensn; @@ -87,14 +87,14 @@ bSensor *copy_sensor(bSensor *sens) return sensn; } -void copy_sensors(ListBase *lbn, const ListBase *lbo) +void copy_sensors(ListBase *lbn, const ListBase *lbo, const int flag) { bSensor *sens, *sensn; lbn->first= lbn->last= NULL; sens= lbo->first; while (sens) { - sensn= copy_sensor(sens); + sensn= copy_sensor(sens, flag); BLI_addtail(lbn, sensn); sens= sens->next; } @@ -234,7 +234,7 @@ void free_controllers(ListBase *lb) } } -bController *copy_controller(bController *cont) +bController *copy_controller(bController *cont, const int UNUSED(flag)) { bController *contn; @@ -251,14 +251,14 @@ bController *copy_controller(bController *cont) return contn; } -void copy_controllers(ListBase *lbn, const ListBase *lbo) +void copy_controllers(ListBase *lbn, const ListBase *lbo, const int flag) { bController *cont, *contn; lbn->first= lbn->last= NULL; cont= lbo->first; while (cont) { - contn= copy_controller(cont); + contn= copy_controller(cont, flag); BLI_addtail(lbn, contn); cont= cont->next; } @@ -359,7 +359,7 @@ void free_actuators(ListBase *lb) } } -bActuator *copy_actuator(bActuator *act) +bActuator *copy_actuator(bActuator *act, const int flag) { bActuator *actn; @@ -374,29 +374,31 @@ bActuator *copy_actuator(bActuator *act) case ACT_SHAPEACTION: { bActionActuator *aa = (bActionActuator *)act->data; - if (aa->act) + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { id_us_plus((ID *)aa->act); + } break; } case ACT_SOUND: { bSoundActuator *sa = (bSoundActuator *)act->data; - if (sa->sound) + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { id_us_plus((ID *)sa->sound); + } break; } } return actn; } -void copy_actuators(ListBase *lbn, const ListBase *lbo) +void copy_actuators(ListBase *lbn, const ListBase *lbo, const int flag) { bActuator *act, *actn; lbn->first= lbn->last= NULL; act= lbo->first; while (act) { - actn= copy_actuator(act); + actn= copy_actuator(act, flag); BLI_addtail(lbn, actn); act= act->next; } @@ -783,11 +785,11 @@ void BKE_sca_logic_links_remap(Main *bmain, Object *ob_old, Object *ob_new) * Handle the copying of logic data into a new object, including internal logic links update. * External links (links between logic bricks of different objects) must be handled separately. */ -void BKE_sca_logic_copy(Object *ob_new, const Object *ob) +void BKE_sca_logic_copy(Object *ob_new, const Object *ob, const int flag) { - copy_sensors(&ob_new->sensors, &ob->sensors); - copy_controllers(&ob_new->controllers, &ob->controllers); - copy_actuators(&ob_new->actuators, &ob->actuators); + copy_sensors(&ob_new->sensors, &ob->sensors, flag); + copy_controllers(&ob_new->controllers, &ob->controllers, flag); + copy_actuators(&ob_new->actuators, &ob->actuators, flag); for (bSensor *sens = ob_new->sensors.first; sens; sens = sens->next) { if (sens->flag & SENS_NEW) { diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index a15f270a3ee..c0dcac33656 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -125,17 +125,6 @@ void free_avicodecdata(AviCodecData *acd) } } -void free_qtcodecdata(QuicktimeCodecData *qcd) -{ - if (qcd) { - if (qcd->cdParms) { - MEM_freeN(qcd->cdParms); - qcd->cdParms = NULL; - qcd->cdSize = 0; - } - } -} - static void remove_sequencer_fcurves(Scene *sce) { AnimData *adt = BKE_animdata_from_id(&sce->id); @@ -154,223 +143,292 @@ static void remove_sequencer_fcurves(Scene *sce) } } -Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) -{ - Scene *scen; - SceneRenderLayer *srl, *new_srl; - FreestyleLineSet *lineset; - ToolSettings *ts; - Base *base, *obase; - - if (type == SCE_COPY_EMPTY) { - ListBase rl, rv; - scen = BKE_scene_add(bmain, sce->id.name + 2); - - rl = scen->r.layers; - rv = scen->r.views; - curvemapping_free_data(&scen->r.mblur_shutter_curve); - scen->r = sce->r; - scen->r.layers = rl; - scen->r.actlay = 0; - scen->r.views = rv; - scen->unit = sce->unit; - scen->physics_settings = sce->physics_settings; - scen->gm = sce->gm; - scen->audio = sce->audio; - - if (sce->id.properties) - scen->id.properties = IDP_CopyProperty(sce->id.properties); - - MEM_freeN(scen->toolsettings); - BKE_sound_destroy_scene(scen); - } - else { - scen = BKE_libblock_copy(bmain, &sce->id); - BLI_duplicatelist(&(scen->base), &(sce->base)); - - if (type != SCE_COPY_FULL) { - id_us_plus((ID *)scen->world); - } - id_us_plus((ID *)scen->set); - /* id_us_plus((ID *)scen->gm.dome.warptext); */ /* XXX Not refcounted? see readfile.c */ - - scen->ed = NULL; - scen->theDag = NULL; - scen->depsgraph = NULL; - scen->obedit = NULL; - scen->stats = NULL; - scen->fps_info = NULL; - - if (sce->rigidbody_world) - scen->rigidbody_world = BKE_rigidbody_world_copy(sce->rigidbody_world); - - BLI_duplicatelist(&(scen->markers), &(sce->markers)); - BLI_duplicatelist(&(scen->transform_spaces), &(sce->transform_spaces)); - BLI_duplicatelist(&(scen->r.layers), &(sce->r.layers)); - BLI_duplicatelist(&(scen->r.views), &(sce->r.views)); - BKE_keyingsets_copy(&(scen->keyingsets), &(sce->keyingsets)); - - if (sce->nodetree) { - /* ID's are managed on both copy and switch */ - scen->nodetree = ntreeCopyTree(bmain, sce->nodetree); - BKE_libblock_relink_ex(bmain, scen->nodetree, &sce->id, &scen->id, false); +/** + * Only copy internal data of Scene ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, const int flag) +{ + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; + + sce_dst->ed = NULL; + sce_dst->theDag = NULL; + sce_dst->depsgraph = NULL; + sce_dst->obedit = NULL; + sce_dst->stats = NULL; + sce_dst->fps_info = NULL; + + BLI_duplicatelist(&(sce_dst->base), &(sce_src->base)); + for (Base *base_dst = sce_dst->base.first, *base_src = sce_src->base.first; + base_dst; + base_dst = base_dst->next, base_src = base_src->next) + { + if (base_src == sce_src->basact) { + sce_dst->basact = base_dst; } + } - obase = sce->base.first; - base = scen->base.first; - while (base) { - id_us_plus(&base->object->id); - if (obase == sce->basact) scen->basact = base; - - obase = obase->next; - base = base->next; - } + BLI_duplicatelist(&(sce_dst->markers), &(sce_src->markers)); + BLI_duplicatelist(&(sce_dst->transform_spaces), &(sce_src->transform_spaces)); + BLI_duplicatelist(&(sce_dst->r.layers), &(sce_src->r.layers)); + BLI_duplicatelist(&(sce_dst->r.views), &(sce_src->r.views)); + BKE_keyingsets_copy(&(sce_dst->keyingsets), &(sce_src->keyingsets)); - /* copy action and remove animation used by sequencer */ - BKE_animdata_copy_id_action(&scen->id, false); + if (sce_src->nodetree) { + BKE_id_copy_ex(bmain, (ID *)sce_src->nodetree, (ID **)&sce_dst->nodetree, flag, false); + BKE_libblock_relink_ex(bmain, sce_dst->nodetree, (void *)(&sce_src->id), &sce_dst->id, false); + } - if (type != SCE_COPY_FULL) - remove_sequencer_fcurves(scen); + if (sce_src->rigidbody_world) { + sce_dst->rigidbody_world = BKE_rigidbody_world_copy(sce_src->rigidbody_world, flag_subdata); + } - /* copy Freestyle settings */ - new_srl = scen->r.layers.first; - for (srl = sce->r.layers.first; srl; srl = srl->next) { - if (new_srl->prop != NULL) { - new_srl->prop = IDP_CopyProperty(new_srl->prop); - } - BKE_freestyle_config_copy(&new_srl->freestyleConfig, &srl->freestyleConfig); - if (type == SCE_COPY_FULL) { - for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { - if (lineset->linestyle) { - /* Has been incremented by BKE_freestyle_config_copy(). */ - id_us_min(&lineset->linestyle->id); - lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle); - } - } - } - new_srl = new_srl->next; + /* copy Freestyle settings */ + for (SceneRenderLayer *srl_dst = sce_dst->r.layers.first, *srl_src = sce_src->r.layers.first; + srl_src; + srl_dst = srl_dst->next, srl_src = srl_src->next) + { + if (srl_dst->prop != NULL) { + srl_dst->prop = IDP_CopyProperty_ex(srl_dst->prop, flag_subdata); } + BKE_freestyle_config_copy(&srl_dst->freestyleConfig, &srl_src->freestyleConfig, flag_subdata); } /* copy color management settings */ - BKE_color_managed_display_settings_copy(&scen->display_settings, &sce->display_settings); - BKE_color_managed_view_settings_copy(&scen->view_settings, &sce->view_settings); - BKE_color_managed_colorspace_settings_copy(&scen->sequencer_colorspace_settings, &sce->sequencer_colorspace_settings); + BKE_color_managed_display_settings_copy(&sce_dst->display_settings, &sce_src->display_settings); + BKE_color_managed_view_settings_copy(&sce_dst->view_settings, &sce_src->view_settings); + BKE_color_managed_colorspace_settings_copy(&sce_dst->sequencer_colorspace_settings, &sce_src->sequencer_colorspace_settings); - BKE_color_managed_display_settings_copy(&scen->r.im_format.display_settings, &sce->r.im_format.display_settings); - BKE_color_managed_view_settings_copy(&scen->r.im_format.view_settings, &sce->r.im_format.view_settings); + BKE_color_managed_display_settings_copy(&sce_dst->r.im_format.display_settings, &sce_src->r.im_format.display_settings); + BKE_color_managed_view_settings_copy(&sce_dst->r.im_format.view_settings, &sce_src->r.im_format.view_settings); - BKE_color_managed_display_settings_copy(&scen->r.bake.im_format.display_settings, &sce->r.bake.im_format.display_settings); - BKE_color_managed_view_settings_copy(&scen->r.bake.im_format.view_settings, &sce->r.bake.im_format.view_settings); + BKE_color_managed_display_settings_copy(&sce_dst->r.bake.im_format.display_settings, &sce_src->r.bake.im_format.display_settings); + BKE_color_managed_view_settings_copy(&sce_dst->r.bake.im_format.view_settings, &sce_src->r.bake.im_format.view_settings); - curvemapping_copy_data(&scen->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve); + curvemapping_copy_data(&sce_dst->r.mblur_shutter_curve, &sce_src->r.mblur_shutter_curve); /* tool settings */ - scen->toolsettings = MEM_dupallocN(sce->toolsettings); - - ts = scen->toolsettings; - if (ts) { + if (sce_dst->toolsettings != NULL) { + ToolSettings *ts = sce_dst->toolsettings = MEM_dupallocN(sce_dst->toolsettings); if (ts->vpaint) { ts->vpaint = MEM_dupallocN(ts->vpaint); - ts->vpaint->paintcursor = NULL; - ts->vpaint->vpaint_prev = NULL; - ts->vpaint->wpaint_prev = NULL; - BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint); + BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag_subdata); } if (ts->wpaint) { ts->wpaint = MEM_dupallocN(ts->wpaint); - ts->wpaint->paintcursor = NULL; - ts->wpaint->vpaint_prev = NULL; - ts->wpaint->wpaint_prev = NULL; - BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint); + BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag_subdata); } if (ts->sculpt) { ts->sculpt = MEM_dupallocN(ts->sculpt); - BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint); + BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag_subdata); } if (ts->uvsculpt) { ts->uvsculpt = MEM_dupallocN(ts->uvsculpt); - BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint); + BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag_subdata); } - BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint); + BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag_subdata); ts->imapaint.paintcursor = NULL; - id_us_plus((ID *)ts->imapaint.stencil); - id_us_plus((ID *)ts->imapaint.clone); - id_us_plus((ID *)ts->imapaint.canvas); ts->particle.paintcursor = NULL; ts->particle.scene = NULL; ts->particle.object = NULL; - + /* duplicate Grease Pencil Drawing Brushes */ BLI_listbase_clear(&ts->gp_brushes); - for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) { + for (bGPDbrush *brush = sce_src->toolsettings->gp_brushes.first; brush; brush = brush->next) { bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush); BLI_addtail(&ts->gp_brushes, newbrush); } - + /* duplicate Grease Pencil interpolation curve */ ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo); } - + /* make a private copy of the avicodecdata */ - if (sce->r.avicodecdata) { - scen->r.avicodecdata = MEM_dupallocN(sce->r.avicodecdata); - scen->r.avicodecdata->lpFormat = MEM_dupallocN(scen->r.avicodecdata->lpFormat); - scen->r.avicodecdata->lpParms = MEM_dupallocN(scen->r.avicodecdata->lpParms); - } - - /* make a private copy of the qtcodecdata */ - if (sce->r.qtcodecdata) { - scen->r.qtcodecdata = MEM_dupallocN(sce->r.qtcodecdata); - scen->r.qtcodecdata->cdParms = MEM_dupallocN(scen->r.qtcodecdata->cdParms); + if (sce_src->r.avicodecdata) { + sce_dst->r.avicodecdata = MEM_dupallocN(sce_src->r.avicodecdata); + sce_dst->r.avicodecdata->lpFormat = MEM_dupallocN(sce_dst->r.avicodecdata->lpFormat); + sce_dst->r.avicodecdata->lpParms = MEM_dupallocN(sce_dst->r.avicodecdata->lpParms); } - - if (sce->r.ffcodecdata.properties) { /* intentionally check scen not sce. */ - scen->r.ffcodecdata.properties = IDP_CopyProperty(sce->r.ffcodecdata.properties); + + if (sce_src->r.ffcodecdata.properties) { /* intentionally check sce_dst not sce_src. */ /* XXX ??? comment outdated... */ + sce_dst->r.ffcodecdata.properties = IDP_CopyProperty_ex(sce_src->r.ffcodecdata.properties, flag_subdata); } - /* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations - * are done outside of blenkernel with ED_objects_single_users! */ + /* before scene copy */ + BKE_sound_create_scene(sce_dst); - /* camera */ - if (type == SCE_COPY_LINK_DATA || type == SCE_COPY_FULL) { - ID_NEW_REMAP(scen->camera); + /* Copy sequencer, this is local data! */ + if (sce_src->ed) { + sce_dst->ed = MEM_callocN(sizeof(*sce_dst->ed), __func__); + sce_dst->ed->seqbasep = &sce_dst->ed->seqbase; + BKE_sequence_base_dupli_recursive( + sce_src, sce_dst, &sce_dst->ed->seqbase, &sce_src->ed->seqbase, SEQ_DUPE_ALL, flag_subdata); } - - /* before scene copy */ - BKE_sound_create_scene(scen); - /* world */ - if (type == SCE_COPY_FULL) { - if (scen->world) { - scen->world = BKE_world_copy(bmain, scen->world); - BKE_animdata_copy_id_action((ID *)scen->world, false); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&sce_dst->id, &sce_src->id); + } + else { + sce_dst->preview = NULL; + } +} + +Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) +{ + Scene *sce_copy; + + /* TODO this should/could most likely be replaced by call to more generic code at some point... + * But for now, let's keep it well isolated here. */ + if (type == SCE_COPY_EMPTY) { + ToolSettings *ts; + ListBase rl, rv; + + sce_copy = BKE_scene_add(bmain, sce->id.name + 2); + + rl = sce_copy->r.layers; + rv = sce_copy->r.views; + curvemapping_free_data(&sce_copy->r.mblur_shutter_curve); + sce_copy->r = sce->r; + sce_copy->r.layers = rl; + sce_copy->r.actlay = 0; + sce_copy->r.views = rv; + sce_copy->unit = sce->unit; + sce_copy->physics_settings = sce->physics_settings; + sce_copy->gm = sce->gm; + sce_copy->audio = sce->audio; + + if (sce->id.properties) + sce_copy->id.properties = IDP_CopyProperty(sce->id.properties); + + MEM_freeN(sce_copy->toolsettings); + BKE_sound_destroy_scene(sce_copy); + + /* copy color management settings */ + BKE_color_managed_display_settings_copy(&sce_copy->display_settings, &sce->display_settings); + BKE_color_managed_view_settings_copy(&sce_copy->view_settings, &sce->view_settings); + BKE_color_managed_colorspace_settings_copy(&sce_copy->sequencer_colorspace_settings, &sce->sequencer_colorspace_settings); + + BKE_color_managed_display_settings_copy(&sce_copy->r.im_format.display_settings, &sce->r.im_format.display_settings); + BKE_color_managed_view_settings_copy(&sce_copy->r.im_format.view_settings, &sce->r.im_format.view_settings); + + BKE_color_managed_display_settings_copy(&sce_copy->r.bake.im_format.display_settings, &sce->r.bake.im_format.display_settings); + BKE_color_managed_view_settings_copy(&sce_copy->r.bake.im_format.view_settings, &sce->r.bake.im_format.view_settings); + + curvemapping_copy_data(&sce_copy->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve); + + /* tool settings */ + sce_copy->toolsettings = MEM_dupallocN(sce->toolsettings); + + ts = sce_copy->toolsettings; + if (ts) { + if (ts->vpaint) { + ts->vpaint = MEM_dupallocN(ts->vpaint); + BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, 0); + } + if (ts->wpaint) { + ts->wpaint = MEM_dupallocN(ts->wpaint); + BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, 0); + } + if (ts->sculpt) { + ts->sculpt = MEM_dupallocN(ts->sculpt); + BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, 0); + } + if (ts->uvsculpt) { + ts->uvsculpt = MEM_dupallocN(ts->uvsculpt); + BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, 0); + } + + BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, 0); + ts->imapaint.paintcursor = NULL; + id_us_plus((ID *)ts->imapaint.stencil); + id_us_plus((ID *)ts->imapaint.clone); + id_us_plus((ID *)ts->imapaint.canvas); + ts->particle.paintcursor = NULL; + ts->particle.scene = NULL; + ts->particle.object = NULL; + + /* duplicate Grease Pencil Drawing Brushes */ + BLI_listbase_clear(&ts->gp_brushes); + for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) { + bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush); + BLI_addtail(&ts->gp_brushes, newbrush); + } + + /* duplicate Grease Pencil interpolation curve */ + ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo); + } + + /* make a private copy of the avicodecdata */ + if (sce->r.avicodecdata) { + sce_copy->r.avicodecdata = MEM_dupallocN(sce->r.avicodecdata); + sce_copy->r.avicodecdata->lpFormat = MEM_dupallocN(sce_copy->r.avicodecdata->lpFormat); + sce_copy->r.avicodecdata->lpParms = MEM_dupallocN(sce_copy->r.avicodecdata->lpParms); } - if (sce->ed) { - scen->ed = MEM_callocN(sizeof(Editing), "addseq"); - scen->ed->seqbasep = &scen->ed->seqbase; - BKE_sequence_base_dupli_recursive(sce, scen, &scen->ed->seqbase, &sce->ed->seqbase, SEQ_DUPE_ALL); + if (sce->r.ffcodecdata.properties) { /* intentionally check scen not sce. */ + sce_copy->r.ffcodecdata.properties = IDP_CopyProperty(sce->r.ffcodecdata.properties); } + + /* before scene copy */ + BKE_sound_create_scene(sce_copy); + + /* grease pencil */ + sce_copy->gpd = NULL; + + sce_copy->preview = NULL; + + return sce_copy; } - - /* grease pencil */ - if (scen->gpd) { + else { + BKE_id_copy_ex(bmain, (ID *)sce, (ID **)&sce_copy, LIB_ID_COPY_ACTIONS, false); + + /* Extra actions, most notably SCE_FULL_COPY also duplicates several 'children' datablocks... */ + if (type == SCE_COPY_FULL) { - scen->gpd = BKE_gpencil_data_duplicate(bmain, scen->gpd, false); - } - else if (type == SCE_COPY_EMPTY) { - scen->gpd = NULL; + /* Copy Freestyle LineStyle datablocks. */ + for (SceneRenderLayer *srl_dst = sce_copy->r.layers.first; srl_dst; srl_dst = srl_dst->next) { + for (FreestyleLineSet *lineset = srl_dst->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { + if (lineset->linestyle) { + /* XXX Not copying anim/actions here? */ + BKE_id_copy_ex(bmain, (ID *)lineset->linestyle, (ID **)&lineset->linestyle, 0, false); + } + } + } + + /* Full copy of world (included animations) */ + if (sce_copy->world) { + BKE_id_copy_ex(bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS, false); + } + + /* Full copy of GreasePencil. */ + /* XXX Not copying anim/actions here? */ + if (sce_copy->gpd) { + BKE_id_copy_ex(bmain, (ID *)sce_copy->gpd, (ID **)&sce_copy->gpd, 0, false); + } } else { - id_us_plus((ID *)scen->gpd); + /* Remove sequencer if not full copy */ + /* XXX Why in Hell? :/ */ + remove_sequencer_fcurves(sce_copy); + BKE_sequencer_editing_free(sce_copy); } - } - BKE_previewimg_id_copy(&scen->id, &sce->id); + /* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations + * are done outside of blenkernel with ED_objects_single_users! */ + + /* camera */ + if (ELEM(type, SCE_COPY_LINK_DATA, SCE_COPY_FULL)) { + ID_NEW_REMAP(sce_copy->camera); + } - return scen; + return sce_copy; + } } void BKE_scene_groups_relink(Scene *sce) @@ -419,11 +477,6 @@ void BKE_scene_free(Scene *sce) MEM_freeN(sce->r.avicodecdata); sce->r.avicodecdata = NULL; } - if (sce->r.qtcodecdata) { - free_qtcodecdata(sce->r.qtcodecdata); - MEM_freeN(sce->r.qtcodecdata); - sce->r.qtcodecdata = NULL; - } if (sce->r.ffcodecdata.properties) { IDP_FreeProperty(sce->r.ffcodecdata.properties); MEM_freeN(sce->r.ffcodecdata.properties); @@ -583,7 +636,7 @@ void BKE_scene_init(Scene *sce) sce->r.seq_prev_type = OB_SOLID; sce->r.seq_rend_type = OB_SOLID; - sce->r.seq_flag = R_SEQ_GL_PREV; + sce->r.seq_flag = 0; sce->r.threads = 1; @@ -843,7 +896,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name) { Scene *sce; - sce = BKE_libblock_alloc(bmain, ID_SCE, name); + sce = BKE_libblock_alloc(bmain, ID_SCE, name, 0); id_us_min(&sce->id); id_us_ensure_real(&sce->id); @@ -1847,8 +1900,6 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc #endif { DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene); - /* TODO(sergey): This is to beocme a node in new depsgraph. */ - BKE_mask_update_scene(bmain, scene); } /* update sound system animation (TODO, move to depsgraph) */ @@ -1965,11 +2016,10 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, /* Following 2 functions are recursive * so don't call within 'scene_update_tagged_recursive' */ DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still + BKE_mask_evaluate_all_masks(bmain, ctime, true); } #endif - BKE_mask_evaluate_all_masks(bmain, ctime, true); - /* Update animated cache files for modifiers. */ BKE_cachefile_update_frame(bmain, sce, ctime, (((double)sce->r.frs_sec) / (double)sce->r.frs_sec_base)); @@ -2318,6 +2368,14 @@ int BKE_scene_num_threads(const Scene *scene) return BKE_render_num_threads(&scene->r); } +int BKE_render_preview_pixel_size(const RenderData *r) +{ + if (r->preview_pixel_size == 0) { + return (U.pixelsize > 1.5f)? 2 : 1; + } + return r->preview_pixel_size; +} + /* Apply the needed correction factor to value, based on unit_type (only length-related are affected currently) * and unit->scale_length. */ diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 857bd5447c8..df47b89fadc 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -181,6 +181,7 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar) BLI_listbase_clear(&newar->ui_lists); newar->swinid = 0; newar->regiontimer = NULL; + newar->headerstr = NULL; /* use optional regiondata callback */ if (ar->regiondata) { diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 669f76cf90b..9b0db300e6d 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -377,6 +377,8 @@ static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt) } break; } + default: + break; } } @@ -480,9 +482,12 @@ void BKE_sequencer_editing_free(Scene *scene) static void sequencer_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf) { +#if 0 + /* Bute buffer is supposed to be in sequencer working space already. */ if (ibuf->rect != NULL) { IMB_colormanagement_assign_rect_colorspace(ibuf, scene->sequencer_colorspace_settings.name); } +#endif if (ibuf->rect_float != NULL) { IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name); } @@ -3233,7 +3238,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq const bool is_background = G.background; const bool do_seq_gl = is_rendering ? 0 /* (context->scene->r.seq_flag & R_SEQ_GL_REND) */ : - (context->scene->r.seq_flag & R_SEQ_GL_PREV) != 0; + (context->scene->r.seq_prev_type) != OB_RENDER; // bool have_seq = false; /* UNUSED */ bool have_comp = false; bool use_gpencil = true; @@ -3315,7 +3320,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq } } else { - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); const int totviews = BKE_scene_multiview_num_views_get(&scene->r); int i; ImBuf **ibufs_arr; @@ -3332,7 +3337,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq */ if (!is_thread_main || is_rendering == false || is_background || context->eval_ctx->mode == DAG_EVAL_RENDER) { if (re == NULL) - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay); RE_BlenderFrame(re, context->bmain, scene, NULL, camera, scene->lay, frame, false); @@ -5371,9 +5376,8 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad return seq; } -static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dupe_flag) +static Sequence *seq_dupli(const Scene *scene_src, Scene *scene_dst, Sequence *seq, int dupe_flag, const int flag) { - Scene *sce_audio = scene_to ? scene_to : scene; Sequence *seqn = MEM_dupallocN(seq); seq->tmp = seqn; @@ -5397,7 +5401,7 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup } if (seq->prop) { - seqn->prop = IDP_CopyProperty(seq->prop); + seqn->prop = IDP_CopyProperty_ex(seq->prop, flag); } if (seqn->modifiers.first) { @@ -5416,7 +5420,7 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup else if (seq->type == SEQ_TYPE_SCENE) { seqn->strip->stripdata = NULL; if (seq->scene_sound) - seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(sce_audio, seqn); + seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene_dst, seqn); } else if (seq->type == SEQ_TYPE_MOVIECLIP) { /* avoid assert */ @@ -5433,9 +5437,11 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata); if (seq->scene_sound) - seqn->scene_sound = BKE_sound_add_scene_sound_defaults(sce_audio, seqn); + seqn->scene_sound = BKE_sound_add_scene_sound_defaults(scene_dst, seqn); - id_us_plus((ID *)seqn->sound); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)seqn->sound); + } } else if (seq->type == SEQ_TYPE_IMAGE) { seqn->strip->stripdata = @@ -5455,11 +5461,15 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup BLI_assert(0); } - if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) - BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqn); + if (scene_src == scene_dst) { + if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) { + BKE_sequence_base_unique_name_recursive(&scene_dst->ed->seqbase, seqn); + } - if (dupe_flag & SEQ_DUPE_ANIM) - BKE_sequencer_dupe_animdata(scene, seq->name + 2, seqn->name + 2); + if (dupe_flag & SEQ_DUPE_ANIM) { + BKE_sequencer_dupe_animdata(scene_dst, seq->name + 2, seqn->name + 2); + } + } return seqn; } @@ -5486,16 +5496,16 @@ static void seq_new_fix_links_recursive(Sequence *seq) } } -Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence *seq, int dupe_flag) +Sequence *BKE_sequence_dupli_recursive(const Scene *scene_src, Scene *scene_dst, Sequence *seq, int dupe_flag) { Sequence *seqn; seq->tmp = NULL; - seqn = seq_dupli(scene, scene_to, seq, dupe_flag); + seqn = seq_dupli(scene_src, scene_dst, seq, dupe_flag, 0); if (seq->type == SEQ_TYPE_META) { Sequence *s; for (s = seq->seqbase.first; s; s = s->next) { - Sequence *n = BKE_sequence_dupli_recursive(scene, scene_to, s, dupe_flag); + Sequence *n = BKE_sequence_dupli_recursive(scene_src, scene_dst, s, dupe_flag); if (n) { BLI_addtail(&seqn->seqbase, n); } @@ -5508,19 +5518,19 @@ Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence * } void BKE_sequence_base_dupli_recursive( - Scene *scene, Scene *scene_to, ListBase *nseqbase, ListBase *seqbase, - int dupe_flag) + const Scene *scene_src, Scene *scene_dst, ListBase *nseqbase, const ListBase *seqbase, + int dupe_flag, const int flag) { Sequence *seq; Sequence *seqn = NULL; - Sequence *last_seq = BKE_sequencer_active_get(scene); + Sequence *last_seq = BKE_sequencer_active_get((Scene *)scene_src); /* always include meta's strips */ int dupe_flag_recursive = dupe_flag | SEQ_DUPE_ALL; for (seq = seqbase->first; seq; seq = seq->next) { seq->tmp = NULL; if ((seq->flag & SELECT) || (dupe_flag & SEQ_DUPE_ALL)) { - seqn = seq_dupli(scene, scene_to, seq, dupe_flag); + seqn = seq_dupli(scene_src, scene_dst, seq, dupe_flag, flag); if (seqn) { /*should never fail */ if (dupe_flag & SEQ_DUPE_CONTEXT) { seq->flag &= ~SEQ_ALLSEL; @@ -5530,13 +5540,13 @@ void BKE_sequence_base_dupli_recursive( BLI_addtail(nseqbase, seqn); if (seq->type == SEQ_TYPE_META) { BKE_sequence_base_dupli_recursive( - scene, scene_to, &seqn->seqbase, &seq->seqbase, - dupe_flag_recursive); + scene_src, scene_dst, &seqn->seqbase, &seq->seqbase, + dupe_flag_recursive, flag); } if (dupe_flag & SEQ_DUPE_CONTEXT) { if (seq == last_seq) { - BKE_sequencer_active_set(scene, seqn); + BKE_sequencer_active_set(scene_dst, seqn); } } } diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 7094d5a3547..f9d1793d7cb 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -152,6 +152,9 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; BVHTreeNearest nearest = NULL_BVHTreeNearest; + if (calc->target != NULL && calc->target->getNumVerts(calc->target) == 0) { + return; + } TIMEIT_BENCH(bvhtree_from_mesh_verts(&treeData, calc->target, 0.0, 2, 6), bvhtree_verts); if (treeData.tree == NULL) { @@ -376,6 +379,9 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for if ((calc->smd->shrinkOpts & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0) return; + if (calc->target != NULL && calc->target->getNumPolys(calc->target) == 0) { + return; + } /* Prepare data to retrieve the direction in which we should project each vertex */ if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { @@ -432,7 +438,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for if (targ_tree) { BVHTree *aux_tree = NULL; void *aux_callback = NULL; - if (auxMesh != NULL) { + if (auxMesh != NULL && auxMesh->getNumPolys(auxMesh) != 0) { /* use editmesh to avoid array allocation */ if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) { emaux = BKE_editmesh_from_object(calc->smd->auxTarget); @@ -560,6 +566,10 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; BVHTreeNearest nearest = NULL_BVHTreeNearest; + if (calc->target->getNumPolys(calc->target) == 0) { + return; + } + /* Create a bvh-tree of the given target */ bvhtree_from_mesh_looptri(&treeData, calc->target, 0.0, 2, 6); if (treeData.tree == NULL) { diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index d0ef5cfc092..adecea7080c 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -2692,7 +2692,6 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object * if (smd->flow->dm) smd->flow->dm->release(smd->flow->dm); smd->flow->dm = CDDM_copy(dm); - DM_ensure_looptri(smd->flow->dm); if (scene->r.cfra > smd->time) { @@ -2715,7 +2714,6 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object * smd->coll->dm->release(smd->coll->dm); smd->coll->dm = CDDM_copy(dm); - DM_ensure_looptri(smd->coll->dm); } smd->time = scene->r.cfra; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 8469351c54a..45d1f969d64 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -83,7 +83,7 @@ bSound *BKE_sound_new_file(struct Main *bmain, const char *filepath) BLI_path_abs(str, path); - sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath)); + sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0); BLI_strncpy(sound->name, filepath, FILE_MAX); /* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */ @@ -155,6 +155,34 @@ void BKE_sound_free(bSound *sound) } } +/** + * Only copy internal data of Sound ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_sound_copy_data(Main *bmain, bSound *sound_dst, const bSound *UNUSED(sound_src), const int UNUSED(flag)) +{ + sound_dst->handle = NULL; + sound_dst->cache = NULL; + sound_dst->waveform = NULL; + sound_dst->playback_handle = NULL; + sound_dst->spinlock = NULL; /* Think this is OK? Otherwise, easy to create new spinlock here... */ + + /* Just to be sure, should not have any value actually after reading time. */ + sound_dst->ipo = NULL; + sound_dst->newpackedfile = NULL; + + if (sound_dst->packedfile) { + sound_dst->packedfile = dupPackedFile(sound_dst->packedfile); + } + + /* Initialize whole runtime (audaspace) stuff. */ + BKE_sound_load(bmain, sound_dst); +} + void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local) { BKE_id_make_local_generic(bmain, &sound->id, true, lib_local); diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index d00e4b1a0d2..9d604a9382a 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -61,25 +61,31 @@ void *BKE_speaker_add(Main *bmain, const char *name) { Speaker *spk; - spk = BKE_libblock_alloc(bmain, ID_SPK, name); + spk = BKE_libblock_alloc(bmain, ID_SPK, name, 0); BKE_speaker_init(spk); return spk; } -Speaker *BKE_speaker_copy(Main *bmain, const Speaker *spk) +/** + * Only copy internal data of Speaker ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_speaker_copy_data(Main *UNUSED(bmain), Speaker *UNUSED(spk_dst), const Speaker *UNUSED(spk_src), const int UNUSED(flag)) { - Speaker *spkn; - - spkn = BKE_libblock_copy(bmain, &spk->id); - - if (spkn->sound) - id_us_plus(&spkn->sound->id); - - BKE_id_copy_ensure_local(bmain, &spk->id, &spkn->id); + /* Nothing to do! */ +} - return spkn; +Speaker *BKE_speaker_copy(Main *bmain, const Speaker *spk) +{ + Speaker *spk_copy; + BKE_id_copy_ex(bmain, &spk->id, (ID **)&spk_copy, 0, false); + return spk_copy; } void BKE_speaker_make_local(Main *bmain, Speaker *spk, const bool lib_local) diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index c4665c40ec4..7c5ee42b7bc 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -42,6 +42,8 @@ #include <math.h> #include <float.h> +#include "atomic_ops.h" + #include "MEM_guardedalloc.h" #include "DNA_mesh_types.h" @@ -3681,6 +3683,11 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int gridFaces = gridSize - 1, totface; int prev_mat_nr = -1; + if (ccgdm->pbvh) { + if (G.debug_value == 14) + BKE_pbvh_draw_BB(ccgdm->pbvh); + } + #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { int new_matnr; @@ -4414,7 +4421,8 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) if (!ob->sculpt) return NULL; - grid_pbvh = ccgDM_use_grid_pbvh(ccgdm); + /* In vwpaint, we always use a grid_pbvh for multires/subsurf */ + grid_pbvh = (!(ob->mode & OB_MODE_SCULPT) || ccgDM_use_grid_pbvh(ccgdm)); if (ob->sculpt->pbvh) { if (grid_pbvh) { @@ -4430,12 +4438,18 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) ccgdm->pbvh = ob->sculpt->pbvh; } - if (ccgdm->pbvh) + if (ccgdm->pbvh) { + /* For vertex paint, keep track of ccgdm */ + if (!(ob->mode & OB_MODE_SCULPT)) { + BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm); + } return ccgdm->pbvh; + } /* no pbvh exists yet, we need to create one. only in case of multires * we build a pbvh over the modified mesh, in other cases the base mesh * is being sculpted, so we build a pbvh from that. */ + /* Note: vwpaint always builds a pbvh over the modified mesh. */ if (grid_pbvh) { ccgdm_create_grids(dm); @@ -4466,6 +4480,10 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) if (ccgdm->pbvh) pbvh_show_diffuse_color_set(ccgdm->pbvh, ob->sculpt->show_diffuse_color); + /* For vertex paint, keep track of ccgdm */ + if (!(ob->mode & OB_MODE_SCULPT) && ccgdm->pbvh) { + BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm); + } return ccgdm->pbvh; } @@ -4474,16 +4492,17 @@ static void ccgDM_recalcTessellation(DerivedMesh *UNUSED(dm)) /* Nothing to do: CCG handles creating its own tessfaces */ } +/* WARNING! *MUST* be called in an 'loops_cache_rwlock' protected thread context! */ static void ccgDM_recalcLoopTri(DerivedMesh *dm) { - BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE); - MLoopTri *mlooptri; + MLoopTri *mlooptri = dm->looptris.array; const int tottri = dm->numPolyData * 2; int i, poly_index; DM_ensure_looptri_data(dm); - mlooptri = dm->looptris.array; + mlooptri = dm->looptris.array_wip; + BLI_assert(tottri == 0 || mlooptri != NULL); BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); BLI_assert(tottri == dm->looptris.num); @@ -4502,19 +4521,10 @@ static void ccgDM_recalcLoopTri(DerivedMesh *dm) lt->tri[2] = (poly_index * 4) + 2; lt->poly = poly_index; } - BLI_rw_mutex_unlock(&loops_cache_rwlock); -} -static const MLoopTri *ccgDM_getLoopTriArray(DerivedMesh *dm) -{ - if (dm->looptris.array) { - BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); - } - else { - dm->recalcLoopTri(dm); - } - - return dm->looptris.array; + BLI_assert(dm->looptris.array == NULL); + atomic_cas_ptr((void **)&dm->looptris.array, dm->looptris.array, dm->looptris.array_wip); + dm->looptris.array_wip = NULL; } static void ccgDM_calcNormals(DerivedMesh *dm) @@ -4533,8 +4543,6 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm) ccgdm->dm.getNumPolys = ccgDM_getNumPolys; ccgdm->dm.getNumTessFaces = ccgDM_getNumTessFaces; - ccgdm->dm.getLoopTriArray = ccgDM_getLoopTriArray; - ccgdm->dm.getVert = ccgDM_getFinalVert; ccgdm->dm.getEdge = ccgDM_getFinalEdge; ccgdm->dm.getTessFace = ccgDM_getFinalFace; diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 466bef7ff36..7c4aa81ee46 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -224,7 +224,7 @@ Text *BKE_text_add(Main *bmain, const char *name) { Text *ta; - ta = BKE_libblock_alloc(bmain, ID_TXT, name); + ta = BKE_libblock_alloc(bmain, ID_TXT, name, 0); BKE_text_init(ta); @@ -410,7 +410,7 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const return false; } - ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs)); + ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs), 0); ta->id.us = 0; BLI_listbase_clear(&ta->lines); @@ -449,53 +449,49 @@ Text *BKE_text_load(Main *bmain, const char *file, const char *relpath) return BKE_text_load_ex(bmain, file, relpath, false); } -Text *BKE_text_copy(Main *bmain, const Text *ta) +/** + * Only copy internal data of Text ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_text_copy_data(Main *UNUSED(bmain), Text *ta_dst, const Text *ta_src, const int UNUSED(flag)) { - Text *tan; - TextLine *line, *tmp; - - tan = BKE_libblock_copy(bmain, &ta->id); - /* file name can be NULL */ - if (ta->name) { - tan->name = BLI_strdup(ta->name); - } - else { - tan->name = NULL; + if (ta_src->name) { + ta_dst->name = BLI_strdup(ta_src->name); } - tan->flags = ta->flags | TXT_ISDIRTY; - - BLI_listbase_clear(&tan->lines); - tan->curl = tan->sell = NULL; - tan->compiled = NULL; - - tan->nlines = ta->nlines; + ta_dst->flags |= TXT_ISDIRTY; + + BLI_listbase_clear(&ta_dst->lines); + ta_dst->curl = ta_dst->sell = NULL; + ta_dst->compiled = NULL; - line = ta->lines.first; /* Walk down, reconstructing */ - while (line) { - tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline"); - tmp->line = MEM_mallocN(line->len + 1, "textline_string"); - tmp->format = NULL; - - strcpy(tmp->line, line->line); + for (TextLine *line_src = ta_src->lines.first; line_src; line_src = line_src->next) { + TextLine *line_dst = MEM_mallocN(sizeof(*line_dst), __func__); - tmp->len = line->len; - - BLI_addtail(&tan->lines, tmp); - - line = line->next; - } + line_dst->line = BLI_strdup(line_src->line); + line_dst->format = NULL; + line_dst->len = line_src->len; - tan->curl = tan->sell = tan->lines.first; - tan->curc = tan->selc = 0; + BLI_addtail(&ta_dst->lines, line_dst); + } - init_undo_text(tan); + ta_dst->curl = ta_dst->sell = ta_dst->lines.first; + ta_dst->curc = ta_dst->selc = 0; - BKE_id_copy_ensure_local(bmain, &ta->id, &tan->id); + init_undo_text(ta_dst); +} - return tan; +Text *BKE_text_copy(Main *bmain, const Text *ta) +{ + Text *ta_copy; + BKE_id_copy_ex(bmain, &ta->id, (ID **)&ta_copy, 0, false); + return ta_copy; } void BKE_text_make_local(Main *bmain, Text *text, const bool lib_local) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 1e0659d3d67..8f0334a4752 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -707,7 +707,7 @@ Tex *BKE_texture_add(Main *bmain, const char *name) { Tex *tex; - tex = BKE_libblock_alloc(bmain, ID_TE, name); + tex = BKE_libblock_alloc(bmain, ID_TE, name, 0); BKE_texture_default(tex); @@ -846,41 +846,71 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot) /* ------------------------------------------------------------------------- */ -Tex *BKE_texture_copy(Main *bmain, const Tex *tex) +/** + * Only copy internal data of Texture ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const int flag) { - Tex *texn; - - texn = BKE_libblock_copy(bmain, &tex->id); - if (BKE_texture_is_image_user(tex)) { - id_us_plus((ID *)texn->ima); + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; + + if (!BKE_texture_is_image_user(tex_src)) { + tex_dst->ima = NULL; } - else { - texn->ima = NULL; + + if (tex_dst->coba) { + tex_dst->coba = MEM_dupallocN(tex_dst->coba); + } + if (tex_dst->env) { + tex_dst->env = BKE_texture_envmap_copy(tex_dst->env, flag_subdata); + } + if (tex_dst->pd) { + tex_dst->pd = BKE_texture_pointdensity_copy(tex_dst->pd, flag_subdata); + } + if (tex_dst->vd) { + tex_dst->vd = MEM_dupallocN(tex_dst->vd); + } + if (tex_dst->ot) { + tex_dst->ot = BKE_texture_ocean_copy(tex_dst->ot, flag_subdata); } - - if (texn->coba) texn->coba = MEM_dupallocN(texn->coba); - if (texn->env) texn->env = BKE_texture_envmap_copy(texn->env); - if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd); - if (texn->vd) texn->vd = MEM_dupallocN(texn->vd); - if (texn->ot) texn->ot = BKE_texture_ocean_copy(texn->ot); - if (tex->nodetree) { - if (tex->nodetree->execdata) { - ntreeTexEndExecTree(tex->nodetree->execdata); + if (tex_src->nodetree) { + if (tex_src->nodetree->execdata) { + ntreeTexEndExecTree(tex_src->nodetree->execdata); } - texn->nodetree = ntreeCopyTree(bmain, tex->nodetree); + BKE_id_copy_ex(bmain, (ID *)tex_src->nodetree, (ID **)&tex_dst->nodetree, flag, false); } - BKE_previewimg_id_copy(&texn->id, &tex->id); - - BKE_id_copy_ensure_local(bmain, &tex->id, &texn->id); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&tex_dst->id, &tex_src->id); + } + else { + tex_dst->preview = NULL; + } +} - return texn; +Tex *BKE_texture_copy(Main *bmain, const Tex *tex) +{ + Tex *tex_copy; + BKE_id_copy_ex(bmain, &tex->id, (ID **)&tex_copy, 0, false); + return tex_copy; } /* texture copy without adding to main dbase */ Tex *BKE_texture_localize(Tex *tex) { + /* TODO replace with something like + * Tex *tex_copy; + * BKE_id_copy_ex(bmain, &tex->id, (ID **)&tex_copy, LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT, false); + * return tex_copy; + * + * ... Once f*** nodes are fully converted to that too :( */ + Tex *texn; texn = BKE_libblock_copy_nolib(&tex->id, false); @@ -889,17 +919,17 @@ Tex *BKE_texture_localize(Tex *tex) if (texn->coba) texn->coba = MEM_dupallocN(texn->coba); if (texn->env) { - texn->env = BKE_texture_envmap_copy(texn->env); + texn->env = BKE_texture_envmap_copy(texn->env, LIB_ID_CREATE_NO_USER_REFCOUNT); id_us_min(&texn->env->ima->id); } - if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd); + if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd, LIB_ID_CREATE_NO_USER_REFCOUNT); if (texn->vd) { texn->vd = MEM_dupallocN(texn->vd); if (texn->vd->dataset) texn->vd->dataset = MEM_dupallocN(texn->vd->dataset); } if (texn->ot) { - texn->ot = BKE_texture_ocean_copy(tex->ot); + texn->ot = BKE_texture_ocean_copy(tex->ot, LIB_ID_CREATE_NO_USER_REFCOUNT); } texn->preview = NULL; @@ -1099,6 +1129,8 @@ void set_active_mtex(ID *id, short act) case ID_PA: ((ParticleSettings *)id)->texact = act; break; + default: + break; } } @@ -1263,16 +1295,20 @@ EnvMap *BKE_texture_envmap_add(void) /* ------------------------------------------------------------------------- */ -EnvMap *BKE_texture_envmap_copy(const EnvMap *env) +EnvMap *BKE_texture_envmap_copy(const EnvMap *env, const int flag) { EnvMap *envn; int a; envn = MEM_dupallocN(env); envn->ok = 0; - for (a = 0; a < 6; a++) envn->cube[a] = NULL; - if (envn->ima) id_us_plus((ID *)envn->ima); - + for (a = 0; a < 6; a++) { + envn->cube[a] = NULL; + } + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)envn->ima); + } + return envn; } @@ -1336,14 +1372,16 @@ PointDensity *BKE_texture_pointdensity_add(void) return pd; } -PointDensity *BKE_texture_pointdensity_copy(const PointDensity *pd) +PointDensity *BKE_texture_pointdensity_copy(const PointDensity *pd, const int UNUSED(flag)) { PointDensity *pdn; pdn = MEM_dupallocN(pd); pdn->point_tree = NULL; pdn->point_data = NULL; - if (pdn->coba) pdn->coba = MEM_dupallocN(pdn->coba); + if (pdn->coba) { + pdn->coba = MEM_dupallocN(pdn->coba); + } pdn->falloff_curve = curvemapping_copy(pdn->falloff_curve); /* can be NULL */ return pdn; } @@ -1430,7 +1468,7 @@ OceanTex *BKE_texture_ocean_add(void) return ot; } -OceanTex *BKE_texture_ocean_copy(const OceanTex *ot) +OceanTex *BKE_texture_ocean_copy(const OceanTex *ot, const int UNUSED(flag)) { OceanTex *otn = MEM_dupallocN(ot); diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 9120d384a16..b4ef381534f 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -190,7 +190,7 @@ void BKE_tracking_free(MovieTracking *tracking) } /* Copy the whole list of tracks. */ -static void tracking_tracks_copy(ListBase *tracks_dst, const ListBase *tracks_src, GHash *tracks_mapping) +static void tracking_tracks_copy(ListBase *tracks_dst, const ListBase *tracks_src, GHash *tracks_mapping, const int flag) { MovieTrackingTrack *track_dst, *track_src; @@ -202,7 +202,9 @@ static void tracking_tracks_copy(ListBase *tracks_dst, const ListBase *tracks_sr if (track_src->markers) { track_dst->markers = MEM_dupallocN(track_src->markers); } - id_us_plus(&track_dst->gpd->id); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus(&track_dst->gpd->id); + } BLI_addtail(tracks_dst, track_dst); BLI_ghash_insert(tracks_mapping, track_src, track_dst); } @@ -210,7 +212,8 @@ static void tracking_tracks_copy(ListBase *tracks_dst, const ListBase *tracks_sr /* copy the whole list of plane tracks (need whole MovieTracking structures due to embedded pointers to tracks). * WARNING: implies tracking_[dst/src] and their tracks have already been copied. */ -static void tracking_plane_tracks_copy(ListBase *plane_tracks_dst, const ListBase *plane_tracks_src, GHash *tracks_mapping) +static void tracking_plane_tracks_copy( + ListBase *plane_tracks_dst, const ListBase *plane_tracks_src, GHash *tracks_mapping, const int flag) { MovieTrackingPlaneTrack *plane_track_dst, *plane_track_src; @@ -225,14 +228,17 @@ static void tracking_plane_tracks_copy(ListBase *plane_tracks_dst, const ListBas for (int i = 0; i < plane_track_dst->point_tracksnr; i++) { plane_track_dst->point_tracks[i] = BLI_ghash_lookup(tracks_mapping, plane_track_src->point_tracks[i]); } - id_us_plus(&plane_track_dst->image->id); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus(&plane_track_dst->image->id); + } BLI_addtail(plane_tracks_dst, plane_track_dst); } } /* Copy reconstruction structure. */ static void tracking_reconstruction_copy( - MovieTrackingReconstruction *reconstruction_dst, const MovieTrackingReconstruction *reconstruction_src) + MovieTrackingReconstruction *reconstruction_dst, const MovieTrackingReconstruction *reconstruction_src, + const int UNUSED(flag)) { *reconstruction_dst = *reconstruction_src; if (reconstruction_src->cameras) { @@ -242,23 +248,25 @@ static void tracking_reconstruction_copy( /* Copy stabilization structure. */ static void tracking_stabilization_copy( - MovieTrackingStabilization *stabilization_dst, const MovieTrackingStabilization *stabilization_src) + MovieTrackingStabilization *stabilization_dst, const MovieTrackingStabilization *stabilization_src, + const int UNUSED(flag)) { *stabilization_dst = *stabilization_src; } /* Copy tracking object. */ static void tracking_object_copy( - MovieTrackingObject *object_dst, const MovieTrackingObject *object_src, GHash *tracks_mapping) + MovieTrackingObject *object_dst, const MovieTrackingObject *object_src, GHash *tracks_mapping, const int flag) { *object_dst = *object_src; - tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping); - tracking_plane_tracks_copy(&object_dst->plane_tracks, &object_src->plane_tracks, tracks_mapping); - tracking_reconstruction_copy(&object_dst->reconstruction, &object_src->reconstruction); + tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping, flag); + tracking_plane_tracks_copy(&object_dst->plane_tracks, &object_src->plane_tracks, tracks_mapping, flag); + tracking_reconstruction_copy(&object_dst->reconstruction, &object_src->reconstruction, flag); } /* Copy list of tracking objects. */ -static void tracking_objects_copy(ListBase *objects_dst, const ListBase *objects_src, GHash *tracks_mapping) +static void tracking_objects_copy( + ListBase *objects_dst, const ListBase *objects_src, GHash *tracks_mapping, const int flag) { MovieTrackingObject *object_dst, *object_src; @@ -266,22 +274,22 @@ static void tracking_objects_copy(ListBase *objects_dst, const ListBase *objects for (object_src = objects_src->first; object_src != NULL; object_src = object_src->next) { object_dst = MEM_mallocN(sizeof(*object_dst), __func__); - tracking_object_copy(object_dst, object_src, tracks_mapping); + tracking_object_copy(object_dst, object_src, tracks_mapping, flag); BLI_addtail(objects_dst, object_dst); } } /* Copy tracking structure content. */ -void BKE_tracking_copy(MovieTracking *tracking_dst, const MovieTracking *tracking_src) +void BKE_tracking_copy(MovieTracking *tracking_dst, const MovieTracking *tracking_src, const int flag) { GHash *tracks_mapping = BLI_ghash_ptr_new(__func__); *tracking_dst = *tracking_src; - tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping); - tracking_plane_tracks_copy(&tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping); - tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction); - tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization); + tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping, flag); + tracking_plane_tracks_copy(&tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping, flag); + tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction, flag); + tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization, flag); if (tracking_src->act_track) { tracking_dst->act_track = BLI_ghash_lookup(tracks_mapping, tracking_src->act_track); } @@ -299,7 +307,7 @@ void BKE_tracking_copy(MovieTracking *tracking_dst, const MovieTracking *trackin } /* Warning! Will override tracks_mapping. */ - tracking_objects_copy(&tracking_dst->objects, &tracking_src->objects, tracks_mapping); + tracking_objects_copy(&tracking_dst->objects, &tracking_src->objects, tracks_mapping, flag); /* Those remaining are runtime data, they will be reconstructed as needed, do not bother copying them. */ tracking_dst->dopesheet.ok = false; diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c index 9475925cdda..30981ed8f23 100644 --- a/source/blender/blenkernel/intern/tracking_auto.c +++ b/source/blender/blenkernel/intern/tracking_auto.c @@ -312,7 +312,7 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip, int num_total_tracks = BLI_listbase_count(tracksbase); context->tracks = - MEM_callocN(sizeof(MovieTrackingTrack*) * num_total_tracks, + MEM_callocN(sizeof(MovieTrackingTrack *) * num_total_tracks, "auto track pointers"); context->image_accessor = @@ -381,7 +381,7 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip, bool BKE_autotrack_context_step(AutoTrackContext *context) { - int frame_delta = context->backwards ? -1 : 1; + const int frame_delta = context->backwards ? -1 : 1; bool ok = false; int track; @@ -395,67 +395,64 @@ bool BKE_autotrack_context_step(AutoTrackContext *context) libmv_reference_marker, libmv_tracked_marker; libmv_TrackRegionResult libmv_result; - int frame = BKE_movieclip_remap_scene_to_clip_frame( - context->clips[options->clip_index], - context->user.framenr); - bool has_marker; - + const int frame = BKE_movieclip_remap_scene_to_clip_frame( + context->clips[options->clip_index], + context->user.framenr); BLI_spin_lock(&context->spin_lock); - has_marker = libmv_autoTrackGetMarker(context->autotrack, - options->clip_index, - frame, - options->track_index, - &libmv_current_marker); + const bool has_marker = libmv_autoTrackGetMarker(context->autotrack, + options->clip_index, + frame, + options->track_index, + &libmv_current_marker); BLI_spin_unlock(&context->spin_lock); - - if (has_marker) { - if (!tracking_check_marker_margin(&libmv_current_marker, - options->track->margin, - context->frame_width, - context->frame_height)) - { - continue; - } - - libmv_tracked_marker = libmv_current_marker; - libmv_tracked_marker.frame = frame + frame_delta; - - if (options->use_keyframe_match) { - libmv_tracked_marker.reference_frame = - libmv_current_marker.reference_frame; - libmv_autoTrackGetMarker(context->autotrack, - options->clip_index, - libmv_tracked_marker.reference_frame, - options->track_index, - &libmv_reference_marker); - } - else { - libmv_tracked_marker.reference_frame = frame; - libmv_reference_marker = libmv_current_marker; - } - - if (libmv_autoTrackMarker(context->autotrack, - &options->track_region_options, - &libmv_tracked_marker, - &libmv_result)) - { - BLI_spin_lock(&context->spin_lock); - libmv_autoTrackAddMarker(context->autotrack, - &libmv_tracked_marker); - BLI_spin_unlock(&context->spin_lock); - } - else { - options->is_failed = true; - options->failed_frame = frame + frame_delta; - } - ok = true; + /* Check whether we've got marker to sync with. */ + if (!has_marker) { + continue; + } + /* Check whether marker is going outside of allowed frame margin. */ + if (!tracking_check_marker_margin(&libmv_current_marker, + options->track->margin, + context->frame_width, + context->frame_height)) + { + continue; + } + libmv_tracked_marker = libmv_current_marker; + libmv_tracked_marker.frame = frame + frame_delta; + /* Update reference frame. */ + if (options->use_keyframe_match) { + libmv_tracked_marker.reference_frame = + libmv_current_marker.reference_frame; + libmv_autoTrackGetMarker(context->autotrack, + options->clip_index, + libmv_tracked_marker.reference_frame, + options->track_index, + &libmv_reference_marker); } + else { + libmv_tracked_marker.reference_frame = frame; + libmv_reference_marker = libmv_current_marker; + } + /* Perform actual tracking. */ + if (libmv_autoTrackMarker(context->autotrack, + &options->track_region_options, + &libmv_tracked_marker, + &libmv_result)) + { + BLI_spin_lock(&context->spin_lock); + libmv_autoTrackAddMarker(context->autotrack, &libmv_tracked_marker); + BLI_spin_unlock(&context->spin_lock); + } + else { + options->is_failed = true; + options->failed_frame = frame + frame_delta; + } + ok = true; } - + /* Advance the frame. */ BLI_spin_lock(&context->spin_lock); context->user.framenr += frame_delta; BLI_spin_unlock(&context->spin_lock); - return ok; } diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index a95399562d5..d8e98291117 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -58,6 +58,15 @@ #include "libmv-capi.h" +/* Uncomment this to have caching-specific debug prints. */ +// #define DEBUG_CACHE + +#ifdef DEBUG_CACHE +# define CACHE_PRINTF(...) printf(__VA_ARGS__) +#else +# define CACHE_PRINTF(...) +#endif + /*********************** Tracks map *************************/ TracksMap *tracks_map_new(const char *object_name, bool is_camera, int num_tracks, int customdata_size) @@ -523,6 +532,8 @@ typedef struct AccessCacheKey { int frame; int downscale; libmv_InputMode input_mode; + bool has_region; + float region_min[2], region_max[2]; int64_t transform_key; } AccessCacheKey; @@ -537,23 +548,44 @@ static bool accesscache_hashcmp(const void *a_v, const void *b_v) { const AccessCacheKey *a = (const AccessCacheKey *) a_v; const AccessCacheKey *b = (const AccessCacheKey *) b_v; - -#define COMPARE_FIELD(field) - { \ - if (a->clip_index != b->clip_index) { \ - return false; \ - } \ - } (void) 0 - - COMPARE_FIELD(clip_index); - COMPARE_FIELD(frame); - COMPARE_FIELD(downscale); - COMPARE_FIELD(input_mode); - COMPARE_FIELD(transform_key); - -#undef COMPARE_FIELD - - return true; + if (a->clip_index != b->clip_index || + a->frame != b->frame || + a->downscale != b->downscale || + a->input_mode != b->input_mode || + a->has_region != b->has_region || + a->transform_key != b->transform_key) + { + return true; + } + /* If there is region applied, compare it. */ + if (a->has_region) { + if (!equals_v2v2(a->region_min, b->region_min) || + !equals_v2v2(a->region_max, b->region_max)) + { + return true; + } + } + return false; +} + +static void accesscache_construct_key(AccessCacheKey *key, + int clip_index, + int frame, + libmv_InputMode input_mode, + int downscale, + const libmv_Region *region, + int64_t transform_key) +{ + key->clip_index = clip_index; + key->frame = frame; + key->input_mode = input_mode; + key->downscale = downscale; + key->has_region = (region != NULL); + if (key->has_region) { + copy_v2_v2(key->region_min, region->min); + copy_v2_v2(key->region_max, region->max); + } + key->transform_key = transform_key; } static void accesscache_put(TrackingImageAccessor *accessor, @@ -561,15 +593,13 @@ static void accesscache_put(TrackingImageAccessor *accessor, int frame, libmv_InputMode input_mode, int downscale, + const libmv_Region *region, int64_t transform_key, ImBuf *ibuf) { AccessCacheKey key; - key.clip_index = clip_index; - key.frame = frame; - key.input_mode = input_mode; - key.downscale = downscale; - key.transform_key = transform_key; + accesscache_construct_key(&key, clip_index, frame, input_mode, downscale, + region, transform_key); IMB_moviecache_put(accessor->cache, &key, ibuf); } @@ -578,14 +608,12 @@ static ImBuf *accesscache_get(TrackingImageAccessor *accessor, int frame, libmv_InputMode input_mode, int downscale, + const libmv_Region *region, int64_t transform_key) { AccessCacheKey key; - key.clip_index = clip_index; - key.frame = frame; - key.input_mode = input_mode; - key.downscale = downscale; - key.transform_key = transform_key; + accesscache_construct_key(&key, clip_index, frame, input_mode, downscale, + region, transform_key); return IMB_moviecache_get(accessor->cache, &key); } @@ -674,29 +702,37 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, { ImBuf *ibuf, *orig_ibuf, *final_ibuf; int64_t transform_key = 0; - if (transform != NULL) { transform_key = libmv_frameAccessorgetTransformKey(transform); } - /* First try to get fully processed image from the cache. */ + BLI_spin_lock(&accessor->cache_lock); ibuf = accesscache_get(accessor, clip_index, frame, input_mode, downscale, + region, transform_key); + BLI_spin_unlock(&accessor->cache_lock); if (ibuf != NULL) { + CACHE_PRINTF("Used cached buffer for frame %d\n", frame); + /* This is a little heuristic here: if we re-used image once, this is + * a high probability of the image to be related to a keyframe matched + * reference image. Those images we don't want to be thrown away because + * if we toss them out we'll be re-calculating them at the next + * iteration. + */ + ibuf->userflags |= IB_PERSISTENT; return ibuf; } - + CACHE_PRINTF("Calculate new buffer for frame %d\n", frame); /* And now we do postprocessing of the original frame. */ orig_ibuf = accessor_get_preprocessed_ibuf(accessor, clip_index, frame); - if (orig_ibuf == NULL) { return NULL; } - + /* Cut a region if requested. */ if (region != NULL) { int width = region->max[0] - region->min[0], height = region->max[1] - region->min[1]; @@ -756,7 +792,7 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, BLI_unlock_thread(LOCK_MOVIECLIP); final_ibuf = orig_ibuf; } - + /* Downscale if needed. */ if (downscale > 0) { if (final_ibuf == orig_ibuf) { final_ibuf = IMB_dupImBuf(orig_ibuf); @@ -765,7 +801,7 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, orig_ibuf->x / (1 << downscale), orig_ibuf->y / (1 << downscale)); } - + /* Apply possible transformation. */ if (transform != NULL) { libmv_FloatImage input_image, output_image; ibuf_to_float_image(final_ibuf, &input_image); @@ -778,12 +814,13 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, final_ibuf = float_image_to_ibuf(&output_image); libmv_floatImageDestroy(&output_image); } - + /* Transform number of channels. */ if (input_mode == LIBMV_IMAGE_MODE_RGBA) { BLI_assert(orig_ibuf->channels == 3 || orig_ibuf->channels == 4); /* pass */ } else /* if (input_mode == LIBMV_IMAGE_MODE_MONO) */ { + BLI_assert(input_mode == LIBMV_IMAGE_MODE_MONO); if (final_ibuf->channels != 1) { ImBuf *grayscale_ibuf = make_grayscale_ibuf_copy(final_ibuf); if (final_ibuf != orig_ibuf) { @@ -793,37 +830,25 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, final_ibuf = grayscale_ibuf; } } - - /* it's possible processing still didn't happen at this point, + /* It's possible processing still didn't happen at this point, * but we really need a copy of the buffer to be transformed * and to be put to the cache. */ if (final_ibuf == orig_ibuf) { final_ibuf = IMB_dupImBuf(orig_ibuf); } - IMB_freeImBuf(orig_ibuf); - - /* We put postprocessed frame to the cache always for now, - * not the smartest thing in the world, but who cares at this point. - */ - - /* TODO(sergey): Disable cache for now, because we don't store region - * in the cache key and can't check whether cached version is usable for - * us or not. - * - * Need to think better about what to cache and when. - */ - if (false) { - accesscache_put(accessor, - clip_index, - frame, - input_mode, - downscale, - transform_key, - final_ibuf); - } - + BLI_spin_lock(&accessor->cache_lock); + /* Put final buffer to cache. */ + accesscache_put(accessor, + clip_index, + frame, + input_mode, + downscale, + region, + transform_key, + final_ibuf); + BLI_spin_unlock(&accessor->cache_lock); return final_ibuf; } @@ -876,7 +901,7 @@ static void accessor_release_image_callback(libmv_CacheKey cache_key) } static libmv_CacheKey accessor_get_mask_for_track_callback( - libmv_FrameAccessorUserData* user_data, + libmv_FrameAccessorUserData *user_data, int clip_index, int frame, int track_index, @@ -958,6 +983,8 @@ TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR accessor_get_mask_for_track_callback, accessor_release_mask_callback); + BLI_spin_init(&accessor->cache_lock); + return accessor; } @@ -965,5 +992,6 @@ void tracking_image_accessor_destroy(TrackingImageAccessor *accessor) { IMB_moviecache_free(accessor->cache); libmv_FrameAccessorDestroy(accessor->libmv_accessor); + BLI_spin_end(&accessor->cache_lock); MEM_freeN(accessor); } diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index c0a373395dc..8606da0743b 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -372,6 +372,12 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, con value_conv = value / unit->scalar; + /* Adjust precision to expected number of significant digits. + * Note that here, we shall not have to worry about very big/small numbers, units are expected to replace + * 'scientific notation' in those cases. */ + prec -= integer_digits_d(value_conv); + CLAMP(prec, 0, 6); + /* Convert to a string */ len = BLI_snprintf_rlen(str, len_max, "%.*f", prec, value_conv); @@ -442,12 +448,15 @@ size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system size_t i; i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0'); + prec -= integer_digits_d(value_a / unit_b->scalar) - integer_digits_d(value_b / unit_b->scalar); + prec = max_ii(prec, 0); + /* is there enough space for at least 1 char of the next unit? */ if (i + 2 < len_max) { str[i++] = ' '; /* use low precision since this is a smaller unit */ - i += unit_as_string(str + i, len_max - i, value_b, prec ? 1 : 0, usys, unit_b, '\0'); + i += unit_as_string(str + i, len_max - i, value_b, prec, usys, unit_b, '\0'); } return i; } diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 363c36e644d..e79b06a44fe 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -112,43 +112,59 @@ World *add_world(Main *bmain, const char *name) { World *wrld; - wrld = BKE_libblock_alloc(bmain, ID_WO, name); + wrld = BKE_libblock_alloc(bmain, ID_WO, name, 0); BKE_world_init(wrld); return wrld; } -World *BKE_world_copy(Main *bmain, const World *wrld) +/** + * Only copy internal data of World ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, const int flag) { - World *wrldn; - int a; - - wrldn = BKE_libblock_copy(bmain, &wrld->id); - - for (a = 0; a < MAX_MTEX; a++) { - if (wrld->mtex[a]) { - wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), "BKE_world_copy"); - memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex)); - id_us_plus((ID *)wrldn->mtex[a]->tex); + for (int a = 0; a < MAX_MTEX; a++) { + if (wrld_src->mtex[a]) { + wrld_dst->mtex[a] = MEM_dupallocN(wrld_src->mtex[a]); } } - if (wrld->nodetree) { - wrldn->nodetree = ntreeCopyTree(bmain, wrld->nodetree); + if (wrld_src->nodetree) { + BKE_id_copy_ex(bmain, (ID *)wrld_src->nodetree, (ID **)&wrld_dst->nodetree, flag, false); } - - BKE_previewimg_id_copy(&wrldn->id, &wrld->id); - BLI_listbase_clear(&wrldn->gpumaterial); + BLI_listbase_clear(&wrld_dst->gpumaterial); - BKE_id_copy_ensure_local(bmain, &wrld->id, &wrldn->id); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&wrld_dst->id, &wrld_src->id); + } + else { + wrld_dst->preview = NULL; + } +} - return wrldn; +World *BKE_world_copy(Main *bmain, const World *wrld) +{ + World *wrld_copy; + BKE_id_copy_ex(bmain, &wrld->id, (ID **)&wrld_copy, 0, false); + return wrld_copy; } World *localize_world(World *wrld) { + /* TODO replace with something like + * World *wrld_copy; + * BKE_id_copy_ex(bmain, &wrld->id, (ID **)&wrld_copy, LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT, false); + * return wrld_copy; + * + * ... Once f*** nodes are fully converted to that too :( */ + World *wrldn; int a; diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index 89b2caa5ac7..2fb4ed03603 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -80,10 +80,6 @@ static void *context_create_avi(void); static void context_free_avi(void *context_v); #endif /* WITH_AVI */ -#ifdef WITH_QUICKTIME -# include "quicktime_export.h" -#endif - #ifdef WITH_FFMPEG # include "BKE_writeffmpeg.h" #endif @@ -115,16 +111,6 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) #endif /* do the platform specific handles */ -#ifdef WITH_QUICKTIME - if (imtype == R_IMF_IMTYPE_QUICKTIME) { - mh.start_movie = start_qt; - mh.append_movie = append_qt; - mh.end_movie = end_qt; - mh.get_movie_path = filepath_qt; - mh.context_create = context_create_qt; - mh.context_free = context_free_qt; - } -#endif #ifdef WITH_FFMPEG if (ELEM(imtype, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, R_IMF_IMTYPE_THEORA)) { mh.start_movie = BKE_ffmpeg_start; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 156b74f5c3d..a19e4142894 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -681,6 +681,7 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int /* xasp & yasp got float lately... */ st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q(((double) rd->xasp / (double) rd->yasp), 255); + st->avg_frame_rate = av_inv_q(c->time_base); set_ffmpeg_properties(rd, c, "video", &opts); diff --git a/source/blender/blenkernel/tracking_private.h b/source/blender/blenkernel/tracking_private.h index 1a68a1cac6a..07236fb2096 100644 --- a/source/blender/blenkernel/tracking_private.h +++ b/source/blender/blenkernel/tracking_private.h @@ -125,6 +125,7 @@ typedef struct TrackingImageAccessor { int num_tracks; int start_frame; struct libmv_FrameAccessor *libmv_accessor; + SpinLock cache_lock; } TrackingImageAccessor; TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP], diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h index 74f24c808ff..3ffca818c0d 100644 --- a/source/blender/blenlib/BLI_array.h +++ b/source/blender/blenlib/BLI_array.h @@ -135,11 +135,12 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, #define BLI_array_append_ret(arr) \ (BLI_array_reserve(arr, 1), &arr[(_##arr##_count++)]) -#define BLI_array_free(arr) \ +#define BLI_array_free(arr) { \ if (arr && (char *)arr != _##arr##_static) { \ BLI_array_fake_user(arr); \ MEM_freeN(arr); \ - } (void)0 + } \ +} ((void)0) #define BLI_array_pop(arr) ( \ (arr && _##arr##_count) ? \ diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h index 01fc9d70207..0726e3bb343 100644 --- a/source/blender/blenlib/BLI_compiler_compat.h +++ b/source/blender/blenlib/BLI_compiler_compat.h @@ -48,12 +48,7 @@ extern "C++" { #if defined(_MSC_VER) # define BLI_INLINE static __forceinline #else -# if (defined(__APPLE__) && defined(__ppc__)) -/* static inline __attribute__ here breaks osx ppc gcc42 build */ -# define BLI_INLINE static __attribute__((always_inline)) __attribute__((__unused__)) -# else -# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) -# endif +# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) #endif #endif /* __BLI_COMPILER_COMPAT_H__ */ diff --git a/source/blender/blenlib/BLI_dial.h b/source/blender/blenlib/BLI_dial.h index ad7680fe03e..71ab57bb61a 100644 --- a/source/blender/blenlib/BLI_dial.h +++ b/source/blender/blenlib/BLI_dial.h @@ -52,8 +52,8 @@ typedef struct Dial Dial; -Dial *BLI_dial_initialize(float start_position[2], float threshold); +Dial *BLI_dial_initialize(const float start_position[2], float threshold); -float BLI_dial_angle(Dial *dial, float current_position[2]); +float BLI_dial_angle(Dial *dial, const float current_position[2]); #endif /* __BLI_DIAL_H__ */ diff --git a/source/blender/blenlib/BLI_fnmatch.h b/source/blender/blenlib/BLI_fnmatch.h index f69f5b39869..06fa5048622 100644 --- a/source/blender/blenlib/BLI_fnmatch.h +++ b/source/blender/blenlib/BLI_fnmatch.h @@ -28,7 +28,7 @@ extern "C" { #endif -#if defined WIN32 && !defined _LIBC || defined __sun +#if defined WIN32 && !defined _LIBC #if defined(__cplusplus) || (defined(__STDC__) && __STDC__) #undef __P @@ -53,7 +53,7 @@ extern "C" { #define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ #define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ -#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined(_GNU_SOURCE) || defined(__SUNPRO_C) +#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined(_GNU_SOURCE) #define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ #define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ #define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ @@ -72,7 +72,7 @@ extern int fnmatch __P((const char *__pattern, const char *__string, # define _GNU_SOURCE # endif # include <fnmatch.h> -#endif /* defined WIN32 && !defined _LIBC || defined __sun */ +#endif /* defined WIN32 && !defined _LIBC */ #ifdef __cplusplus } diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index 7cf3e97bdc9..b42a36a3567 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -43,7 +43,7 @@ extern "C" { #ifndef GHASH_INTERNAL_API # ifdef __GNUC__ # undef _GHASH_INTERNAL_ATTR -# define _GHASH_INTERNAL_ATTR __attribute__ ((deprecated)) +# define _GHASH_INTERNAL_ATTR __attribute__ ((deprecated)) /* not deprecated, just private. */ # endif #endif @@ -90,6 +90,7 @@ void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfre void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve); void BLI_ghash_insert(GHash *gh, void *key, void *val); bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); +void *BLI_ghash_replace_key(GHash *gh, void *key); void *BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; void *BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default) ATTR_WARN_UNUSED_RESULT; void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; @@ -248,6 +249,7 @@ void BLI_gset_insert(GSet *gh, void *key); bool BLI_gset_add(GSet *gs, void *key); bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key); bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp); +void *BLI_gset_replace_key(GSet *gs, void *key); bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT; bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp); diff --git a/source/blender/blenlib/BLI_kdtree.h b/source/blender/blenlib/BLI_kdtree.h index aa54e1c823c..18908f8c551 100644 --- a/source/blender/blenlib/BLI_kdtree.h +++ b/source/blender/blenlib/BLI_kdtree.h @@ -66,6 +66,10 @@ void BLI_kdtree_range_search_cb( const KDTree *tree, const float co[3], float range, bool (*search_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data); +int BLI_kdtree_calc_duplicates_fast( + const KDTree *tree, const float range, bool use_index_order, + int *doubles); + /* Normal use is deprecated */ /* remove __normal functions when last users drop */ int BLI_kdtree_find_nearest_n__normal( diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index 0126e30d900..e6a72298ae7 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -138,6 +138,9 @@ MINLINE int signum_i(float a); MINLINE float power_of_2(float f); +MINLINE int integer_digits_f(const float f); +MINLINE int integer_digits_d(const double d); + /* these don't really fit anywhere but were being copied about a lot */ MINLINE int is_power_of_2_i(int n); MINLINE int power_of_2_max_i(int n); @@ -146,10 +149,37 @@ MINLINE int power_of_2_min_i(int n); MINLINE unsigned int power_of_2_max_u(unsigned int x); MINLINE unsigned int power_of_2_min_u(unsigned int x); -MINLINE int iroundf(float a); MINLINE int divide_round_i(int a, int b); MINLINE int mod_i(int i, int n); +MINLINE signed char round_fl_to_char(float a); +MINLINE unsigned char round_fl_to_uchar(float a); +MINLINE short round_fl_to_short(float a); +MINLINE unsigned short round_fl_to_ushort(float a); +MINLINE int round_fl_to_int(float a); +MINLINE unsigned int round_fl_to_uint(float a); + +MINLINE signed char round_db_to_char(double a); +MINLINE unsigned char round_db_to_uchar(double a); +MINLINE short round_db_to_short(double a); +MINLINE unsigned short round_db_to_ushort(double a); +MINLINE int round_db_to_int(double a); +MINLINE unsigned int round_db_to_uint(double a); + +MINLINE signed char round_fl_to_char_clamp(float a); +MINLINE unsigned char round_fl_to_uchar_clamp(float a); +MINLINE short round_fl_to_short_clamp(float a); +MINLINE unsigned short round_fl_to_ushort_clamp(float a); +MINLINE int round_fl_to_int_clamp(float a); +MINLINE unsigned int round_fl_to_uint_clamp(float a); + +MINLINE signed char round_db_to_char_clamp(double a); +MINLINE unsigned char round_db_to_uchar_clamp(double a); +MINLINE short round_db_to_short_clamp(double a); +MINLINE unsigned short round_db_to_ushort_clamp(double a); +MINLINE int round_db_to_int_clamp(double a); +MINLINE unsigned int round_db_to_uint_clamp(double a); + int pow_i(int base, int exp); double double_round(double x, int ndigits); diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 18bba33cdfa..2893da9bce8 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -166,8 +166,14 @@ void limit_dist_v3(float v1[3], float v2[3], const float dist); int isect_seg_seg_v2(const float a1[2], const float a2[2], const float b1[2], const float b2[2]); int isect_seg_seg_v2_int(const int a1[2], const int a2[2], const int b1[2], const int b2[2]); -int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float vi[2]); -bool isect_seg_seg_v2_simple(const float v1[2], const float v2[2], const float v3[2], const float v4[2]); +int isect_seg_seg_v2_point_ex( + const float v0[2], const float v1[2], const float v2[2], const float v3[2], const float endpoint_bias, + float vi[2]); +int isect_seg_seg_v2_point( + const float v0[2], const float v1[2], const float v2[2], const float v3[2], + float vi[2]); +bool isect_seg_seg_v2_simple( + const float v1[2], const float v2[2], const float v3[2], const float v4[2]); int isect_line_sphere_v3(const float l1[3], const float l2[3], const float sp[3], const float r, float r_p1[3], float r_p2[3]); int isect_line_sphere_v2(const float l1[2], const float l2[2], const float sp[2], const float r, float r_p1[2], float r_p2[2]); diff --git a/source/blender/blenlib/BLI_math_inline.h b/source/blender/blenlib/BLI_math_inline.h index 840cf24f8cf..383abda5b2f 100644 --- a/source/blender/blenlib/BLI_math_inline.h +++ b/source/blender/blenlib/BLI_math_inline.h @@ -44,12 +44,7 @@ extern "C" { # define MALWAYS_INLINE MINLINE # else # define MINLINE static inline -# if (defined(__APPLE__) && defined(__ppc__)) - /* static inline __attribute__ here breaks osx ppc gcc42 build */ -# define MALWAYS_INLINE static __attribute__((always_inline)) __attribute__((unused)) -# else -# define MALWAYS_INLINE static inline __attribute__((always_inline)) __attribute__((unused)) -# endif +# define MALWAYS_INLINE static inline __attribute__((always_inline)) __attribute__((unused)) # endif #else # define MINLINE diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 43f414f376a..4fdb33926a2 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -299,6 +299,8 @@ void angle_poly_v3(float *angles, const float *verts[3], int len); void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2]); void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]); +void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2]); +void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3]); void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3]); void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2]); void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3]); diff --git a/source/blender/blenlib/BLI_polyfill2d_beautify.h b/source/blender/blenlib/BLI_polyfill2d_beautify.h index 20e53b080fe..29a900200bb 100644 --- a/source/blender/blenlib/BLI_polyfill2d_beautify.h +++ b/source/blender/blenlib/BLI_polyfill2d_beautify.h @@ -33,8 +33,12 @@ void BLI_polyfill_beautify( /* structs for reuse */ struct MemArena *arena, struct Heap *eheap, struct EdgeHash *eh); -float BLI_polyfill_beautify_quad_rotate_calc( - const float v1[2], const float v2[2], const float v3[2], const float v4[2]); +float BLI_polyfill_beautify_quad_rotate_calc_ex( + const float v1[2], const float v2[2], const float v3[2], const float v4[2], + const bool lock_degenerate); +#define BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4) \ + BLI_polyfill_beautify_quad_rotate_calc_ex(v1, v2, v3, v4, false) + /* avoid realloc's when creating new structures for polyfill ngons */ #define BLI_POLYFILL_ALLOC_NGON_RESERVE 64 diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h index 21b9c75ac35..471d875c9af 100644 --- a/source/blender/blenlib/BLI_rect.h +++ b/source/blender/blenlib/BLI_rect.h @@ -55,6 +55,8 @@ void BLI_rcti_do_minmax_v(struct rcti *rect, const int xy[2]); void BLI_rctf_do_minmax_v(struct rctf *rect, const float xy[2]); void BLI_rctf_transform_pt_v(const rctf *dst, const rctf *src, float xy_dst[2], const float xy_src[2]); +void BLI_rctf_transform_calc_m4_pivot_min_ex(const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y); +void BLI_rctf_transform_calc_m4_pivot_min(const rctf *dst, const rctf *src, float matrix[4][4]); void BLI_rctf_translate(struct rctf *rect, float x, float y); void BLI_rcti_translate(struct rcti *rect, int x, int y); diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h index bb19ed574bb..5701bce51ea 100644 --- a/source/blender/blenlib/BLI_string_utils.h +++ b/source/blender/blenlib/BLI_string_utils.h @@ -39,6 +39,7 @@ extern "C" { #endif #include "BLI_compiler_attrs.h" +#include "BLI_utildefines_variadic.h" struct ListBase; @@ -49,6 +50,24 @@ size_t BLI_split_name_num(char *left, int *nr, const char *name, const char deli void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len); void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len); +/* Join strings, return newly allocated string. */ +char *BLI_string_join_arrayN( + const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +char *BLI_string_join_array_by_sep_charN( + char sep, const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +char *BLI_string_join_array_by_sep_char_with_tableN( + char sep, char *table[], const char *strings[], uint strings_len) ATTR_NONNULL(); +/* Take multiple arguments, pass as (array, length). */ +#define BLI_string_joinN(...) \ + BLI_string_join_arrayN( \ + ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define BLI_string_join_by_sep_charN(sep, ...) \ + BLI_string_join_array_by_sep_charN( \ + sep, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define BLI_string_join_by_sep_char_with_tableN(sep, table, ...) \ + BLI_string_join_array_by_sep_char_with_tableN( \ + sep, table, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) + void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len); bool BLI_uniquename_cb( diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index 746eb922c65..66c7f247f61 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -39,35 +39,12 @@ extern "C" { /* avoid many includes for now */ #include "BLI_sys_types.h" #include "BLI_compiler_compat.h" +#include "BLI_utildefines_variadic.h" #ifndef NDEBUG /* for BLI_assert */ #include <stdio.h> #endif - -/* varargs macros (keep first so others can use) */ -/* --- internal helpers --- */ -#define _VA_NARGS_GLUE(x, y) x y -#define _VA_NARGS_RETURN_COUNT(\ - _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, \ - _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \ - _33_, _34_, _35_, _36_, _37_, _38_, _39_, _40_, _41_, _42_, _43_, _44_, _45_, _46_, _47_, _48_, \ - _49_, _50_, _51_, _52_, _53_, _54_, _55_, _56_, _57_, _58_, _59_, _60_, _61_, _62_, _63_, _64_, \ - count, ...) count -#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args -/* 64 args max */ -#define _VA_NARGS_COUNT(...) _VA_NARGS_EXPAND((__VA_ARGS__, \ - 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, \ - 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \ - 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \ - 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) -#define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count -#define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count) -#define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count) -/* --- expose for re-use --- */ -#define VA_NARGS_CALL_OVERLOAD(name, ...) \ - _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, _VA_NARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__)) - /* useful for finding bad use of min/max */ #if 0 /* gcc only */ diff --git a/source/blender/blenlib/BLI_utildefines_iter.h b/source/blender/blenlib/BLI_utildefines_iter.h new file mode 100644 index 00000000000..094c1a4b3dc --- /dev/null +++ b/source/blender/blenlib/BLI_utildefines_iter.h @@ -0,0 +1,52 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_UTILDEFINES_ITER_H__ +#define __BLI_UTILDEFINES_ITER_H__ + +/** \file BLI_utildefines_iter.h + * \ingroup bli + * + * General looping helpers, use `BLI_FOREACH` prefix. + */ + +/** + * Even value distribution. + * + * \a src must be larger than \a dst, + * \a dst defines the number of iterations, their values are evenly spaced. + * + * The following pairs represent (src, dst) arguments and the values they loop over. + * <pre> + * (19, 4) -> [2, 7, 11. 16] + * (100, 5) -> [9, 29, 49, 69, 89] + * (100, 3) -> [16, 49, 83] + * (100, 100) -> [0..99] + * </pre> + * \note this is mainly useful for numbers that might not divide evenly into eachother. + */ +#define BLI_FOREACH_SPARSE_RANGE(src, dst, i) \ +for (int _src = (src), _src2 = _src * 2, _dst2 = (dst) * 2, _error = _dst2 - _src, i = 0, _delta; \ + ((void)(_delta = divide_floor_i(_error, _dst2)), \ + (void)(i -= _delta), \ + (i < _src)); \ + _error -= (_delta * _dst2) + _src2) + +#endif /* __BLI_UTILDEFINES_ITER_H__ */ diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_utildefines_stack.h index 42b11eb9a2b..15b0029e727 100644 --- a/source/blender/blenlib/BLI_stackdefines.h +++ b/source/blender/blenlib/BLI_utildefines_stack.h @@ -18,10 +18,10 @@ * ***** END GPL LICENSE BLOCK ***** */ -#ifndef __BLI_STACKDEFINES_H__ -#define __BLI_STACKDEFINES_H__ +#ifndef __BLI_UTILDEFINES_STACK_H__ +#define __BLI_UTILDEFINES_STACK_H__ -/** \file BLI_stackdefines.h +/** \file BLI_utildefines_stack.h * \ingroup bli * * Macro's for a simple array based stack @@ -86,4 +86,4 @@ } ((void)0) #endif -#endif /* __BLI_STACKDEFINES_H__ */ +#endif /* __BLI_UTILDEFINES_STACK_H__ */ diff --git a/source/blender/blenlib/BLI_utildefines_variadic.h b/source/blender/blenlib/BLI_utildefines_variadic.h new file mode 100644 index 00000000000..7c15754fd83 --- /dev/null +++ b/source/blender/blenlib/BLI_utildefines_variadic.h @@ -0,0 +1,50 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_UTILDEFINES_VARIADIC_H__ +#define __BLI_UTILDEFINES_VARIADIC_H__ + +/** \file BLI_utildefines_variadic.h + * \ingroup bli + */ + +/* --- internal helpers --- */ +#define _VA_NARGS_GLUE(x, y) x y +#define _VA_NARGS_RETURN_COUNT(\ + _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, \ + _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \ + _33_, _34_, _35_, _36_, _37_, _38_, _39_, _40_, _41_, _42_, _43_, _44_, _45_, _46_, _47_, _48_, \ + _49_, _50_, _51_, _52_, _53_, _54_, _55_, _56_, _57_, _58_, _59_, _60_, _61_, _62_, _63_, _64_, \ + count, ...) count +#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args +#define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count +#define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count) +#define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count) +/* --- expose for re-use --- */ +/* 64 args max */ +#define VA_NARGS_COUNT(...) _VA_NARGS_EXPAND((__VA_ARGS__, \ + 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, \ + 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \ + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \ + 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) +#define VA_NARGS_CALL_OVERLOAD(name, ...) \ + _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, VA_NARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__)) + +#endif /* __BLI_UTILDEFINES_VARIADIC_H__ */ diff --git a/source/blender/blenlib/BLI_vfontdata.h b/source/blender/blenlib/BLI_vfontdata.h index 8a7079b6c5f..0cd50319a33 100644 --- a/source/blender/blenlib/BLI_vfontdata.h +++ b/source/blender/blenlib/BLI_vfontdata.h @@ -52,8 +52,10 @@ typedef struct VChar { } VChar; VFontData *BLI_vfontdata_from_freetypefont(struct PackedFile *pf); +VFontData *BLI_vfontdata_copy(const VFontData *vfont_src, const int flag); VChar *BLI_vfontchar_from_freetypefont(struct VFont *vfont, unsigned long character); +VChar *BLI_vfontchar_copy(const VChar *vchar_src, const int flag); #endif diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index fcb02a86a84..61a1241cd8f 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -192,7 +192,6 @@ set(SRC BLI_sort.h BLI_sort_utils.h BLI_stack.h - BLI_stackdefines.h BLI_strict_flags.h BLI_string.h BLI_string_cursor_utf8.h @@ -204,6 +203,9 @@ set(SRC BLI_threads.h BLI_timecode.h BLI_utildefines.h + BLI_utildefines_iter.h + BLI_utildefines_stack.h + BLI_utildefines_variadic.h BLI_uvproject.h BLI_vfontdata.h BLI_voronoi.h diff --git a/source/blender/blenlib/intern/BLI_dial.c b/source/blender/blenlib/intern/BLI_dial.c index cfbb52847fd..89f18fa10b4 100644 --- a/source/blender/blenlib/intern/BLI_dial.c +++ b/source/blender/blenlib/intern/BLI_dial.c @@ -46,7 +46,7 @@ struct Dial { }; -Dial *BLI_dial_initialize(float start_position[2], float threshold) +Dial *BLI_dial_initialize(const float start_position[2], float threshold) { Dial *dial = MEM_callocN(sizeof(Dial), "dial"); @@ -56,7 +56,7 @@ Dial *BLI_dial_initialize(float start_position[2], float threshold) return dial; } -float BLI_dial_angle(Dial *dial, float current_position[2]) +float BLI_dial_angle(Dial *dial, const float current_position[2]) { float current_direction[2]; diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 69dee12c713..1b2a27e33d8 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -763,6 +763,28 @@ bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreef } /** + * Replaces the key of an item in the \a gh. + * + * Use when a key is re-allocated or it's memory location is changed. + * + * \returns The previous key or NULL if not found, the caller may free if it's needed. + */ +void *BLI_ghash_replace_key(GHash *gh, void *key) +{ + const unsigned int hash = ghash_keyhash(gh, key); + const unsigned int bucket_index = ghash_bucket_index(gh, hash); + GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, bucket_index); + if (e != NULL) { + void *key_prev = e->e.key; + e->e.key = key; + return key_prev; + } + else { + return NULL; + } +} + +/** * Lookup the value of \a key in \a gh. * * \param key The key to lookup. @@ -1434,6 +1456,18 @@ bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp) return ghash_insert_safe_keyonly((GHash *)gs, key, true, keyfreefp); } +/** + * Replaces the key to the set if it's found. + * Matching #BLI_ghash_replace_key + * + * \returns The old key or NULL if not found. + */ +void *BLI_gset_replace_key(GSet *gs, void *key) +{ + return BLI_ghash_replace_key((GHash *)gs, key); +} + + bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp) { return BLI_ghash_remove((GHash *)gs, key, keyfreefp, NULL); diff --git a/source/blender/blenlib/intern/BLI_kdtree.c b/source/blender/blenlib/intern/BLI_kdtree.c index a81f9b28b83..84ac339cc4d 100644 --- a/source/blender/blenlib/intern/BLI_kdtree.c +++ b/source/blender/blenlib/intern/BLI_kdtree.c @@ -674,3 +674,123 @@ finally: if (stack != defaultstack) MEM_freeN(stack); } + +/** + * Use when we want to loop over nodes ordered by index. + * Requires indices to be aligned with nodes. + */ +static uint *kdtree_order(const KDTree *tree) +{ + const KDTreeNode *nodes = tree->nodes; + uint *order = MEM_mallocN(sizeof(uint) * tree->totnode, __func__); + for (uint i = 0; i < tree->totnode; i++) { + order[nodes[i].index] = i; + } + return order; +} + +/* -------------------------------------------------------------------- */ +/** \name BLI_kdtree_calc_duplicates_fast + * \{ */ + +struct DeDuplicateParams { + /* Static */ + const KDTreeNode *nodes; + float range; + float range_sq; + int *duplicates; + int *duplicates_found; + + /* Per Search */ + float search_co[3]; + int search; +}; + +static void deduplicate_recursive(const struct DeDuplicateParams *p, uint i) +{ + const KDTreeNode *node = &p->nodes[i]; + if (p->search_co[node->d] + p->range <= node->co[node->d]) { + if (node->left != KD_NODE_UNSET) { + deduplicate_recursive(p, node->left); + } + } + else if (p->search_co[node->d] - p->range >= node->co[node->d]) { + if (node->right != KD_NODE_UNSET) { + deduplicate_recursive(p, node->right); + } + } + else { + if ((p->search != node->index) && (p->duplicates[node->index] == -1)) { + if (compare_len_squared_v3v3(node->co, p->search_co, p->range_sq)) { + p->duplicates[node->index] = (int)p->search; + *p->duplicates_found += 1; + } + } + if (node->left != KD_NODE_UNSET) { + deduplicate_recursive(p, node->left); + } + if (node->right != KD_NODE_UNSET) { + deduplicate_recursive(p, node->right); + } + } +} + +/** + * Find duplicate points in \a range. + * Favors speed over quality since it doesn't find the best target vertex for merging. + * Nodes are looped over, duplicates are added when found. + * Nevertheless results are predictable. + * + * \param range: Coordinates in this range are candidates to be merged. + * \param use_index_order: Loop over the coordinates ordered by #KDTreeNode.index + * At the expense of some performance, this ensures the layout of the tree doesn't influence + * the iteration order. + * \param duplicates: An array of int's the length of #KDTree.totnode + * Values initialized to -1 are candidates to me merged. + * Setting the index to it's own position in the array prevents it from being touched, + * although it can still be used as a target. + * \returns The numebr of merges found (includes any merges already in the \a duplicates array). + * + * \note Merging is always a single step (target indices wont be marked for merging). + */ +int BLI_kdtree_calc_duplicates_fast( + const KDTree *tree, const float range, bool use_index_order, + int *duplicates) +{ + int found = 0; + struct DeDuplicateParams p = { + .nodes = tree->nodes, + .range = range, + .range_sq = range * range, + .duplicates = duplicates, + .duplicates_found = &found, + }; + + if (use_index_order) { + uint *order = kdtree_order(tree); + for (uint i = 0; i < tree->totnode; i++) { + const uint node_index = order[i]; + const int index = (int)i; + if (ELEM(duplicates[index], -1, index)) { + p.search = index; + copy_v3_v3(p.search_co, tree->nodes[node_index].co); + deduplicate_recursive(&p, tree->root); + } + } + MEM_freeN(order); + } + else { + for (uint i = 0; i < tree->totnode; i++) { + const uint node_index = i; + const int index = p.nodes[node_index].index; + if (ELEM(duplicates[index], -1, index)) { + p.search = index; + copy_v3_v3(p.search_co, tree->nodes[node_index].co); + deduplicate_recursive(&p, tree->root); + } + } + } + return found; +} + +/** \} */ diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c index 8719c92a2a6..e990f0b663c 100644 --- a/source/blender/blenlib/intern/freetypefont.c +++ b/source/blender/blenlib/intern/freetypefont.c @@ -481,6 +481,22 @@ VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf) return vfd; } +static void *vfontdata_copy_characters_value_cb(const void *src) +{ + return BLI_vfontchar_copy(src, 0); +} + +VFontData *BLI_vfontdata_copy(const VFontData *vfont_src, const int UNUSED(flag)) +{ + VFontData *vfont_dst = MEM_dupallocN(vfont_src); + + if (vfont_src->characters != NULL) { + vfont_dst->characters = BLI_ghash_copy(vfont_src->characters, NULL, vfontdata_copy_characters_value_cb); + } + + return vfont_dst; +} + VChar *BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character) { VChar *che = NULL; @@ -503,6 +519,20 @@ VChar *BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character) return che; } +/* Yeah, this is very bad... But why is this in BLI in the first place, since it uses Nurb data? + * Anyway, do not feel like duplicating whole Nurb copy code here, so unless someone has a better idea... */ +#include "../../blenkernel/BKE_curve.h" + +VChar *BLI_vfontchar_copy(const VChar *vchar_src, const int UNUSED(flag)) +{ + VChar *vchar_dst = MEM_dupallocN(vchar_src); + + BLI_listbase_clear(&vchar_dst->nurbsbase); + BKE_nurbList_duplicate(&vchar_dst->nurbsbase, &vchar_src->nurbsbase); + + return vchar_dst; +} + #if 0 /* Freetype2 Outline struct */ diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 8d2d80c2a35..749c18fc0ce 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -33,6 +33,7 @@ #include <float.h> #include <stdio.h> #include <stdlib.h> +#include <limits.h> #ifdef __SSE2__ # include <emmintrin.h> @@ -181,11 +182,59 @@ MINLINE unsigned power_of_2_min_u(unsigned x) return x - (x >> 1); } -MINLINE int iroundf(float a) -{ - return (int)floorf(a + 0.5f); +/* rounding and clamping */ + +#define _round_clamp_fl_impl(arg, ty, min, max) { \ + float r = floorf(arg + 0.5f); \ + if (UNLIKELY(r <= (float)min)) return (ty)min; \ + else if (UNLIKELY(r >= (float)max)) return (ty)max; \ + else return (ty)r; \ +} + +#define _round_clamp_db_impl(arg, ty, min, max) { \ + double r = floor(arg + 0.5); \ + if (UNLIKELY(r <= (double)min)) return (ty)min; \ + else if (UNLIKELY(r >= (double)max)) return (ty)max; \ + else return (ty)r; \ } +#define _round_fl_impl(arg, ty) { return (ty)floorf(arg + 0.5f); } +#define _round_db_impl(arg, ty) { return (ty)floor(arg + 0.5); } + +MINLINE signed char round_fl_to_char(float a) { _round_fl_impl(a, signed char) } +MINLINE unsigned char round_fl_to_uchar(float a) { _round_fl_impl(a, unsigned char) } +MINLINE short round_fl_to_short(float a) { _round_fl_impl(a, short) } +MINLINE unsigned short round_fl_to_ushort(float a) { _round_fl_impl(a, unsigned short) } +MINLINE int round_fl_to_int(float a) { _round_fl_impl(a, int) } +MINLINE unsigned int round_fl_to_uint(float a) { _round_fl_impl(a, unsigned int) } + +MINLINE signed char round_db_to_char(double a) { _round_db_impl(a, signed char) } +MINLINE unsigned char round_db_to_uchar(double a) { _round_db_impl(a, unsigned char) } +MINLINE short round_db_to_short(double a) { _round_db_impl(a, short) } +MINLINE unsigned short round_db_to_ushort(double a) { _round_db_impl(a, unsigned short) } +MINLINE int round_db_to_int(double a) { _round_db_impl(a, int) } +MINLINE unsigned int round_db_to_uint(double a) { _round_db_impl(a, unsigned int) } + +#undef _round_fl_impl +#undef _round_db_impl + +MINLINE signed char round_fl_to_char_clamp(float a) { _round_clamp_fl_impl(a, signed char, SCHAR_MIN, SCHAR_MAX) } +MINLINE unsigned char round_fl_to_uchar_clamp(float a) { _round_clamp_fl_impl(a, unsigned char, 0, UCHAR_MAX) } +MINLINE short round_fl_to_short_clamp(float a) { _round_clamp_fl_impl(a, short, SHRT_MIN, SHRT_MAX) } +MINLINE unsigned short round_fl_to_ushort_clamp(float a) { _round_clamp_fl_impl(a, unsigned short, 0, USHRT_MAX) } +MINLINE int round_fl_to_int_clamp(float a) { _round_clamp_fl_impl(a, int, INT_MIN, INT_MAX) } +MINLINE unsigned int round_fl_to_uint_clamp(float a) { _round_clamp_fl_impl(a, unsigned int, 0, UINT_MAX) } + +MINLINE signed char round_db_to_char_clamp(double a) { _round_clamp_db_impl(a, signed char, SCHAR_MIN, SCHAR_MAX) } +MINLINE unsigned char round_db_to_uchar_clamp(double a) { _round_clamp_db_impl(a, unsigned char, 0, UCHAR_MAX) } +MINLINE short round_db_to_short_clamp(double a) { _round_clamp_db_impl(a, short, SHRT_MIN, SHRT_MAX) } +MINLINE unsigned short round_db_to_ushort_clamp(double a) { _round_clamp_db_impl(a, unsigned short, 0, USHRT_MAX) } +MINLINE int round_db_to_int_clamp(double a) { _round_clamp_db_impl(a, int, INT_MIN, INT_MAX) } +MINLINE unsigned int round_db_to_uint_clamp(double a) { _round_clamp_db_impl(a, unsigned int, 0, UINT_MAX) } + +#undef _round_clamp_fl_impl +#undef _round_clamp_db_impl + /* integer division that rounds 0.5 up, particularly useful for color blending * with integers, to avoid gradual darkening when rounding down */ MINLINE int divide_round_i(int a, int b) @@ -194,6 +243,17 @@ MINLINE int divide_round_i(int a, int b) } /** + * Integer division that floors negative result. + * \note This works like Python's int division. + */ +MINLINE int divide_floor_i(int a, int b) +{ + int d = a / b; + int r = a % b; /* Optimizes into a single division. */ + return r ? d - ((a < 0) ^ (b < 0)) : d; +} + +/** * modulo that handles negative numbers, works the same as Python's. */ MINLINE int mod_i(int i, int n) @@ -314,6 +374,21 @@ MINLINE int signum_i(float a) else return 0; } +/** Returns number of (base ten) *significant* digits of integer part of given float + * (negative in case of decimal-only floats, 0.01 returns -1 e.g.). */ +MINLINE int integer_digits_f(const float f) +{ + return (f == 0.0f) ? 0 : (int)floor(log10(fabs(f))) + 1; +} + +/** Returns number of (base ten) *significant* digits of integer part of given double + * (negative in case of decimal-only floats, 0.01 returns -1 e.g.). */ +MINLINE int integer_digits_d(const double d) +{ + return (d == 0.0) ? 0 : (int)floor(log10(fabs(d))) + 1; +} + + /* Internal helpers for SSE2 implementation. * * NOTE: Are to be called ONLY from inside `#ifdef __SSE2__` !!! diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 630eaed05db..30164ff9f6a 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -765,18 +765,29 @@ int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], co return ISECT_LINE_LINE_NONE; } -/* get intersection point of two 2D segments and return intersection type: - * -1: collinear - * 1: intersection +/** + * Get intersection point of two 2D segments. + * + * \param endpoint_bias: Bias to use when testing for end-point overlap. + * A positive value considers intersections that extend past the endpoints, + * negative values contract the endpoints. + * Note the bias is applied to a 0-1 factor, not scaled to the length of segments. + * + * \returns intersection type: + * - -1: collinear. + * - 1: intersection. + * - 0: no intersection. */ -int isect_seg_seg_v2_point( +int isect_seg_seg_v2_point_ex( const float v0[2], const float v1[2], const float v2[2], const float v3[2], + const float endpoint_bias, float r_vi[2]) { float s10[2], s32[2], s30[2], d; const float eps = 1e-6f; - const float eps_sq = eps * eps; + const float endpoint_min = -endpoint_bias; + const float endpoint_max = endpoint_bias + 1.0f; sub_v2_v2v2(s10, v1, v0); sub_v2_v2v2(s32, v3, v2); @@ -790,8 +801,8 @@ int isect_seg_seg_v2_point( u = cross_v2v2(s30, s32) / d; v = cross_v2v2(s10, s30) / d; - if ((u >= -eps && u <= 1.0f + eps) && - (v >= -eps && v <= 1.0f + eps)) + if ((u >= endpoint_min && u <= endpoint_max) && + (v >= endpoint_min && v <= endpoint_max)) { /* intersection */ float vi_test[2]; @@ -810,7 +821,7 @@ int isect_seg_seg_v2_point( sub_v2_v2v2(s_vi_v2, vi_test, v2); v = (dot_v2v2(s32, s_vi_v2) / dot_v2v2(s32, s32)); #endif - if (v >= -eps && v <= 1.0f + eps) { + if (v >= endpoint_min && v <= endpoint_max) { copy_v2_v2(r_vi, vi_test); return 1; } @@ -828,7 +839,7 @@ int isect_seg_seg_v2_point( float u_a, u_b; if (equals_v2v2(v0, v1)) { - if (len_squared_v2v2(v2, v3) > eps_sq) { + if (len_squared_v2v2(v2, v3) > SQUARE(eps)) { /* use non-point segment as basis */ SWAP(const float *, v0, v2); SWAP(const float *, v1, v3); @@ -855,7 +866,7 @@ int isect_seg_seg_v2_point( if (u_a > u_b) SWAP(float, u_a, u_b); - if (u_a > 1.0f + eps || u_b < -eps) { + if (u_a > endpoint_max || u_b < endpoint_min) { /* non-overlapping segments */ return -1; } @@ -871,6 +882,15 @@ int isect_seg_seg_v2_point( } } +int isect_seg_seg_v2_point( + const float v0[2], const float v1[2], + const float v2[2], const float v3[2], + float r_vi[2]) +{ + const float endpoint_bias = 1e-6f; + return isect_seg_seg_v2_point_ex(v0, v1, v2, v3, endpoint_bias, r_vi); +} + bool isect_seg_seg_v2_simple(const float v1[2], const float v2[2], const float v3[2], const float v4[2]) { #define CCW(A, B, C) \ diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index f47f9ad76e6..d1a219c196a 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -1663,6 +1663,9 @@ void rotate_m4(float mat[4][4], const char axis, const float angle) mat[0][col] = temp; } break; + default: + BLI_assert(0); + break; } } diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index c6e9b8229ba..5f44c93e169 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -652,6 +652,31 @@ void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]) } /** + * Project \a p onto a unit length \a v_proj + */ +void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2]) +{ + BLI_ASSERT_UNIT_V2(v_proj); + const float mul = dot_v2v2(p, v_proj); + + out[0] = mul * v_proj[0]; + out[1] = mul * v_proj[1]; +} + +/** + * Project \a p onto a unit length \a v_proj + */ +void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3]) +{ + BLI_ASSERT_UNIT_V3(v_proj); + const float mul = dot_v3v3(p, v_proj); + + out[0] = mul * v_proj[0]; + out[1] = mul * v_proj[1]; + out[2] = mul * v_proj[2]; +} + +/** * In this case plane is a 3D vector only (no 4th component). * * Projecting will make \a c a copy of \a v orthogonal to \a v_plane. diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c index 347640aae0d..86c24307ae2 100644 --- a/source/blender/blenlib/intern/noise.c +++ b/source/blender/blenlib/intern/noise.c @@ -1395,9 +1395,9 @@ static float voronoi_CrS(float x, float y, float z) static float cellNoiseU(float x, float y, float z) { /* avoid precision issues on unit coordinates */ - x = (x + 0.000001f)*0.999999f; - y = (y + 0.000001f)*0.999999f; - z = (z + 0.000001f)*0.999999f; + x = (x + 0.000001f)*1.00001f; + y = (y + 0.000001f)*1.00001f; + z = (z + 0.000001f)*1.00001f; int xi = (int)(floor(x)); int yi = (int)(floor(y)); @@ -1417,9 +1417,9 @@ float cellNoise(float x, float y, float z) void cellNoiseV(float x, float y, float z, float ca[3]) { /* avoid precision issues on unit coordinates */ - x = (x + 0.000001f)*0.999999f; - y = (y + 0.000001f)*0.999999f; - z = (z + 0.000001f)*0.999999f; + x = (x + 0.000001f)*1.00001f; + y = (y + 0.000001f)*1.00001f; + z = (z + 0.000001f)*1.00001f; int xi = (int)(floor(x)); int yi = (int)(floor(y)); diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c index 5f9b92198a5..018e2f9be5a 100644 --- a/source/blender/blenlib/intern/polyfill2d.c +++ b/source/blender/blenlib/intern/polyfill2d.c @@ -411,11 +411,11 @@ static bool kdtree2d_isect_tri_recursive( } #define KDTREE2D_ISECT_TRI_RECURSE_NEG \ - (((node->neg != KDNODE_UNSET) && (co[node->axis] > bounds[node->axis].min)) && \ + (((node->neg != KDNODE_UNSET) && (co[node->axis] >= bounds[node->axis].min)) && \ (kdtree2d_isect_tri_recursive(tree, tri_index, tri_coords, tri_center, bounds, \ &tree->nodes[node->neg]))) #define KDTREE2D_ISECT_TRI_RECURSE_POS \ - (((node->pos != KDNODE_UNSET) && (co[node->axis] < bounds[node->axis].max)) && \ + (((node->pos != KDNODE_UNSET) && (co[node->axis] <= bounds[node->axis].max)) && \ (kdtree2d_isect_tri_recursive(tree, tri_index, tri_coords, tri_center, bounds, \ &tree->nodes[node->pos]))) @@ -698,12 +698,12 @@ static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip) /* check if counting is wrong */ { uint coords_tot_concave_test = 0; - uint i = pf->coords_tot; - while (i--) { - if (coords_sign[indices[i]] != CONVEX) { + PolyIndex *pi_iter = pi_ear_tip; + do { + if (pi_iter->sign != CONVEX) { coords_tot_concave_test += 1; } - } + } while ((pi_iter = pi_iter->next) != pi_ear_tip); BLI_assert(coords_tot_concave_test == pf->coords_tot_concave); } #endif diff --git a/source/blender/blenlib/intern/polyfill2d_beautify.c b/source/blender/blenlib/intern/polyfill2d_beautify.c index 896177f436c..5f6fb8e6cd4 100644 --- a/source/blender/blenlib/intern/polyfill2d_beautify.c +++ b/source/blender/blenlib/intern/polyfill2d_beautify.c @@ -121,45 +121,53 @@ BLI_INLINE bool is_boundary_edge(unsigned int i_a, unsigned int i_b, const unsig * Assuming we have 2 triangles sharing an edge (2 - 4), * check if the edge running from (1 - 3) gives better results. * + * \param lock_degenerate: Use to avoid rotating out of a degenerate state. + * - When true, an existing zero area face on either side of the (2 - 4) split will return a positive value. + * - When false, the check must be non-biased towards either split direction. + * * \return (negative number means the edge can be rotated, lager == better). */ -float BLI_polyfill_beautify_quad_rotate_calc( - const float v1[2], const float v2[2], const float v3[2], const float v4[2]) +float BLI_polyfill_beautify_quad_rotate_calc_ex( + const float v1[2], const float v2[2], const float v3[2], const float v4[2], + const bool lock_degenerate) { /* not a loop (only to be able to break out) */ do { - bool is_zero_a, is_zero_b; - + /* Allow very small faces to be considered non-zero. */ + const float eps_zero_area = 1e-12f; const float area_2x_234 = cross_tri_v2(v2, v3, v4); const float area_2x_241 = cross_tri_v2(v2, v4, v1); const float area_2x_123 = cross_tri_v2(v1, v2, v3); const float area_2x_134 = cross_tri_v2(v1, v3, v4); - { - BLI_assert((ELEM(v1, v2, v3, v4) == false) && - (ELEM(v2, v1, v3, v4) == false) && - (ELEM(v3, v1, v2, v4) == false) && - (ELEM(v4, v1, v2, v3) == false)); - - is_zero_a = (fabsf(area_2x_234) <= FLT_EPSILON); - is_zero_b = (fabsf(area_2x_241) <= FLT_EPSILON); - - if (is_zero_a && is_zero_b) { - break; - } + BLI_assert((ELEM(v1, v2, v3, v4) == false) && + (ELEM(v2, v1, v3, v4) == false) && + (ELEM(v3, v1, v2, v4) == false) && + (ELEM(v4, v1, v2, v3) == false)); + /* + * Test for unusable (1-3) state. + * - Area sign flipping to check faces aren't going to point in opposite directions. + * - Area epsilon check that the one of the faces won't be zero area. + */ + if ((area_2x_123 >= 0.0f) != (area_2x_134 >= 0.0f)) { + break; } - - /* one of the tri's was degenerate, check we're not rotating - * into a different degenerate shape or flipping the face */ - if ((fabsf(area_2x_123) <= FLT_EPSILON) || (fabsf(area_2x_134) <= FLT_EPSILON)) { - /* one of the new rotations is degenerate */ + else if ((fabsf(area_2x_123) <= eps_zero_area) || (fabsf(area_2x_134) <= eps_zero_area)) { break; } - if ((area_2x_123 >= 0.0f) != (area_2x_134 >= 0.0f)) { - /* rotation would cause flipping */ - break; + /* Test for unusable (2-4) state (same as above). */ + if ((area_2x_234 >= 0.0f) != (area_2x_241 >= 0.0f)) { + if (lock_degenerate) { + break; + } + else { + return -FLT_MAX; /* always rotate */ + } + } + else if ((fabsf(area_2x_234) <= eps_zero_area) || (fabsf(area_2x_241) <= eps_zero_area)) { + return -FLT_MAX; /* always rotate */ } { diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c index e0c4cbe9990..3adc6b30f6e 100644 --- a/source/blender/blenlib/intern/rct.c +++ b/source/blender/blenlib/intern/rct.c @@ -32,6 +32,7 @@ * A minimalist lib for functions doing stuff with rectangle structs. */ +#include <stdlib.h> #include <stdio.h> #include <math.h> @@ -41,6 +42,9 @@ #include "DNA_vec_types.h" #include "BLI_rect.h" +/* avoid including BLI_math */ +static void unit_m4(float m[4][4]); + /** * Determine if a rect is empty. An empty * rect is one with a zero (or negative) @@ -405,6 +409,31 @@ void BLI_rctf_transform_pt_v(const rctf *dst, const rctf *src, float xy_dst[2], xy_dst[1] = dst->ymin + ((dst->ymax - dst->ymin) * xy_dst[1]); } +/** + * Calculate a 4x4 matrix representing the transformation between two rectangles. + * + * \note Multiplying a vector by this matrix does *not* give the same value as #BLI_rctf_transform_pt_v. + */ +void BLI_rctf_transform_calc_m4_pivot_min_ex( + const rctf *dst, const rctf *src, float matrix[4][4], + uint x, uint y) +{ + BLI_assert(x < 3 && y < 3); + + unit_m4(matrix); + + matrix[x][x] = BLI_rctf_size_x(src) / BLI_rctf_size_x(dst); + matrix[y][y] = BLI_rctf_size_y(src) / BLI_rctf_size_y(dst); + matrix[3][x] = (src->xmin - dst->xmin) * matrix[x][x]; + matrix[3][y] = (src->ymin - dst->ymin) * matrix[y][y]; +} + +void BLI_rctf_transform_calc_m4_pivot_min( + const rctf *dst, const rctf *src, float matrix[4][4]) +{ + BLI_rctf_transform_calc_m4_pivot_min_ex(dst, src, matrix, 0, 1); +} + void BLI_rcti_translate(rcti *rect, int x, int y) { rect->xmin += x; @@ -763,3 +792,12 @@ void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle) #undef ROTATE_SINCOS /** \} */ + +static void unit_m4(float m[4][4]) +{ + m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f; + m[0][1] = m[0][2] = m[0][3] = 0.0f; + m[1][0] = m[1][2] = m[1][3] = 0.0f; + m[2][0] = m[2][1] = m[2][3] = 0.0f; + m[3][0] = m[3][1] = m[3][2] = 0.0f; +} diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index b819c513fbd..a48c8b074dd 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -37,14 +37,10 @@ #include <sys/stat.h> -#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || defined(__sun) +#if defined(__NetBSD__) || defined(__DragonFly__) /* Other modern unix os's should probably use this also */ # include <sys/statvfs.h> # define USE_STATFS_STATVFS -#elif (defined(__sparc) || defined(__sparc__)) && !defined(__FreeBSD__) && !defined(__linux__) -# include <sys/statfs.h> - /* 4 argument version (not common) */ -# define USE_STATFS_4ARGS #endif #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c index 8d91a55a5ad..a693463a302 100644 --- a/source/blender/blenlib/intern/string_utils.c +++ b/source/blender/blenlib/intern/string_utils.c @@ -383,3 +383,91 @@ bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim return BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len); } + +/* ------------------------------------------------------------------------- */ +/** \name Join Strings + * + * For non array versions of these functions, use the macros: + * - #BLI_string_joinN + * - #BLI_string_join_by_sep_charN + * - #BLI_string_join_by_sep_char_with_tableN + * + * \{ */ + +/** + * Join an array of strings into a newly allocated, null terminated string. + */ +char *BLI_string_join_arrayN( + const char *strings[], uint strings_len) +{ + uint total_len = 1; + for (uint i = 0; i < strings_len; i++) { + total_len += strlen(strings[i]); + } + char *result = MEM_mallocN(sizeof(char) * total_len, __func__); + char *c = result; + for (uint i = 0; i < strings_len; i++) { + c += BLI_strcpy_rlen(c, strings[i]); + } + return result; +} + +/** + * A version of #BLI_string_joinN that takes a separator which can be any character including '\0'. + */ +char *BLI_string_join_array_by_sep_charN( + char sep, const char *strings[], uint strings_len) +{ + uint total_len = 0; + for (uint i = 0; i < strings_len; i++) { + total_len += strlen(strings[i]) + 1; + } + if (total_len == 0) { + total_len = 1; + } + + char *result = MEM_mallocN(sizeof(char) * total_len, __func__); + char *c = result; + if (strings_len != 0) { + for (uint i = 0; i < strings_len; i++) { + c += BLI_strcpy_rlen(c, strings[i]); + *c = sep; + c++; + } + c--; + } + *c = '\0'; + return result; +} + +/** + * A version of #BLI_string_join_array_by_sep_charN that takes a table array. + * The new location of each string is written into this array. + */ +char *BLI_string_join_array_by_sep_char_with_tableN( + char sep, char *table[], const char *strings[], uint strings_len) +{ + uint total_len = 0; + for (uint i = 0; i < strings_len; i++) { + total_len += strlen(strings[i]) + 1; + } + if (total_len == 0) { + total_len = 1; + } + + char *result = MEM_mallocN(sizeof(char) * total_len, __func__); + char *c = result; + if (strings_len != 0) { + for (uint i = 0; i < strings_len; i++) { + table[i] = c; /* <-- only difference to BLI_string_join_array_by_sep_charN. */ + c += BLI_strcpy_rlen(c, strings[i]); + *c = sep; + c++; + } + c--; + } + *c = '\0'; + return result; +} + +/** \} */ diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c index e755a7ae52c..7856bad4d99 100644 --- a/source/blender/blenlib/intern/timecode.c +++ b/source/blender/blenlib/intern/timecode.c @@ -94,11 +94,11 @@ size_t BLI_timecode_string_from_time( * to cope with 'half' frames, etc., which should be fine in most cases */ seconds = (int)time; - frames = iroundf((float)(((double)time - (double)seconds) * fps)); + frames = round_fl_to_int((float)(((double)time - (double)seconds) * fps)); } else { /* seconds (with pixel offset rounding) */ - seconds = iroundf(time); + seconds = round_fl_to_int(time); } switch (timecode_style) { @@ -169,7 +169,7 @@ size_t BLI_timecode_string_from_time( /* precision of decimal part */ const int ms_dp = (power <= 0) ? (1 - power) : 1; - const int ms = iroundf((time - (float)seconds) * 1000.0f); + const int ms = round_fl_to_int((time - (float)seconds) * 1000.0f); rlen = BLI_snprintf_rlen( str, maxncpy, "%s%02d:%02d:%02d,%0*d", neg, hours, minutes, seconds, ms_dp, ms); @@ -183,7 +183,7 @@ size_t BLI_timecode_string_from_time( rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds); } else { - rlen = BLI_snprintf_rlen(str, maxncpy, "%d", iroundf(time_seconds)); + rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds)); } break; } @@ -250,7 +250,7 @@ size_t BLI_timecode_string_from_time_seconds( rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds); } else { - rlen = BLI_snprintf_rlen(str, maxncpy, "%d", iroundf(time_seconds)); + rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds)); } return rlen; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f224f0b5633..3b7662be2b2 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -638,7 +638,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab /* Add library datablock itself to 'main' Main, since libraries are **never** linked data. * Fixes bug where you could end with all ID_LI datablocks having the same name... */ - lib = BKE_libblock_alloc(mainlist->first, ID_LI, "Lib"); + lib = BKE_libblock_alloc(mainlist->first, ID_LI, "Lib", 0); lib->id.us = ID_FAKE_USERS(lib); /* Important, consistency with main ID reading code from read_libblock(). */ BLI_strncpy(lib->name, filepath, sizeof(lib->name)); BLI_strncpy(lib->filepath, name1, sizeof(lib->filepath)); @@ -6003,16 +6003,6 @@ static void direct_link_scene(FileData *fd, Scene *sce) sce->toolsettings->particle.scene = NULL; sce->toolsettings->particle.object = NULL; sce->toolsettings->gp_sculpt.paintcursor = NULL; - - /* in rare cases this is needed, see [#33806] */ - if (sce->toolsettings->vpaint) { - sce->toolsettings->vpaint->vpaint_prev = NULL; - sce->toolsettings->vpaint->tot = 0; - } - if (sce->toolsettings->wpaint) { - sce->toolsettings->wpaint->wpaint_prev = NULL; - sce->toolsettings->wpaint->tot = 0; - } /* relink grease pencil drawing brushes */ link_list(fd, &sce->toolsettings->gp_brushes); @@ -6162,11 +6152,6 @@ static void direct_link_scene(FileData *fd, Scene *sce) sce->r.avicodecdata->lpFormat = newdataadr(fd, sce->r.avicodecdata->lpFormat); sce->r.avicodecdata->lpParms = newdataadr(fd, sce->r.avicodecdata->lpParms); } - - sce->r.qtcodecdata = newdataadr(fd, sce->r.qtcodecdata); - if (sce->r.qtcodecdata) { - sce->r.qtcodecdata->cdParms = newdataadr(fd, sce->r.qtcodecdata->cdParms); - } if (sce->r.ffcodecdata.properties) { sce->r.ffcodecdata.properties = newdataadr(fd, sce->r.ffcodecdata.properties); IDP_DirectLinkGroup_OrFree(&sce->r.ffcodecdata.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); @@ -9912,6 +9897,8 @@ void BLO_expand_main(void *fdhandle, Main *mainvar) case ID_CF: expand_cachefile(fd, mainvar, (CacheFile *)id); break; + default: + break; } do_it = true; diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 94d335870ca..8459e080f99 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -60,6 +60,7 @@ #include "DNA_genfile.h" #include "BKE_animsys.h" +#include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_library.h" #include "BKE_main.h" @@ -1652,6 +1653,23 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } + { + Brush *br; + br = (Brush *)BKE_libblock_find_name_ex(main, ID_BR, "Average"); + if (!br) { + br = BKE_brush_add(main, "Average", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT); + br->vertexpaint_tool = PAINT_BLEND_AVERAGE; + br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT; + } + + br = (Brush *)BKE_libblock_find_name_ex(main, ID_BR, "Smear"); + if (!br) { + br = BKE_brush_add(main, "Smear", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT); + br->vertexpaint_tool = PAINT_BLEND_SMEAR; + br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT; + } + } + FOREACH_NODETREE(main, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { do_versions_compositor_render_passes(ntree); @@ -1659,7 +1677,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END } - { + if (!MAIN_VERSION_ATLEAST(main, 279, 0)) { for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { if (scene->r.im_format.exr_codec == R_IMF_EXR_CODEC_DWAB) { scene->r.im_format.exr_codec = R_IMF_EXR_CODEC_DWAA; @@ -1671,12 +1689,23 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) CustomData_set_layer_name(&me->vdata, CD_MDEFORMVERT, 0, ""); } } + + { + /* Fix for invalid state of screen due to bug in older versions. */ + for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) { + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + if(sa->full && sc->state == SCREENNORMAL) { + sa->full = NULL; + } + } + } + } } void do_versions_after_linking_270(Main *main) { /* To be added to next subversion bump! */ - { + if (!MAIN_VERSION_ATLEAST(main, 279, 0)) { FOREACH_NODETREE(main, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { ntreeSetTypes(NULL, ntree); diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index e7e0054e7a1..3d3e73eb470 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -58,6 +58,9 @@ void BLO_update_defaults_userpref_blend(void) U.uiflag |= USER_QUIT_PROMPT; U.uiflag |= USER_CONTINUOUS_MOUSE; + /* See T45301 */ + U.uiflag |= USER_LOCK_CURSOR_ADJUST; + U.versions = 1; U.savetime = 2; @@ -106,6 +109,16 @@ void BLO_update_defaults_startup_blend(Main *bmain) sculpt->detail_size = 12; } + if (ts->vpaint) { + VPaint *vp = ts->vpaint; + vp->radial_symm[0] = vp->radial_symm[1] = vp->radial_symm[2] = 1; + } + + if (ts->wpaint) { + VPaint *wp = ts->wpaint; + wp->radial_symm[0] = wp->radial_symm[1] = wp->radial_symm[2] = 1; + } + if (ts->gp_sculpt.brush[0].size == 0) { GP_BrushEdit_Settings *gset = &ts->gp_sculpt; GP_EditBrush_Data *brush; @@ -233,6 +246,20 @@ void BLO_update_defaults_startup_blend(Main *bmain) br->ob_mode = OB_MODE_TEXTURE_PAINT; } + /* Vertex/Weight Paint */ + br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Average"); + if (!br) { + br = BKE_brush_add(bmain, "Average", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT); + br->vertexpaint_tool = PAINT_BLEND_AVERAGE; + br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT; + } + br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Smear"); + if (!br) { + br = BKE_brush_add(bmain, "Smear", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT); + br->vertexpaint_tool = PAINT_BLEND_SMEAR; + br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT; + } + br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Mask"); if (br) { br->imagepaint_tool = PAINT_TOOL_MASK; diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index c29ffbb76f2..ad37679800b 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -2911,12 +2911,12 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) Scene *sce; for (sce = main->scene.first; sce; sce = sce->id.next) { if (sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[1] || - sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[2] || - sce->toolsettings->skgen_subdivisions[1] == sce->toolsettings->skgen_subdivisions[2]) + sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[2] || + sce->toolsettings->skgen_subdivisions[1] == sce->toolsettings->skgen_subdivisions[2]) { - sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION; - sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH; - sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE; + sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION; + sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH; + sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE; } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ee9665dc834..2648ebdc395 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2688,13 +2688,6 @@ static void write_scene(WriteData *wd, Scene *sce) writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms); } } - - if (sce->r.qtcodecdata) { - writestruct(wd, DATA, QuicktimeCodecData, 1, sce->r.qtcodecdata); - if (sce->r.qtcodecdata->cdParms) { - writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms); - } - } if (sce->r.ffcodecdata.properties) { IDP_WriteProperty(sce->r.ffcodecdata.properties, wd); } @@ -3841,6 +3834,9 @@ static bool write_file_handle( } for (; id; id = id->next) { + /* We should never attempt to write non-regular IDs (i.e. all kind of temp/runtime ones). */ + BLI_assert((id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0); + switch ((ID_Type)GS(id->name)) { case ID_WM: write_windowmanager(wd, (wmWindowManager *)id); diff --git a/source/blender/blentranslation/CMakeLists.txt b/source/blender/blentranslation/CMakeLists.txt index c0dce5b4f0d..320a784ea25 100644 --- a/source/blender/blentranslation/CMakeLists.txt +++ b/source/blender/blentranslation/CMakeLists.txt @@ -61,4 +61,6 @@ endif() blender_add_lib(bf_blentranslation "${SRC}" "${INC}" "${INC_SYS}") -add_subdirectory(msgfmt) +if(WITH_INTERNATIONAL) + add_subdirectory(msgfmt) +endif() diff --git a/source/blender/blentranslation/msgfmt/msgfmt.c b/source/blender/blentranslation/msgfmt/msgfmt.c index 487d9fee7b4..3abce7b1d3f 100644 --- a/source/blender/blentranslation/msgfmt/msgfmt.c +++ b/source/blender/blentranslation/msgfmt/msgfmt.c @@ -160,7 +160,8 @@ static char **get_keys_sorted(GHash *messages, const uint32_t num_keys) return keys; } -BLI_INLINE size_t uint32_to_bytes(const int value, char *bytes) { +BLI_INLINE size_t uint32_to_bytes(const int value, char *bytes) +{ size_t i; for (i = 0; i < sizeof(value); i++) { bytes[i] = (char) ((value >> ((int)i * 8)) & 0xff); @@ -168,7 +169,8 @@ BLI_INLINE size_t uint32_to_bytes(const int value, char *bytes) { return i; } -BLI_INLINE size_t msg_to_bytes(char *msg, char *bytes, uint32_t size) { +BLI_INLINE size_t msg_to_bytes(char *msg, char *bytes, uint32_t size) +{ /* Note that we also perform replacing of our NULLSEP placeholder by real NULL char... */ size_t i; for (i = 0; i < size; i++, msg++, bytes++) { @@ -452,7 +454,8 @@ static int make(const char *input_file_name, const char *output_file_name) return EXIT_SUCCESS; } -int main(int argc, char **argv) { +int main(int argc, char **argv) +{ if (argc != 3) { printf("Usage: %s <input.po> <output.mo>\n", argv[0]); return EXIT_FAILURE; diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 4fe14fdf5c9..c7ff93cf504 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -32,7 +32,7 @@ #include "BLI_array.h" #include "BLI_alloca.h" #include "BLI_linklist_stack.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLT_translation.h" @@ -2415,7 +2415,8 @@ static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separ /* don't visit again */ n_prev->next = n_step->next; } - } while ((n_prev = n_step), + } while ((void) + (n_prev = n_step), (n_step = n_step->next)); } while ((n_orig = n_orig->next) && n_orig->next); diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c index 5780dc57d78..b3b23933d2f 100644 --- a/source/blender/bmesh/intern/bmesh_edgeloop.c +++ b/source/blender/bmesh/intern/bmesh_edgeloop.c @@ -32,6 +32,7 @@ #include "BLI_math_vector.h" #include "BLI_listbase.h" #include "BLI_mempool.h" +#include "BLI_utildefines_iter.h" #include "bmesh.h" @@ -708,21 +709,16 @@ void BM_edgeloop_expand( } if (el_store->len < el_store_len) { - const int step = max_ii(1, el_store->len / (el_store->len % el_store_len)); - LinkData *node_first = el_store->verts.first; - LinkData *node_curr = node_first; + LinkData *node_curr = el_store->verts.first; - do { - LinkData *node_curr_init = node_curr; - LinkData *node_curr_copy; - int i = 0; - BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (&el_store->verts, node_curr, node_curr_init) { - if (i++ < step) { - break; - } + int iter_prev = 0; + BLI_FOREACH_SPARSE_RANGE(el_store->len, (el_store_len - el_store->len), iter) { + while (iter_prev < iter) { + node_curr = node_curr->next; + iter_prev += 1; } - BLI_LISTBASE_CIRCULAR_FORWARD_END (&el_store->verts, node_curr, node_curr_init); + LinkData *node_curr_copy; node_curr_copy = MEM_dupallocN(node_curr); if (split == false) { BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy); @@ -730,7 +726,8 @@ void BM_edgeloop_expand( } else { if (node_curr->next || (el_store->flag & BM_EDGELOOP_IS_CLOSED)) { - EDGE_SPLIT(node_curr_copy, node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first); + EDGE_SPLIT(node_curr_copy, + node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first); BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy); node_curr = node_curr_copy->next; } @@ -742,9 +739,11 @@ void BM_edgeloop_expand( split_swap = !split_swap; } el_store->len++; - } while (el_store->len < el_store_len); + iter_prev += 1; + } } +#undef BKE_FOREACH_SUBSET_OF_RANGE #undef EDGE_SPLIT BLI_assert(el_store->len == el_store_len); diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c index 59ce91a3e70..7787d704b59 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_conv.c +++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c @@ -219,6 +219,11 @@ static BMFace *bm_face_create_from_mpoly( /** * \brief Mesh -> BMesh + * \param bm: The mesh to write into, while this is typically a newly created BMesh, + * merging into existing data is supported. + * Note the custom-data layout isn't used. + * If more comprehensive merging is needed we should move this into a separate function + * since this should be kept fast for edit-mode switching and storing undo steps. * * \warning This function doesn't calculate face normals. */ @@ -226,6 +231,9 @@ void BM_mesh_bm_from_me( BMesh *bm, Mesh *me, const struct BMeshFromMeshParams *params) { + const bool is_new = + !(bm->totvert || + (bm->vdata.totlayer || bm->edata.totlayer || bm->pdata.totlayer || bm->ldata.totlayer)); MVert *mvert; MEdge *medge; MLoop *mloop; @@ -233,19 +241,12 @@ void BM_mesh_bm_from_me( KeyBlock *actkey, *block; BMVert *v, **vtable = NULL; BMEdge *e, **etable = NULL; - BMFace *f; + BMFace *f, **ftable = NULL; float (*keyco)[3] = NULL; - int totuv, totloops, i, j; - - /* free custom data */ - /* this isnt needed in most cases but do just incase */ - CustomData_free(&bm->vdata, bm->totvert); - CustomData_free(&bm->edata, bm->totedge); - CustomData_free(&bm->ldata, bm->totloop); - CustomData_free(&bm->pdata, bm->totface); + int totuv, totloops, i; if (!me || !me->totvert) { - if (me) { /*no verts? still copy customdata layout*/ + if (me && is_new) { /*no verts? still copy customdata layout*/ CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_ASSIGN, 0); CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_ASSIGN, 0); CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_ASSIGN, 0); @@ -259,19 +260,27 @@ void BM_mesh_bm_from_me( return; /* sanity check */ } - vtable = MEM_mallocN(sizeof(void **) * me->totvert, "mesh to bmesh vtable"); + if (is_new) { + CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); + /* make sure uv layer names are consisten */ + totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); + for (i = 0; i < totuv; i++) { + int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i); + CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name); + } + } - /* make sure uv layer names are consisten */ - totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); - for (i = 0; i < totuv; i++) { - int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i); - CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name); + /* -------------------------------------------------------------------- */ + /* Shape Key */ + int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0; + if (is_new == false) { + tot_shape_keys = min_ii(tot_shape_keys, CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY)); } + const float (**shape_key_table)[3] = tot_shape_keys ? BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL; if ((params->active_shapekey != 0) && (me->key != NULL)) { actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1); @@ -280,63 +289,68 @@ void BM_mesh_bm_from_me( actkey = NULL; } - const int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0; - const float (**shape_key_table)[3] = tot_shape_keys ? BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL; - - if (tot_shape_keys || params->add_key_index) { - CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0); + if (is_new) { + if (tot_shape_keys || params->add_key_index) { + CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0); + } } if (tot_shape_keys) { - /* check if we need to generate unique ids for the shapekeys. - * this also exists in the file reading code, but is here for - * a sanity check */ - if (!me->key->uidgen) { - fprintf(stderr, - "%s had to generate shape key uid's in a situation we shouldn't need to! " - "(bmesh internal error)\n", - __func__); - - me->key->uidgen = 1; - for (block = me->key->block.first; block; block = block->next) { - block->uid = me->key->uidgen++; + if (is_new) { + /* check if we need to generate unique ids for the shapekeys. + * this also exists in the file reading code, but is here for + * a sanity check */ + if (!me->key->uidgen) { + fprintf(stderr, + "%s had to generate shape key uid's in a situation we shouldn't need to! " + "(bmesh internal error)\n", + __func__); + + me->key->uidgen = 1; + for (block = me->key->block.first; block; block = block->next) { + block->uid = me->key->uidgen++; + } } } if (actkey && actkey->totelem == me->totvert) { - keyco = actkey->data; - bm->shapenr = params->active_shapekey; + keyco = params->use_shapekey ? actkey->data : NULL; + if (is_new) { + bm->shapenr = params->active_shapekey; + } } - for (i = 0, block = me->key->block.first; block; block = block->next, i++) { - CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, - CD_ASSIGN, NULL, 0, block->name); - - j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i); - bm->vdata.layers[j].uid = block->uid; - + for (i = 0, block = me->key->block.first; i < tot_shape_keys; block = block->next, i++) { + if (is_new) { + CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, + CD_ASSIGN, NULL, 0, block->name); + int j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i); + bm->vdata.layers[j].uid = block->uid; + } shape_key_table[i] = (const float (*)[3])block->data; } } - CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT); - CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); - CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP); - CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE); + if (is_new) { + CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT); + CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); + CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP); + CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE); - BM_mesh_cd_flag_apply(bm, me->cd_flag); + BM_mesh_cd_flag_apply(bm, me->cd_flag); + } const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); const int cd_shape_key_offset = me->key ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) : -1; - const int cd_shape_keyindex_offset = (tot_shape_keys || params->add_key_index) ? + const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ? CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : -1; + vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__); + for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) { - v = vtable[i] = BM_vert_create( - bm, keyco && params->use_shapekey ? keyco[i] : mvert->co, NULL, - BM_CREATE_SKIP_CD); + v = vtable[i] = BM_vert_create(bm, keyco ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD); BM_elem_index_set(v, i); /* set_ok */ /* transfer flag */ @@ -360,20 +374,16 @@ void BM_mesh_bm_from_me( /* set shapekey data */ if (tot_shape_keys) { float (*co_dst)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset); - for (j = 0; j < tot_shape_keys; j++, co_dst++) { + for (int j = 0; j < tot_shape_keys; j++, co_dst++) { copy_v3_v3(*co_dst, shape_key_table[j][i]); } } } - - bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */ - - if (!me->totedge) { - MEM_freeN(vtable); - return; + if (is_new) { + bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */ } - etable = MEM_mallocN(sizeof(void **) * me->totedge, "mesh to bmesh etable"); + etable = MEM_mallocN(sizeof(BMEdge **) * me->totedge, __func__); medge = me->medge; for (i = 0; i < me->totedge; i++, medge++) { @@ -395,8 +405,14 @@ void BM_mesh_bm_from_me( if (cd_edge_crease_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge->crease / 255.0f); } + if (is_new) { + bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */ + } - bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */ + /* only needed for selection. */ + if (me->mselect && me->totselect != 0) { + ftable = MEM_mallocN(sizeof(BMFace **) * me->totpoly, __func__); + } mloop = me->mloop; mp = me->mpoly; @@ -406,6 +422,9 @@ void BM_mesh_bm_from_me( f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart, bm, vtable, etable); + if (ftable != NULL) { + ftable[i] = f; + } if (UNLIKELY(f == NULL)) { printf("%s: Warning! Bad face in mesh" @@ -428,7 +447,7 @@ void BM_mesh_bm_from_me( f->mat_nr = mp->mat_nr; if (i == me->act_face) bm->act_face = f; - j = mp->loopstart; + int j = mp->loopstart; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { /* don't use 'j' since we may have skipped some faces, hence some loops. */ @@ -445,54 +464,49 @@ void BM_mesh_bm_from_me( BM_face_normal_update(f); } } + if (is_new) { + bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */ + } - bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */ + /* -------------------------------------------------------------------- */ + /* MSelect clears the array elements (avoid adding multiple times). + * + * Take care to keep this last and not use (v/e/ftable) after this. + */ if (me->mselect && me->totselect != 0) { - - BMVert **vert_array = MEM_mallocN(sizeof(BMVert *) * bm->totvert, "VSelConv"); - BMEdge **edge_array = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, "ESelConv"); - BMFace **face_array = MEM_mallocN(sizeof(BMFace *) * bm->totface, "FSelConv"); MSelect *msel; - -#pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) - { -#pragma omp section - { BM_iter_as_array(bm, BM_VERTS_OF_MESH, NULL, (void **)vert_array, bm->totvert); } -#pragma omp section - { BM_iter_as_array(bm, BM_EDGES_OF_MESH, NULL, (void **)edge_array, bm->totedge); } -#pragma omp section - { BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)face_array, bm->totface); } - } - for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) { + BMElem **ele_p; switch (msel->type) { case ME_VSEL: - BM_select_history_store(bm, (BMElem *)vert_array[msel->index]); + ele_p = (BMElem **)&vtable[msel->index]; break; case ME_ESEL: - BM_select_history_store(bm, (BMElem *)edge_array[msel->index]); + ele_p = (BMElem **)&etable[msel->index]; break; case ME_FSEL: - BM_select_history_store(bm, (BMElem *)face_array[msel->index]); + ele_p = (BMElem **)&ftable[msel->index]; break; + default: + continue; } - } - MEM_freeN(vert_array); - MEM_freeN(edge_array); - MEM_freeN(face_array); + if (*ele_p != NULL) { + BM_select_history_store_notest(bm, *ele_p); + *ele_p = NULL; + } + } } else { - me->totselect = 0; - if (me->mselect) { - MEM_freeN(me->mselect); - me->mselect = NULL; - } + BM_select_history_clear(bm); } MEM_freeN(vtable); MEM_freeN(etable); + if (ftable) { + MEM_freeN(ftable); + } } diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c index 7c9ebc800a3..3a6a3543bc8 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_validate.c +++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c @@ -41,7 +41,7 @@ /* macro which inserts the function name */ -#if defined __GNUC__ || defined __sun +#if defined __GNUC__ # define ERRMSG(format, args...) { fprintf(stderr, "%s: " format ", " AT "\n", __func__, ##args); errtot++; } (void)0 #else # define ERRMSG(format, ...) { fprintf(stderr, "%s: " format ", " AT "\n", __func__, __VA_ARGS__); errtot++; } (void)0 diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index a4621b45fe6..7b9d17b27b5 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -39,6 +39,8 @@ #include "BLI_polyfill2d.h" #include "BLI_polyfill2d_beautify.h" #include "BLI_linklist.h" +#include "BLI_edgehash.h" +#include "BLI_heap.h" #include "bmesh.h" #include "bmesh_tools.h" @@ -1474,3 +1476,147 @@ void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptri #undef USE_TESSFACE_SPEEDUP } + + +/** + * A version of #BM_mesh_calc_tessellation that avoids degenerate triangles. + */ +void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot) +{ + /* this assumes all faces can be scan-filled, which isn't always true, + * worst case we over alloc a little which is acceptable */ +#ifndef NDEBUG + const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop); +#endif + + BMIter iter; + BMFace *efa; + int i = 0; + + MemArena *pf_arena = NULL; + + /* use_beauty */ + Heap *pf_heap = NULL; + EdgeHash *pf_ehash = NULL; + + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + /* don't consider two-edged faces */ + if (UNLIKELY(efa->len < 3)) { + /* do nothing */ + } + else if (efa->len == 3) { + BMLoop *l; + BMLoop **l_ptr = looptris[i++]; + l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa); + l_ptr[1] = l = l->next; + l_ptr[2] = l->next; + } + else if (efa->len == 4) { + BMLoop *l_v1 = BM_FACE_FIRST_LOOP(efa); + BMLoop *l_v2 = l_v1->next; + BMLoop *l_v3 = l_v2->next; + BMLoop *l_v4 = l_v1->prev; + + /* #BM_verts_calc_rotate_beauty performs excessive checks we don't need! + * It's meant for rotating edges, it also calculates a new normal. + * + * Use #BLI_polyfill_beautify_quad_rotate_calc since we have the normal. + */ +#if 0 + const bool split_13 = (BM_verts_calc_rotate_beauty( + l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) < 0.0f); +#else + float axis_mat[3][3], v_quad[4][2]; + axis_dominant_v3_to_m3(axis_mat, efa->no); + mul_v2_m3v3(v_quad[0], axis_mat, l_v1->v->co); + mul_v2_m3v3(v_quad[1], axis_mat, l_v2->v->co); + mul_v2_m3v3(v_quad[2], axis_mat, l_v3->v->co); + mul_v2_m3v3(v_quad[3], axis_mat, l_v4->v->co); + + const bool split_13 = BLI_polyfill_beautify_quad_rotate_calc( + v_quad[0], v_quad[1], v_quad[2], v_quad[3]) < 0.0f; +#endif + + BMLoop **l_ptr_a = looptris[i++]; + BMLoop **l_ptr_b = looptris[i++]; + if (split_13) { + l_ptr_a[0] = l_v1; + l_ptr_a[1] = l_v2; + l_ptr_a[2] = l_v3; + + l_ptr_b[0] = l_v1; + l_ptr_b[1] = l_v3; + l_ptr_b[2] = l_v4; + } + else { + l_ptr_a[0] = l_v1; + l_ptr_a[1] = l_v2; + l_ptr_a[2] = l_v4; + + l_ptr_b[0] = l_v2; + l_ptr_b[1] = l_v3; + l_ptr_b[2] = l_v4; + } + } + else { + int j; + + BMLoop *l_iter; + BMLoop *l_first; + BMLoop **l_arr; + + float axis_mat[3][3]; + float (*projverts)[2]; + unsigned int (*tris)[3]; + + const int totfilltri = efa->len - 2; + + if (UNLIKELY(pf_arena == NULL)) { + pf_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); + pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE); + } + + tris = BLI_memarena_alloc(pf_arena, sizeof(*tris) * totfilltri); + l_arr = BLI_memarena_alloc(pf_arena, sizeof(*l_arr) * efa->len); + projverts = BLI_memarena_alloc(pf_arena, sizeof(*projverts) * efa->len); + + axis_dominant_v3_to_m3_negate(axis_mat, efa->no); + + j = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + l_arr[j] = l_iter; + mul_v2_m3v3(projverts[j], axis_mat, l_iter->v->co); + j++; + } while ((l_iter = l_iter->next) != l_first); + + BLI_polyfill_calc_arena((const float (*)[2])projverts, efa->len, 1, tris, pf_arena); + + BLI_polyfill_beautify((const float (*)[2])projverts, efa->len, tris, pf_arena, pf_heap, pf_ehash); + + for (j = 0; j < totfilltri; j++) { + BMLoop **l_ptr = looptris[i++]; + unsigned int *tri = tris[j]; + + l_ptr[0] = l_arr[tri[0]]; + l_ptr[1] = l_arr[tri[1]]; + l_ptr[2] = l_arr[tri[2]]; + } + + BLI_memarena_clear(pf_arena); + } + } + + if (pf_arena) { + BLI_memarena_free(pf_arena); + + BLI_heap_free(pf_heap, NULL); + BLI_edgehash_free(pf_ehash, NULL); + } + + *r_looptris_tot = i; + + BLI_assert(i <= looptris_tot); + +} diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h index d944f3a8bc5..313caac1243 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.h +++ b/source/blender/bmesh/intern/bmesh_polygon.h @@ -33,6 +33,7 @@ struct Heap; #include "BLI_compiler_attrs.h" void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot); +void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot); void BM_face_calc_tessellation( const BMFace *f, const bool use_fixed_quad, diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index e515f9af63f..8a3cb329610 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -32,7 +32,7 @@ #include "BLI_memarena.h" #include "BLI_array.h" #include "BLI_alloca.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_linklist_stack.h" #include "BLI_sort.h" #include "BLI_sort_utils.h" @@ -725,10 +725,30 @@ BLI_INLINE bool edge_isect_verts_point_2d( const BMEdge *e, const BMVert *v_a, const BMVert *v_b, float r_isect[2]) { - return ((isect_seg_seg_v2_point(v_a->co, v_b->co, e->v1->co, e->v2->co, r_isect) == 1) && + /* This bias seems like it could be too large, + * mostly its not needed, see T52329 for example where it is. */ + const float endpoint_bias = 1e-4f; + return ((isect_seg_seg_v2_point_ex(v_a->co, v_b->co, e->v1->co, e->v2->co, endpoint_bias, r_isect) == 1) && ((e->v1 != v_a) && (e->v2 != v_a) && (e->v1 != v_b) && (e->v2 != v_b))); } +BLI_INLINE int axis_pt_cmp(const float pt_a[2], const float pt_b[2]) +{ + if (pt_a[0] < pt_b[0]) { + return -1; + } + if (pt_a[0] > pt_b[0]) { + return 1; + } + if (pt_a[1] < pt_b[1]) { + return -1; + } + if (pt_a[1] > pt_b[1]) { + return 1; + } + return 0; +} + /** * Represents isolated edge-links, * each island owns contiguous slices of the vert array. @@ -749,7 +769,8 @@ struct EdgeGroupIsland { struct { BMVert *min, *max; /* used for sorting only */ - float min_axis; + float min_axis[2]; + float max_axis[2]; } vert_span; }; @@ -758,12 +779,11 @@ static int group_min_cmp_fn(const void *p1, const void *p2) const struct EdgeGroupIsland *g1 = *(struct EdgeGroupIsland **)p1; const struct EdgeGroupIsland *g2 = *(struct EdgeGroupIsland **)p2; /* min->co[SORT_AXIS] hasn't been applied yet */ - const float f1 = g1->vert_span.min_axis; - const float f2 = g2->vert_span.min_axis; - - if (f1 < f2) return -1; - if (f1 > f2) return 1; - else return 0; + int test = axis_pt_cmp(g1->vert_span.min_axis, g2->vert_span.min_axis); + if (UNLIKELY(test == 0)) { + test = axis_pt_cmp(g1->vert_span.max_axis, g2->vert_span.max_axis); + } + return test; } struct Edges_VertVert_BVHTreeTest { @@ -993,8 +1013,8 @@ static int bm_face_split_edgenet_find_connection( for (int j = 0; j < 2; j++) { BMVert *v_iter = v_pair[j]; if (BM_elem_flag_test(v_iter, VERT_IS_VALID)) { - if (direction_sign ? (v_iter->co[SORT_AXIS] >= v_origin->co[SORT_AXIS]) : - (v_iter->co[SORT_AXIS] <= v_origin->co[SORT_AXIS])) + if (direction_sign ? (v_iter->co[SORT_AXIS] > v_origin->co[SORT_AXIS]) : + (v_iter->co[SORT_AXIS] < v_origin->co[SORT_AXIS])) { BLI_SMALLSTACK_PUSH(vert_search, v_iter); BLI_SMALLSTACK_PUSH(vert_blacklist, v_iter); @@ -1360,8 +1380,8 @@ bool BM_face_split_edgenet_connect_islands( /* init with *any* different verts */ g->vert_span.min = ((BMEdge *)edge_links->link)->v1; g->vert_span.max = ((BMEdge *)edge_links->link)->v2; - float min_axis = FLT_MAX; - float max_axis = -FLT_MAX; + float min_axis[2] = {FLT_MAX, FLT_MAX}; + float max_axis[2] = {-FLT_MAX, -FLT_MAX}; do { BMEdge *e = edge_links->link; @@ -1372,24 +1392,29 @@ bool BM_face_split_edgenet_connect_islands( BLI_assert(v_iter->head.htype == BM_VERT); /* ideally we could use 'v_iter->co[SORT_AXIS]' here, * but we need to sort the groups before setting the vertex array order */ + const float axis_value[2] = { #if SORT_AXIS == 0 - const float axis_value = dot_m3_v3_row_x(axis_mat, v_iter->co); + dot_m3_v3_row_x(axis_mat, v_iter->co), + dot_m3_v3_row_y(axis_mat, v_iter->co), #else - const float axis_value = dot_m3_v3_row_y(axis_mat, v_iter->co); + dot_m3_v3_row_y(axis_mat, v_iter->co), + dot_m3_v3_row_x(axis_mat, v_iter->co), #endif + }; - if (axis_value < min_axis) { + if (axis_pt_cmp(axis_value, min_axis) == -1) { g->vert_span.min = v_iter; - min_axis = axis_value; + copy_v2_v2(min_axis, axis_value); } - if (axis_value > max_axis ) { + if (axis_pt_cmp(axis_value, max_axis) == 1) { g->vert_span.max = v_iter; - max_axis = axis_value; + copy_v2_v2(max_axis, axis_value); } } } while ((edge_links = edge_links->next)); - g->vert_span.min_axis = min_axis; + copy_v2_v2(g->vert_span.min_axis, min_axis); + copy_v2_v2(g->vert_span.max_axis, max_axis); g->has_prev_edge = false; @@ -1449,8 +1474,10 @@ bool BM_face_split_edgenet_connect_islands( bm->elem_index_dirty |= BM_VERT; - /* Now create bvh tree*/ - BVHTree *bvhtree = BLI_bvhtree_new(edge_arr_len, 0.0f, 8, 8); + /* Now create bvh tree + * + * Note that a large epsilon is used because meshes with dimensions of around 100+ need it. see T52329. */ + BVHTree *bvhtree = BLI_bvhtree_new(edge_arr_len, 1e-4f, 8, 8); for (uint i = 0; i < edge_arr_len; i++) { const float e_cos[2][3] = { {UNPACK2(edge_arr[i]->v1->co), 0.0f}, diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h index 4161fbe90fb..4dcf97e3f35 100644 --- a/source/blender/bmesh/intern/bmesh_private.h +++ b/source/blender/bmesh/intern/bmesh_private.h @@ -44,13 +44,14 @@ # define BM_CHECK_ELEMENT(el) (void)(el) #else int bmesh_elem_check(void *element, const char htype); -# define BM_CHECK_ELEMENT(el) \ +# define BM_CHECK_ELEMENT(el) { \ if (bmesh_elem_check(el, ((BMHeader *)el)->htype)) { \ printf("check_element failure, with code %i on line %i in file\n" \ " \"%s\"\n\n", \ bmesh_elem_check(el, ((BMHeader *)el)->htype), \ __LINE__, __FILE__); \ - } (void)0 + } \ +} ((void)0) #endif int bmesh_radial_length(const BMLoop *l); diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 668fb998254..5bdc3927e16 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -36,7 +36,7 @@ #include "BLI_math.h" #include "BLI_alloca.h" #include "BLI_linklist.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BKE_customdata.h" @@ -754,6 +754,22 @@ bool BM_vert_is_edge_pair(const BMVert *v) } /** + * Fast alternative to ``(BM_vert_edge_count(v) == 2)`` + * that checks both edges connect to the same faces. + */ +bool BM_vert_is_edge_pair_manifold(const BMVert *v) +{ + const BMEdge *e = v->e; + if (e) { + BMEdge *e_other = BM_DISK_EDGE_NEXT(e, v); + if (((e_other != e) && (BM_DISK_EDGE_NEXT(e_other, v) == e))) { + return BM_edge_is_manifold(e) && BM_edge_is_manifold(e_other); + } + } + return false; +} + +/** * Access a verts 2 connected edges. * * \return true when only 2 verts are found. diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 83977fa8be0..c9fce96c798 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -85,6 +85,7 @@ int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_vert_is_edge_pair_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b); bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/bmesh/operators/bmo_bisect_plane.c b/source/blender/bmesh/operators/bmo_bisect_plane.c index 2c80ff651b8..ed232e81b82 100644 --- a/source/blender/bmesh/operators/bmo_bisect_plane.c +++ b/source/blender/bmesh/operators/bmo_bisect_plane.c @@ -29,7 +29,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_math.h" #include "bmesh.h" diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c index c5c4ac959a9..0b5f1bb9ca1 100644 --- a/source/blender/bmesh/operators/bmo_connect.c +++ b/source/blender/bmesh/operators/bmo_connect.c @@ -27,7 +27,7 @@ */ #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_alloca.h" #include "BLI_linklist_stack.h" diff --git a/source/blender/bmesh/operators/bmo_offset_edgeloops.c b/source/blender/bmesh/operators/bmo_offset_edgeloops.c index a9840a72fc9..269f933f27f 100644 --- a/source/blender/bmesh/operators/bmo_offset_edgeloops.c +++ b/source/blender/bmesh/operators/bmo_offset_edgeloops.c @@ -33,7 +33,7 @@ #include "BLI_math.h" #include "BLI_alloca.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BKE_customdata.h" diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index cca0f7387cd..d8f83d786b4 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -839,7 +839,7 @@ void BM_mesh_calc_uvs_grid( const float dx = 1.0f / (float)(x_segments - 1); const float dy = 1.0f / (float)(y_segments - 1); float x = 0.0f; - float y = 0.0f; + float y = dy; int loop_index; @@ -854,16 +854,16 @@ void BM_mesh_calc_uvs_grid( switch (loop_index) { case 0: - x += dx; + y -= dy; break; case 1: - y += dy; + x += dx; break; case 2: - x -= dx; + y += dy; break; case 3: - y -= dy; + x -= dx; break; default: break; diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index 7d19d90807a..e85751531ae 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -30,7 +30,8 @@ #include "BLI_math.h" #include "BLI_alloca.h" -#include "BLI_stackdefines.h" +#include "BLI_kdtree.h" +#include "BLI_utildefines_stack.h" #include "BLI_stack.h" #include "BKE_customdata.h" @@ -277,22 +278,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) BMO_mesh_delete_oflag_context(bm, ELE_DEL, DEL_ONLYTAGGED); } -static int vergaverco(const void *e1, const void *e2) -{ - const BMVert *v1 = *(const void **)e1, *v2 = *(const void **)e2; - float x1 = v1->co[0] + v1->co[1] + v1->co[2]; - float x2 = v2->co[0] + v2->co[1] + v2->co[2]; - - if (x1 > x2) return 1; - else if (x1 < x2) return -1; - else return 0; -} - -// #define VERT_TESTED 1 // UNUSED -#define VERT_DOUBLE 2 -#define VERT_TARGET 4 #define VERT_KEEP 8 -// #define VERT_MARK 16 // UNUSED #define VERT_IN 32 #define EDGE_MARK 1 @@ -584,77 +570,62 @@ static void bmesh_find_doubles_common( BMesh *bm, BMOperator *op, BMOperator *optarget, BMOpSlot *optarget_slot) { - BMVert **verts; - int verts_len; + const BMOpSlot *slot_verts = BMO_slot_get(op->slots_in, "verts"); + BMVert * const *verts = (BMVert **)slot_verts->data.buf; + const int verts_len = slot_verts->len; - int i, j, keepvert = 0; + bool has_keep_vert = false; + bool found_duplicates = false; const float dist = BMO_slot_float_get(op->slots_in, "dist"); - const float dist_sq = dist * dist; - const float dist3 = ((float)M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */ /* Test whether keep_verts arg exists and is non-empty */ if (BMO_slot_exists(op->slots_in, "keep_verts")) { BMOIter oiter; - keepvert = BMO_iter_new(&oiter, op->slots_in, "keep_verts", BM_VERT) != NULL; + has_keep_vert = BMO_iter_new(&oiter, op->slots_in, "keep_verts", BM_VERT) != NULL; } - /* get the verts as an array we can sort */ - verts = BMO_slot_as_arrayN(op->slots_in, "verts", &verts_len); - - /* sort by vertex coordinates added together */ - qsort(verts, verts_len, sizeof(BMVert *), vergaverco); - /* Flag keep_verts */ - if (keepvert) { + if (has_keep_vert) { BMO_slot_buffer_flag_enable(bm, op->slots_in, "keep_verts", BM_VERT, VERT_KEEP); } - for (i = 0; i < verts_len; i++) { - BMVert *v_check = verts[i]; - - if (BMO_vert_flag_test(bm, v_check, VERT_DOUBLE | VERT_TARGET)) { - continue; + int *duplicates = MEM_mallocN(sizeof(int) * verts_len, __func__); + { + KDTree *tree = BLI_kdtree_new(verts_len); + for (int i = 0; i < verts_len; i++) { + BLI_kdtree_insert(tree, i, verts[i]->co); + if (has_keep_vert && BMO_vert_flag_test(bm, verts[i], VERT_KEEP)) { + duplicates[i] = i; + } + else { + duplicates[i] = -1; + } } - for (j = i + 1; j < verts_len; j++) { - BMVert *v_other = verts[j]; - - /* a match has already been found, (we could check which is best, for now don't) */ - if (BMO_vert_flag_test(bm, v_other, VERT_DOUBLE | VERT_TARGET)) { - continue; - } + BLI_kdtree_balance(tree); + found_duplicates = BLI_kdtree_calc_duplicates_fast(tree, dist, false, duplicates) != 0; + BLI_kdtree_free(tree); + } - /* Compare sort values of the verts using 3x tolerance (allowing for the tolerance - * on each of the three axes). This avoids the more expensive length comparison - * for most vertex pairs. */ - if ((v_other->co[0] + v_other->co[1] + v_other->co[2]) - - (v_check->co[0] + v_check->co[1] + v_check->co[2]) > dist3) - { - break; + if (found_duplicates) { + for (int i = 0; i < verts_len; i++) { + BMVert *v_check = verts[i]; + if (duplicates[i] == -1) { + /* nop (others can use as target) */ } - - if (keepvert) { - if (BMO_vert_flag_test(bm, v_other, VERT_KEEP) == BMO_vert_flag_test(bm, v_check, VERT_KEEP)) - continue; + else if (duplicates[i] == i) { + /* keep (others can use as target) */ } - - if (compare_len_squared_v3v3(v_check->co, v_other->co, dist_sq)) { - - /* If one vert is marked as keep, make sure it will be the target */ - if (BMO_vert_flag_test(bm, v_other, VERT_KEEP)) { - SWAP(BMVert *, v_check, v_other); - } - - BMO_vert_flag_enable(bm, v_other, VERT_DOUBLE); - BMO_vert_flag_enable(bm, v_check, VERT_TARGET); - - BMO_slot_map_elem_insert(optarget, optarget_slot, v_other, v_check); + else { + BMVert *v_other = verts[duplicates[i]]; + BLI_assert(ELEM(duplicates[duplicates[i]], -1, duplicates[i])); + BMO_slot_map_elem_insert(optarget, optarget_slot, v_check, v_other); } } } - MEM_freeN(verts); + MEM_freeN(duplicates); } void bmo_remove_doubles_exec(BMesh *bm, BMOperator *op) diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index 94b60a51f68..adcc0c71629 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -40,7 +40,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_alloca.h" #include "BLI_math.h" #include "BLI_listbase.h" diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c index f08f21a2c88..6e6242fc9f9 100644 --- a/source/blender/bmesh/tools/bmesh_beautify.c +++ b/source/blender/bmesh/tools/bmesh_beautify.c @@ -150,7 +150,7 @@ static float bm_edge_calc_rotate_beauty__area( (ELEM(v4, v1, v2, v3) == false)); add_v3_v3v3(no, no_a, no_b); - if (UNLIKELY((no_scale = normalize_v3(no)) <= FLT_EPSILON)) { + if (UNLIKELY((no_scale = normalize_v3(no)) == 0.0f)) { break; } @@ -182,7 +182,12 @@ static float bm_edge_calc_rotate_beauty__area( } } - return BLI_polyfill_beautify_quad_rotate_calc(v1_xy, v2_xy, v3_xy, v4_xy); + /** + * Important to lock degenerate here, + * since the triangle pars will be projected into different 2D spaces. + * Allowing to rotate out of a degenerate state can flip the faces (when performed iteratively). + */ + return BLI_polyfill_beautify_quad_rotate_calc_ex(v1_xy, v2_xy, v3_xy, v4_xy, true); } while (false); return FLT_MAX; diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 6673c5d25cf..51a0fa4b2cc 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -234,7 +234,7 @@ static bool nearly_parallel(const float d1[3], const float d2[3]) float ang; ang = angle_v3v3(d1, d2); - return (fabsf(ang) < BEVEL_EPSILON_ANG) || (fabsf(ang - M_PI) < BEVEL_EPSILON_ANG); + return (fabsf(ang) < BEVEL_EPSILON_ANG) || (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG); } /* Make a new BoundVert of the given kind, insert it at the end of the circular linked @@ -4531,53 +4531,198 @@ static void set_profile_spacing(BevelParams *bp) } /* - * Calculate and return an offset that is the lesser of the current + * Assume we have a situation like: + * + * a d + * \ / + * A \ / C + * \ th1 th2/ + * b---------c + * B + * + * where edges are A, B, and C, + * following a face around vertices a, b, c, d; + * th1 is angle abc and th2 is angle bcd; + * and the argument EdgeHalf eb is B, going from b to c. + * In general case, edge offset specs for A, B, C have + * the form ka*t, kb*t, kc*t where ka, kb, kc are some factors + * (may be 0) and t is the current bp->offset. + * We want to calculate t at which the clone of B parallel + * to it collapses. This can be calculated using trig. + * Another case of geometry collision that can happen is + * When B slides along A because A is unbeveled. + * Then it might collide with a. Similarly for B sliding along C. + */ +static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb) +{ + EdgeHalf *ea, *ec, *ebother; + BevVert *bvc; + BMLoop *lb; + BMVert *va, *vb, *vc, *vd; + float ka, kb, kc, g, h, t, den, no_collide_offset, th1, th2, sin1, sin2, tan1, tan2, limit; + + limit = no_collide_offset = bp->offset + 1e6; + if (bp->offset == 0.0f) + return no_collide_offset; + kb = eb->offset_l_spec; + ea = eb->next; /* note: this is in direction b --> a */ + ka = ea->offset_r_spec; + if (eb->is_rev) { + vc = eb->e->v1; + vb = eb->e->v2; + } + else { + vb = eb->e->v1; + vc = eb->e->v2; + } + va = ea->is_rev ? ea->e->v1 : ea->e->v2; + bvc = NULL; + ebother = find_other_end_edge_half(bp, eb, &bvc); + if (ebother != NULL) { + ec = ebother->prev; /* note: this is in direction c --> d*/ + vc = bvc->v; + kc = ec->offset_l_spec; + vd = ec->is_rev ? ec->e->v1 : ec->e->v2; + } + else { + /* No bevvert for w, so C can't be beveled */ + kc = 0.0f; + ec = NULL; + /* Find an edge from c that has same face */ + lb = BM_face_edge_share_loop(eb->fnext, eb->e); + if (!lb) { + return no_collide_offset; + } + if (lb->next->v == vc) + vd = lb->next->next->v; + else if (lb->v == vc) + vd = lb->prev->v; + else { + return no_collide_offset; + } + } + if (ea->e == eb->e || (ec && ec->e == eb->e)) + return no_collide_offset; + ka = ka / bp->offset; + kb = kb / bp->offset; + kc = kc / bp->offset; + th1 = angle_v3v3v3(va->co, vb->co, vc->co); + th2 = angle_v3v3v3(vb->co, vc->co, vd->co); + + /* First calculate offset at which edge B collapses, which happens + * when advancing clones of A, B, C all meet at a point. + * This only happens if at least two of those three edges have non-zero k's */ + sin1 = sinf(th1); + sin2 = sinf(th2); + if ((ka > 0.0f) + (kb > 0.0f) + (kc > 0.0f) >= 2) { + tan1 = tanf(th1); + tan2 = tanf(th2); + g = tan1 * tan2; + h = sin1 * sin2; + den = g * (ka * sin2 + kc * sin1) + kb * h * (tan1 + tan2); + if (den != 0.0f) { + t = BM_edge_calc_length(eb->e); + t *= g * h / den; + if (t >= 0.0f) + limit = t; + } + } + + /* Now check edge slide cases */ + if (kb > 0.0f && ka == 0.0f /*&& bvb->selcount == 1 && bvb->edgecount > 2*/) { + t = BM_edge_calc_length(ea->e); + t *= sin1 / kb; + if (t >= 0.0f && t < limit) + limit = t; + } + if (kb > 0.0f && kc == 0.0f /* && bvc && ec && bvc->selcount == 1 && bvc->edgecount > 2 */) { + t = BM_edge_calc_length(ec->e); + t *= sin2 / kb; + if (t >= 0.0f && t < limit) + limit = t; + } + return limit; +} + +/* + * We have an edge A between vertices a and b, + * where EdgeHalf ea is the half of A that starts at a. + * For vertex-only bevels, the new vertices slide from a at a rate ka*t + * and from b at a rate kb*t. + * We want to calculate the t at which the two meet. + */ +static float vertex_collide_offset(BevelParams *bp, EdgeHalf *ea) +{ + float limit, ka, kb, no_collide_offset, la, kab; + EdgeHalf *eb; + + limit = no_collide_offset = bp->offset + 1e6; + if (bp->offset == 0.0f) + return no_collide_offset; + ka = ea->offset_l_spec / bp->offset; + eb = find_other_end_edge_half(bp, ea, NULL); + kb = eb ? eb->offset_l_spec / bp->offset : 0.0f; + kab = ka + kb; + la = BM_edge_calc_length(ea->e); + if (kab <= 0.0f) + return no_collide_offset; + limit = la / kab; + return limit; +} + +/* + * Calculate an offset that is the lesser of the current * bp.offset and the maximum possible offset before geometry * collisions happen. - * Currently this is a quick and dirty estimate of the max - * possible: half the minimum edge length of any vertex involved - * in a bevel. This is usually conservative. - * The correct calculation is quite complicated. - * TODO: implement this correctly. + * If the offset changes as a result of this, adjust the + * current edge offset specs to reflect this clamping, + * and store the new offset in bp.offset. */ -static float bevel_limit_offset(BMesh *bm, BevelParams *bp) +static void bevel_limit_offset(BevelParams *bp) { - BMVert *v; - BMEdge *e; - BMIter v_iter, e_iter; - float limited_offset, half_elen; - bool vbeveled; + BevVert *bv; + EdgeHalf *eh; + GHashIterator giter; + float limited_offset, offset_factor, collision_offset; + int i; limited_offset = bp->offset; - if (bp->offset_type == BEVEL_AMT_PERCENT) { - if (limited_offset > 50.0f) - limited_offset = 50.0f; - return limited_offset; - } - BM_ITER_MESH (v, &v_iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + GHASH_ITER(giter, bp->vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + for (i = 0; i < bv->edgecount; i++) { + eh = &bv->edges[i]; if (bp->vertex_only) { - vbeveled = true; + collision_offset = vertex_collide_offset(bp, eh); + if (collision_offset < limited_offset) + limited_offset = collision_offset; } else { - vbeveled = false; - BM_ITER_ELEM (e, &e_iter, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG)) { - vbeveled = true; - break; - } - } + collision_offset = geometry_collide_offset(bp, eh); + if (collision_offset < limited_offset) + limited_offset = collision_offset; } - if (vbeveled) { - BM_ITER_ELEM (e, &e_iter, v, BM_EDGES_OF_VERT) { - half_elen = 0.5f * BM_edge_calc_length(e); - if (half_elen < limited_offset) - limited_offset = half_elen; - } + } + } + + if (limited_offset < bp->offset) { + /* All current offset specs have some number times bp->offset, + * so we can just multiply them all by the reduction factor + * of the offset to have the effect of recalculating the specs + * with the new limited_offset. + */ + offset_factor = limited_offset / bp->offset; + GHASH_ITER(giter, bp->vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + for (i = 0; i < bv->edgecount; i++) { + eh = &bv->edges[i]; + eh->offset_l_spec *= offset_factor; + eh->offset_r_spec *= offset_factor; + eh->offset_l *= offset_factor; + eh->offset_r *= offset_factor; } } + bp->offset = limited_offset; } - return limited_offset; } /** @@ -4604,6 +4749,7 @@ void BM_mesh_bevel( BMEdge *e; BevVert *bv; BevelParams bp = {NULL}; + GHashIterator giter; bp.offset = offset; bp.offset_type = offset_type; @@ -4627,24 +4773,33 @@ void BM_mesh_bevel( BLI_memarena_use_calloc(bp.mem_arena); set_profile_spacing(&bp); - if (limit_offset) - bp.offset = bevel_limit_offset(bm, &bp); - /* Analyze input vertices, sorting edges and assigning initial new vertex positions */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { bv = bevel_vert_construct(bm, &bp, v); - if (bv) + if (!limit_offset && bv) build_boundary(&bp, bv, true); } } + /* Perhaps clamp offset to avoid geometry colliisions */ + if (limit_offset) { + bevel_limit_offset(&bp); + + /* Assign initial new vertex positions */ + GHASH_ITER(giter, bp.vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + build_boundary(&bp, bv, true); + } + } + /* Perhaps do a pass to try to even out widths */ if (!bp.vertex_only) { adjust_offsets(&bp); } /* Build the meshes around vertices, now that positions are final */ + /* Note: could use GHASH_ITER over bp.vert_hash when backward compatibility no longer matters */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { bv = find_bevvert(&bp, v); diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c index 676a8de94c8..f3927a3ff67 100644 --- a/source/blender/bmesh/tools/bmesh_bisect_plane.c +++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c @@ -38,7 +38,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_alloca.h" #include "BLI_linklist.h" #include "BLI_linklist_stack.h" diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c index c417131d588..36ae7231f94 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c +++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c @@ -40,7 +40,7 @@ #include "BLI_edgehash.h" #include "BLI_polyfill2d.h" #include "BLI_polyfill2d_beautify.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BKE_customdata.h" diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index b9408492cc1..9d1b20cb4d2 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -44,7 +44,7 @@ #include "BLI_sort_utils.h" #include "BLI_linklist_stack.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #ifndef NDEBUG # include "BLI_array_utils.h" #endif diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c index 30b083cacda..85c591b6684 100644 --- a/source/blender/bmesh/tools/bmesh_path.c +++ b/source/blender/bmesh/tools/bmesh_path.c @@ -38,24 +38,34 @@ /* -------------------------------------------------------------------- */ /* Generic Helpers */ -static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3[3]) +/** + * Use skip options when we want to start measuring from a boundary. + */ +static float step_cost_3_v3_ex( + const float v1[3], const float v2[3], const float v3[3], + bool skip_12, bool skip_23) { - float cost, d1[3], d2[3]; - + float d1[3], d2[3]; /* The cost is based on the simple sum of the length of the two edgees... */ sub_v3_v3v3(d1, v2, v1); sub_v3_v3v3(d2, v3, v2); - cost = normalize_v3(d1) + normalize_v3(d2); + const float cost_12 = normalize_v3(d1); + const float cost_23 = normalize_v3(d2); + const float cost = ((skip_12 ? 0.0f : cost_12) + + (skip_23 ? 0.0f : cost_23)); /* but is biased to give higher values to sharp turns, so that it will take * paths with fewer "turns" when selecting between equal-weighted paths between * the two edges */ - cost = cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2))))); - - return cost; + return cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2))))); } +static float step_cost_3_v3( + const float v1[3], const float v2[3], const float v3[3]) +{ + return step_cost_3_v3_ex(v1, v2, v3, false, false); +} /* -------------------------------------------------------------------- */ @@ -364,7 +374,7 @@ LinkNode *BM_mesh_calc_path_edge( /* -------------------------------------------------------------------- */ /* BM_mesh_calc_path_face */ -static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e) +static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e, const void * const f_endpoints[2]) { float f_a_cent[3]; float f_b_cent[3]; @@ -392,10 +402,12 @@ static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e) } #endif - return step_cost_3_v3(f_a_cent, e_cent, f_b_cent); + return step_cost_3_v3_ex( + f_a_cent, e_cent, f_b_cent, + (f_a == f_endpoints[0]), (f_b == f_endpoints[1])); } -static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v) +static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v, const void * const f_endpoints[2]) { float f_a_cent[3]; float f_b_cent[3]; @@ -403,12 +415,14 @@ static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v) BM_face_calc_center_mean_weighted(f_a, f_a_cent); BM_face_calc_center_mean_weighted(f_b, f_b_cent); - return step_cost_3_v3(f_a_cent, v->co, f_b_cent); + return step_cost_3_v3_ex( + f_a_cent, v->co, f_b_cent, + (f_a == f_endpoints[0]), (f_b == f_endpoints[1])); } static void facetag_add_adjacent( Heap *heap, BMFace *f_a, BMFace **faces_prev, float *cost, - const struct BMCalcPathParams *params) + const void * const f_endpoints[2], const struct BMCalcPathParams *params) { const int f_a_index = BM_elem_index_get(f_a); @@ -427,7 +441,7 @@ static void facetag_add_adjacent( /* we know 'f_b' is not visited, check it out! */ const int f_b_index = BM_elem_index_get(f_b); const float cost_cut = params->use_topology_distance ? - 1.0f : facetag_cut_cost_edge(f_a, f_b, l_iter->e); + 1.0f : facetag_cut_cost_edge(f_a, f_b, l_iter->e, f_endpoints); const float cost_new = cost[f_a_index] + cost_cut; if (cost[f_b_index] > cost_new) { @@ -454,7 +468,7 @@ static void facetag_add_adjacent( /* we know 'f_b' is not visited, check it out! */ const int f_b_index = BM_elem_index_get(f_b); const float cost_cut = params->use_topology_distance ? - 1.0f : facetag_cut_cost_vert(f_a, f_b, l_a->v); + 1.0f : facetag_cut_cost_vert(f_a, f_b, l_a->v, f_endpoints); const float cost_new = cost[f_a_index] + cost_cut; if (cost[f_b_index] > cost_new) { @@ -482,6 +496,9 @@ LinkNode *BM_mesh_calc_path_face( BMFace **faces_prev; int i, totface; + /* Start measuring face path at the face edges, ignoring their centers. */ + const void * const f_endpoints[2] = {f_src, f_dst}; + /* note, would pass BM_EDGE except we are looping over all faces anyway */ // BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG @@ -522,7 +539,7 @@ LinkNode *BM_mesh_calc_path_face( if (!BM_elem_flag_test(f, BM_ELEM_TAG)) { BM_elem_flag_enable(f, BM_ELEM_TAG); - facetag_add_adjacent(heap, f, faces_prev, cost, params); + facetag_add_adjacent(heap, f, faces_prev, cost, f_endpoints, params); } } diff --git a/source/blender/bmesh/tools/bmesh_path_region.c b/source/blender/bmesh/tools/bmesh_path_region.c index aad1f9c5a49..d23ea537d82 100644 --- a/source/blender/bmesh/tools/bmesh_path_region.c +++ b/source/blender/bmesh/tools/bmesh_path_region.c @@ -29,22 +29,32 @@ #include "BLI_math.h" #include "BLI_linklist.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_alloca.h" #include "bmesh.h" #include "bmesh_path_region.h" /* own include */ -/* Special handling of vertices with 2 edges - * (act as if the edge-chain is a single edge). */ +/** + * Special handling of vertices with 2 edges + * (act as if the edge-chain is a single edge). + * + * \note Regarding manifold edge stepping: #BM_vert_is_edge_pair_manifold usage. + * Logic to skip a chain of vertices is not applied at boundaries because it gives + * strange behavior from a user perspective especially with boundary quads, see: T52701 + * + * Restrict walking over a vertex chain to cases where the edges share the same faces. + * This is more typical of what a user would consider a vertex chain. + */ #define USE_EDGE_CHAIN #ifdef USE_EDGE_CHAIN /** - * Takes a vertex with 2 edge users and fills in the vertices at each end-point, - * or nothing if if the edges loop back to its self. + * Takes a vertex with 2 edge users and assigns the vertices at each end-point, + * + * \return Success when \a v_end_pair values are set or false if the edges loop back on themselves. */ static bool bm_vert_pair_ends(BMVert *v_pivot, BMVert *v_end_pair[2]) { @@ -53,7 +63,7 @@ static bool bm_vert_pair_ends(BMVert *v_pivot, BMVert *v_end_pair[2]) do { BMEdge *e_chain = e; BMVert *v_other = BM_edge_other_vert(e_chain, v_pivot); - while (BM_vert_is_edge_pair(v_other)) { + while (BM_vert_is_edge_pair_manifold(v_other)) { BMEdge *e_chain_next = BM_DISK_EDGE_NEXT(e_chain, v_other); BLI_assert(BM_DISK_EDGE_NEXT(e_chain_next, v_other) == e_chain); v_other = BM_edge_other_vert(e_chain_next, v_other); @@ -88,7 +98,7 @@ static bool bm_vert_region_test_chain(BMVert *v, int * const depths[2], const in if (bm_vert_region_test(v, depths, pass)) { return true; } - else if (BM_vert_is_edge_pair(v) && + else if (BM_vert_is_edge_pair_manifold(v) && bm_vert_pair_ends(v, v_end_pair) && bm_vert_region_test(v_end_pair[0], depths, pass) && bm_vert_region_test(v_end_pair[1], depths, pass)) @@ -206,7 +216,7 @@ static LinkNode *mesh_calc_path_region_elem( for (int i = 0; i < ele_verts_len[side]; i++) { BMVert *v = ele_verts[side][i]; BMVert *v_end_pair[2]; - if (BM_vert_is_edge_pair(v) && bm_vert_pair_ends(v, v_end_pair)) { + if (BM_vert_is_edge_pair_manifold(v) && bm_vert_pair_ends(v, v_end_pair)) { for (int j = 0; j < 2; j++) { const int v_end_index = BM_elem_index_get(v_end_pair[j]); if (depths[side][v_end_index] == -1) { @@ -239,7 +249,7 @@ static LinkNode *mesh_calc_path_region_elem( /* Walk along the chain, fill in values until we reach a vertex with 3+ edges. */ { BMEdge *e_chain = e; - while (BM_vert_is_edge_pair(v_b) && + while (BM_vert_is_edge_pair_manifold(v_b) && ((depths[side][v_b_index] == -1))) { depths[side][v_b_index] = pass; @@ -256,7 +266,7 @@ static LinkNode *mesh_calc_path_region_elem( /* Add the other vertex to the stack, to be traversed in the next pass. */ if (depths[side][v_b_index] == -1) { #ifdef USE_EDGE_CHAIN - BLI_assert(!BM_vert_is_edge_pair(v_b)); + BLI_assert(!BM_vert_is_edge_pair_manifold(v_b)); #endif BLI_assert(pass == depths[side][BM_elem_index_get(v_a)] + 1); depths[side][v_b_index] = pass; diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp index 3bff20e846b..d4f434d56fd 100644 --- a/source/blender/collada/AnimationExporter.cpp +++ b/source/blender/collada/AnimationExporter.cpp @@ -312,12 +312,12 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa if (ob->type == OB_ARMATURE) { ob_name = getObjectBoneName(ob, fcu); BLI_snprintf( - anim_id, - sizeof(anim_id), - "%s_%s.%s", - (char *)translate_id(ob_name).c_str(), - (char *)translate_id(transformName).c_str(), - axis_name); + anim_id, + sizeof(anim_id), + "%s_%s.%s", + (char *)translate_id(ob_name).c_str(), + (char *)translate_id(transformName).c_str(), + axis_name); } else { if (ma) @@ -326,12 +326,12 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa ob_name = id_name(ob); BLI_snprintf( - anim_id, - sizeof(anim_id), - "%s_%s_%s", - (char *)translate_id(ob_name).c_str(), - (char *)getAnimationPathId(fcu).c_str(), - axis_name); + anim_id, + sizeof(anim_id), + "%s_%s_%s", + (char *)translate_id(ob_name).c_str(), + (char *)getAnimationPathId(fcu).c_str(), + axis_name); } openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); @@ -530,7 +530,7 @@ void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_ addSampler(sampler); - std::string target = translate_id(bone_name) + "/transform"; + std::string target = get_joint_id(bone, ob_arm) + "/transform"; addChannel(COLLADABU::URI(empty, sampler_id), target); closeAnimation(); diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index 634071bc90f..dcfd062470c 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -305,7 +305,10 @@ int DocumentExporter::exportCurrentScene(Scene *sce) // <library_visual_scenes> SceneExporter se(writer, &arm_exporter, this->export_settings); - +#if 0 + /* The following code seems to be an obsolete workaround + Comment out until it proofs correct that we no longer need it. + */ if (has_animations && this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) { // channels adressing <matrix> objects is not (yet) supported // So we force usage of <location>, <translation> and <scale> @@ -317,7 +320,9 @@ int DocumentExporter::exportCurrentScene(Scene *sce) else { se.setExportTransformationType(this->export_settings->export_transformation_type); } - +#else + se.setExportTransformationType(this->export_settings->export_transformation_type); +#endif se.exportScene(sce); // <scene> diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 435eaa0208a..f7fdfb06a40 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -508,9 +508,9 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA std::vector<Object *> *root_objects = new std::vector<Object *>(); fprintf(stderr, - "Writing node id='%s', name='%s'\n", - id.c_str(), - name.c_str()); + "Writing node id='%s', name='%s'\n", + id.c_str(), + name.c_str()); if (is_joint) { if (parent_node == NULL && !is_library_node) { diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp index b8b1ff7fd95..8a9ccbbed51 100644 --- a/source/blender/collada/GeometryExporter.cpp +++ b/source/blender/collada/GeometryExporter.cpp @@ -396,7 +396,7 @@ void GeometryExporter::createPolylist(short material_index, ostr << translate_id(material_id); facelist->setMaterial(ostr.str()); } - + COLLADASW::InputList &til = facelist->getInputList(); // creates <input> in <polylist> for vertices @@ -718,12 +718,13 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me) source.setArrayId(layer_id + ARRAY_ID_SUFFIX); source.setAccessorCount(me->totloop); - source.setAccessorStride(3); + source.setAccessorStride(4); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); param.push_back("R"); param.push_back("G"); param.push_back("B"); + param.push_back("A"); source.prepareToAppendValues(); @@ -735,7 +736,8 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me) source.appendValues( mlc->r / 255.0f, mlc->g / 255.0f, - mlc->b / 255.0f + mlc->b / 255.0f, + mlc->a / 255.0f ); } } diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp index e3dfd69d8ec..40db5efda27 100644 --- a/source/blender/compositor/intern/COM_compositor.cpp +++ b/source/blender/compositor/intern/COM_compositor.cpp @@ -64,9 +64,21 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende /* Make sure node tree has previews. * Don't create previews in advance, this is done when adding preview operations. * Reserved preview size is determined by render output for now. + * + * We fit the aspect into COM_PREVIEW_SIZE x COM_PREVIEW_SIZE image to avoid + * insane preview resolution, which might even overflow preview dimensions. */ - float aspect = rd->xsch > 0 ? (float)rd->ysch / (float)rd->xsch : 1.0f; - BKE_node_preview_init_tree(editingtree, COM_PREVIEW_SIZE, (int)(COM_PREVIEW_SIZE * aspect), false); + const float aspect = rd->xsch > 0 ? (float)rd->ysch / (float)rd->xsch : 1.0f; + int preview_width, preview_height; + if (aspect < 1.0f) { + preview_width = COM_PREVIEW_SIZE; + preview_height = (int)(COM_PREVIEW_SIZE * aspect); + } + else { + preview_width = (int)(COM_PREVIEW_SIZE / aspect); + preview_height = COM_PREVIEW_SIZE; + } + BKE_node_preview_init_tree(editingtree, preview_width, preview_height, false); /* initialize workscheduler, will check if already done. TODO deinitialize somewhere */ bool use_opencl = (editingtree->flag & NTREE_COM_OPENCL) != 0; diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cpp b/source/blender/compositor/nodes/COM_CompositorNode.cpp index 9e8b40d8af4..4754f23a167 100644 --- a/source/blender/compositor/nodes/COM_CompositorNode.cpp +++ b/source/blender/compositor/nodes/COM_CompositorNode.cpp @@ -41,6 +41,7 @@ void CompositorNode::convertToOperations(NodeConverter &converter, const Composi NodeInput *depthSocket = this->getInputSocket(2); CompositorOperation *compositorOperation = new CompositorOperation(); + compositorOperation->setScene(context.getScene()); compositorOperation->setSceneName(context.getScene()->id.name); compositorOperation->setRenderData(context.getRenderData()); compositorOperation->setViewName(context.getViewName()); diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp index 75128de2d84..2286db81860 100644 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp @@ -15,8 +15,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Jeroen Bakker + * Contributor: + * Jeroen Bakker * Monique Dewanchand */ @@ -25,16 +25,22 @@ #include "COM_TranslateOperation.h" #include "COM_RotateOperation.h" #include "COM_ScaleOperation.h" +#include "COM_SetColorOperation.h" #include "COM_SetValueOperation.h" +#include "COM_SetVectorOperation.h" RenderLayersNode::RenderLayersNode(bNode *editorNode) : Node(editorNode) { /* pass */ } -void RenderLayersNode::testSocketLink(NodeConverter &converter, const CompositorContext &context, - NodeOutput *output, RenderLayersProg *operation, - Scene *scene, int layerId, bool is_preview) const +void RenderLayersNode::testSocketLink(NodeConverter &converter, + const CompositorContext &context, + NodeOutput *output, + RenderLayersProg *operation, + Scene *scene, + int layerId, + bool is_preview) const { operation->setScene(scene); operation->setLayerId(layerId); @@ -43,45 +49,140 @@ void RenderLayersNode::testSocketLink(NodeConverter &converter, const Compositor converter.mapOutputSocket(output, operation->getOutputSocket()); converter.addOperation(operation); - + if (is_preview) /* only for image socket */ converter.addPreview(operation->getOutputSocket()); } -void RenderLayersNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const +void RenderLayersNode::testRenderLink(NodeConverter &converter, + const CompositorContext &context, + Render *re) const { Scene *scene = (Scene *)this->getbNode()->id; - short layerId = this->getbNode()->custom1; - Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL; - int numberOfOutputs = this->getNumberOfOutputSockets(); - - if (re) { - RenderResult *rr = RE_AcquireResultRead(re); - if (rr) { - SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, layerId); - if (srl) { - RenderLayer *rl = RE_GetRenderLayer(rr, srl->name); - if (rl) { - for (int i = 0; i < numberOfOutputs; i++) { - NodeOutput *output = this->getOutputSocket(i); - NodeImageLayer *storage = (NodeImageLayer*) output->getbNodeSocket()->storage; - RenderPass *rpass = (RenderPass*) BLI_findstring(&rl->passes, storage->pass_name, offsetof(RenderPass, name)); - if (rpass) { - if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && STREQ(output->getbNodeSocket()->name, "Alpha")) { - testSocketLink(converter, context, output, new RenderLayersAlphaProg(rpass->name, COM_DT_VALUE, rpass->channels), scene, layerId, false); - } - else if (STREQ(rpass->name, RE_PASSNAME_Z)) { - testSocketLink(converter, context, output, new RenderLayersDepthProg(rpass->name, COM_DT_VALUE, rpass->channels), scene, layerId, false); - } - else { - DataType type = ((rpass->channels == 4)? COM_DT_COLOR : ((rpass->channels == 3)? COM_DT_VECTOR : COM_DT_VALUE)); - testSocketLink(converter, context, output, new RenderLayersProg(rpass->name, type, rpass->channels), scene, layerId, STREQ(output->getbNodeSocket()->name, "Image")); - } - } - } - } + const short layerId = this->getbNode()->custom1; + RenderResult *rr = RE_AcquireResultRead(re); + if (rr == NULL) { + missingRenderLink(converter); + return; + } + SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, layerId); + if (srl == NULL) { + missingRenderLink(converter); + return; + } + RenderLayer *rl = RE_GetRenderLayer(rr, srl->name); + if (rl == NULL) { + missingRenderLink(converter); + return; + } + const int num_outputs = this->getNumberOfOutputSockets(); + for (int i = 0; i < num_outputs; i++) { + NodeOutput *output = this->getOutputSocket(i); + NodeImageLayer *storage = (NodeImageLayer*) output->getbNodeSocket()->storage; + RenderPass *rpass = (RenderPass*) BLI_findstring( + &rl->passes, + storage->pass_name, + offsetof(RenderPass, name)); + if (rpass == NULL) { + missingSocketLink(converter, output); + continue; + } + RenderLayersProg *operation; + bool is_preview; + if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && + STREQ(output->getbNodeSocket()->name, "Alpha")) + { + operation = new RenderLayersAlphaProg(rpass->name, + COM_DT_VALUE, + rpass->channels); + is_preview = false; + } + else if (STREQ(rpass->name, RE_PASSNAME_Z)) { + operation = new RenderLayersDepthProg(rpass->name, + COM_DT_VALUE, + rpass->channels); + is_preview = false; + } + else { + DataType type; + switch (rpass->channels) { + case 4: type = COM_DT_COLOR; break; + case 3: type = COM_DT_VECTOR; break; + case 1: type = COM_DT_VALUE; break; + default: + BLI_assert(!"Unexpected number of channels for pass"); + type = COM_DT_VALUE; + break; } + operation = new RenderLayersProg(rpass->name, + type, + rpass->channels); + is_preview = STREQ(output->getbNodeSocket()->name, "Image"); + } + testSocketLink(converter, + context, + output, + operation, + scene, + layerId, + is_preview); + } +} + +void RenderLayersNode::missingSocketLink(NodeConverter &converter, + NodeOutput *output) const +{ + NodeOperation *operation; + switch (output->getDataType()) { + case COM_DT_COLOR: + { + const float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + SetColorOperation *color_operation = new SetColorOperation(); + color_operation->setChannels(color); + operation = color_operation; + break; + } + case COM_DT_VECTOR: + { + const float vector[3] = {0.0f, 0.0f, 0.0f}; + SetVectorOperation *vector_operation = new SetVectorOperation(); + vector_operation->setVector(vector); + operation = vector_operation; + break; + } + case COM_DT_VALUE: + { + SetValueOperation *value_operation = new SetValueOperation(); + value_operation->setValue(0.0f); + operation = value_operation; + break; } + } + + converter.mapOutputSocket(output, operation->getOutputSocket()); + converter.addOperation(operation); +} + +void RenderLayersNode::missingRenderLink(NodeConverter &converter) const +{ + const int num_outputs = this->getNumberOfOutputSockets(); + for (int i = 0; i < num_outputs; i++) { + NodeOutput *output = this->getOutputSocket(i); + missingSocketLink(converter, output); + } +} + +void RenderLayersNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + Scene *scene = (Scene *)this->getbNode()->id; + Render *re = (scene) ? RE_GetSceneRender(scene) : NULL; + + if (re != NULL) { + testRenderLink(converter, context, re); RE_ReleaseResult(re); } + else { + missingRenderLink(converter); + } } diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.h b/source/blender/compositor/nodes/COM_RenderLayersNode.h index 1f733a9f4bb..5c6c5e17d1f 100644 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.h +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.h @@ -24,6 +24,8 @@ #include "DNA_node_types.h" #include "COM_RenderLayersProg.h" +struct Render; + /** * @brief RenderLayersNode * @ingroup Node @@ -31,7 +33,8 @@ class RenderLayersNode : public Node { public: RenderLayersNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const; private: void testSocketLink(NodeConverter &converter, const CompositorContext &context, @@ -40,4 +43,11 @@ private: Scene *scene, int layerId, bool is_preview) const; + void testRenderLink(NodeConverter &converter, + const CompositorContext &context, + Render *re) const; + + void missingSocketLink(NodeConverter &converter, + NodeOutput *output) const; + void missingRenderLink(NodeConverter &converter) const; }; diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp index 76f74c144f6..15ffff2fc90 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cpp +++ b/source/blender/compositor/operations/COM_CompositorOperation.cpp @@ -51,6 +51,7 @@ CompositorOperation::CompositorOperation() : NodeOperation() this->m_useAlphaInput = false; this->m_active = false; + this->m_scene = NULL; this->m_sceneName[0] = '\0'; this->m_viewName = NULL; } @@ -78,7 +79,7 @@ void CompositorOperation::deinitExecution() return; if (!isBreaked()) { - Render *re = RE_GetRender(this->m_sceneName); + Render *re = RE_GetSceneRender(this->m_scene); RenderResult *rr = RE_AcquireResultWrite(re); if (rr) { @@ -217,7 +218,7 @@ void CompositorOperation::determineResolution(unsigned int resolution[2], unsign // check actual render resolution with cropping it may differ with cropped border.rendering // FIX for: [31777] Border Crop gives black (easy) - Render *re = RE_GetRender(this->m_sceneName); + Render *re = RE_GetSceneRender(this->m_scene); if (re) { RenderResult *rr = RE_AcquireResultRead(re); if (rr) { diff --git a/source/blender/compositor/operations/COM_CompositorOperation.h b/source/blender/compositor/operations/COM_CompositorOperation.h index e81ba520695..269a065a793 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.h +++ b/source/blender/compositor/operations/COM_CompositorOperation.h @@ -26,11 +26,14 @@ #include "BLI_rect.h" #include "BLI_string.h" +struct Scene; + /** * @brief Compositor output operation */ class CompositorOperation : public NodeOperation { private: + const struct Scene *m_scene; /** * @brief Scene name, used for getting the render output, includes 'SC' prefix. */ @@ -84,6 +87,7 @@ public: CompositorOperation(); const bool isActiveCompositorOutput() const { return this->m_active; } void executeRegion(rcti *rect, unsigned int tileNumber); + void setScene(const struct Scene *scene) { m_scene = scene; } void setSceneName(const char *sceneName) { BLI_strncpy(this->m_sceneName, sceneName, sizeof(this->m_sceneName)); } void setViewName(const char *viewName) { this->m_viewName = viewName; } void setRenderData(const RenderData *rd) { this->m_rd = rd; } diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp index 57aa3a1bac2..94f407dad86 100644 --- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp @@ -65,10 +65,10 @@ void GlareSimpleStarOperation::generateGlare(float *data, MemoryBuffer *inputTil } } // // B - for (y = tbuf1->getHeight() - 1 && (!breaked); y >= 0; y--) { + for (y = this->getHeight() - 1; y >= 0 && (!breaked); y--) { ym = y - i; yp = y + i; - for (x = tbuf1->getWidth() - 1; x >= 0; x--) { + for (x = this->getWidth() - 1; x >= 0; x--) { xm = x - i; xp = x + i; tbuf1->read(c, x, y); diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp index 41f7da7c49f..0c2da8415f8 100644 --- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp +++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp @@ -28,55 +28,58 @@ extern "C" { MovieClipAttributeOperation::MovieClipAttributeOperation() : NodeOperation() { this->addOutputSocket(COM_DT_VALUE); - this->m_valueSet = false; this->m_framenumber = 0; this->m_attribute = MCA_X; this->m_invert = false; } -void MovieClipAttributeOperation::executePixelSampled(float output[4], - float /*x*/, float /*y*/, - PixelSampler /*sampler*/) +void MovieClipAttributeOperation::initExecution() { - /* TODO(sergey): This code isn't really thread-safe. */ - if (!this->m_valueSet) { - float loc[2], scale, angle; - loc[0] = 0.0f; - loc[1] = 0.0f; - scale = 1.0f; - angle = 0.0f; - if (this->m_clip) { - int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_clip, this->m_framenumber); - BKE_tracking_stabilization_data_get(this->m_clip, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle); - } - switch (this->m_attribute) { - case MCA_SCALE: - this->m_value = scale; - break; - case MCA_ANGLE: - this->m_value = angle; - break; - case MCA_X: - this->m_value = loc[0]; - break; - case MCA_Y: - this->m_value = loc[1]; - break; + float loc[2], scale, angle; + loc[0] = 0.0f; + loc[1] = 0.0f; + scale = 1.0f; + angle = 0.0f; + int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame( + this->m_clip, this->m_framenumber); + BKE_tracking_stabilization_data_get(this->m_clip, + clip_framenr, + getWidth(), getHeight(), + loc, &scale, &angle); + switch (this->m_attribute) { + case MCA_SCALE: + this->m_value = scale; + break; + case MCA_ANGLE: + this->m_value = angle; + break; + case MCA_X: + this->m_value = loc[0]; + break; + case MCA_Y: + this->m_value = loc[1]; + break; + } + if (this->m_invert) { + if (this->m_attribute != MCA_SCALE) { + this->m_value = -this->m_value; } - if (this->m_invert) { - if (this->m_attribute != MCA_SCALE) { - this->m_value = -this->m_value; - } - else { - this->m_value = 1.0f / this->m_value; - } + else { + this->m_value = 1.0f / this->m_value; } - this->m_valueSet = true; } +} + +void MovieClipAttributeOperation::executePixelSampled(float output[4], + float /*x*/, float /*y*/, + PixelSampler /*sampler*/) +{ output[0] = this->m_value; } -void MovieClipAttributeOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) +void MovieClipAttributeOperation::determineResolution( + unsigned int resolution[2], + unsigned int preferredResolution[2]) { resolution[0] = preferredResolution[0]; resolution[1] = preferredResolution[1]; diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h index 731b9debaf0..659f54c1ca2 100644 --- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h +++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h @@ -39,16 +39,18 @@ class MovieClipAttributeOperation : public NodeOperation { private: MovieClip *m_clip; float m_value; - bool m_valueSet; int m_framenumber; bool m_invert; MovieClipAttribute m_attribute; + public: /** * Default constructor */ MovieClipAttributeOperation(); - + + void initExecution(); + /** * the inner loop of this program */ diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp index f2f1b211a97..d1c654ddb6c 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp @@ -48,7 +48,7 @@ RenderLayersProg::RenderLayersProg(const char *passName, DataType type, int elem void RenderLayersProg::initExecution() { Scene *scene = this->getScene(); - Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL; + Render *re = (scene) ? RE_GetSceneRender(scene) : NULL; RenderResult *rr = NULL; if (re) @@ -179,7 +179,7 @@ void RenderLayersProg::deinitExecution() void RenderLayersProg::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2]) { Scene *sce = this->getScene(); - Render *re = (sce) ? RE_GetRender(sce->id.name) : NULL; + Render *re = (sce) ? RE_GetSceneRender(sce) : NULL; RenderResult *rr = NULL; resolution[0] = 0; @@ -246,4 +246,4 @@ void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float unsigned int offset = (iy * this->getWidth() + ix); output[0] = inputBuffer[offset]; } -}
\ No newline at end of file +} diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cpp b/source/blender/compositor/operations/COM_ScaleOperation.cpp index 117ae743ee7..46e155e43b5 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.cpp +++ b/source/blender/compositor/operations/COM_ScaleOperation.cpp @@ -271,9 +271,9 @@ bool ScaleFixedSizeOperation::determineDependingAreaOfInterest(rcti *input, Read { rcti newInput; - newInput.xmax = (input->xmax - m_offsetX) * this->m_relX; + newInput.xmax = (input->xmax - m_offsetX) * this->m_relX + 1; newInput.xmin = (input->xmin - m_offsetX) * this->m_relX; - newInput.ymax = (input->ymax - m_offsetY) * this->m_relY; + newInput.ymax = (input->ymax - m_offsetY) * this->m_relY + 1; newInput.ymin = (input->ymin - m_offsetY) * this->m_relY; return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); diff --git a/source/blender/datatoc/datatoc.c b/source/blender/datatoc/datatoc.c index 4e49a9a7694..ffccca98f99 100644 --- a/source/blender/datatoc/datatoc.c +++ b/source/blender/datatoc/datatoc.c @@ -91,6 +91,11 @@ int main(int argc, char **argv) } fprintf(fpout, "/* DataToC output of file <%s> */\n\n", argv[1]); + + /* Quiet 'missing-variable-declarations' warning. */ + fprintf(fpout, "extern int datatoc_%s_size;\n", argv[1]); + fprintf(fpout, "extern char datatoc_%s[];\n\n", argv[1]); + fprintf(fpout, "int datatoc_%s_size = %d;\n", argv[1], (int)size); fprintf(fpout, "char datatoc_%s[] = {\n", argv[1]); while (size--) { diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index 945a4785b9c..59b10b95d49 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -134,6 +134,9 @@ void DEG_ids_clear_recalc(struct Main *bmain); /* Flush updates for all IDs */ void DEG_ids_flush_tagged(struct Main *bmain); +/* Flush updates for IDs in a single scene. */ +void DEG_scene_flush_update(struct Main *bmain, struct Scene *scene); + /* Check if something was changed in the database and inform * editors about this. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 086fd0c1144..e3494e4756e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -69,7 +69,7 @@ static bool check_object_needs_evaluation(Object *object) void deg_graph_build_flush_layers(Depsgraph *graph) { - BLI_Stack *stack = BLI_stack_new(sizeof(OperationDepsNode*), + BLI_Stack *stack = BLI_stack_new(sizeof(OperationDepsNode *), "DEG flush layers stack"); foreach (OperationDepsNode *node, graph->operations) { IDDepsNode *id_node = node->owner->owner; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 55f1f93be6a..17f0c030bd0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -81,6 +81,7 @@ extern "C" { #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_mask.h" #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_mball.h" @@ -320,8 +321,11 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) if (base != NULL) { id_node->layers |= base->lay; } - if (ob == scene->camera) { - /* Camera should always be updated, it used directly by viewport. */ + if (ob->type == OB_CAMERA) { + /* Camera should always be updated, it used directly by viewport. + * + * TODO(sergey): Make it only for active scene camera. + */ id_node->layers |= (unsigned int)(-1); } /* Skip rest of components if the ID node was already there. */ @@ -671,6 +675,13 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob) ComponentDepsNode *psys_comp = add_component_node(&ob->id, DEG_NODE_TYPE_EVAL_PARTICLES); + add_operation_node(psys_comp, + function_bind(BKE_particle_system_eval_init, + _1, + scene, + ob), + DEG_OPCODE_PSYS_EVAL_INIT); + /* particle systems */ LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) { ParticleSettings *part = psys->part; @@ -682,11 +693,7 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob) /* this particle system */ // TODO: for now, this will just be a placeholder "ubereval" node add_operation_node(psys_comp, - function_bind(BKE_particle_system_eval, - _1, - scene, - ob, - psys), + NULL, DEG_OPCODE_PSYS_EVAL, psys->name); } @@ -845,17 +852,6 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) "Geometry Eval"); op_node->set_as_entry(); - /* Calculate curve path - this is used by constraints, etc. */ - if (ELEM(ob->type, OB_CURVE, OB_FONT)) { - add_operation_node(obdata, - DEG_NODE_TYPE_GEOMETRY, - function_bind(BKE_curve_eval_path, - _1, - (Curve *)obdata), - DEG_OPCODE_GEOMETRY_PATH, - "Path"); - } - /* Make sure objects used for bevel.taper are in the graph. * NOTE: This objects might be not linked to the scene. */ @@ -965,7 +961,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) { ID *id = bnode->id; if (id != NULL) { - short id_type = GS(id->name); + ID_Type id_type = GS(id->name); if (id_type == ID_MA) { build_material((Material *)id); } @@ -1102,7 +1098,18 @@ void DepsgraphNodeBuilder::build_mask(Mask *mask) { ID *mask_id = &mask->id; add_id_node(mask_id); + /* F-Curve based animation/ */ build_animdata(mask_id); + /* Animation based on mask's shapes. */ + add_operation_node(mask_id, + DEG_NODE_TYPE_ANIMATION, + function_bind(BKE_mask_eval_animation, _1, mask), + DEG_OPCODE_MASK_ANIMATION); + /* Final mask evaluation. */ + add_operation_node(mask_id, + DEG_NODE_TYPE_PARAMETERS, + function_bind(BKE_mask_eval_update, _1, mask), + DEG_OPCODE_MASK_EVAL); } void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index fe7ccaa7fc0..ceb2fd25f94 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -182,6 +182,11 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE, + function_bind(BKE_pose_eval_init_ik, _1, scene, ob, ob->pose), + DEG_OPCODE_POSE_INIT_IK); + + op_node = add_operation_node(&ob->id, + DEG_NODE_TYPE_EVAL_POSE, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE); op_node->set_as_exit(); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc index 3249867e416..521276bc608 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc @@ -126,6 +126,13 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) LINKLIST_FOREACH (MovieClip *, clip, &bmain->movieclip) { build_movieclip(clip); } + + /* Parameters evaluation for scene relations mainly. */ + add_operation_node(&scene->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Scene Eval"); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 62a7d6c6ab7..d42c4047691 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -661,58 +661,74 @@ void DepsgraphRelationBuilder::build_object_parent(Object *ob) } } -void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata, - ListBase *constraints, RootPChanMap *root_map) +void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, + eDepsNode_Type component_type, + const char *component_subdata, + ListBase *constraints, + RootPChanMap *root_map) { - OperationKey constraint_op_key(id, component_type, component_subdata, - (component_type == DEG_NODE_TYPE_BONE) ? DEG_OPCODE_BONE_CONSTRAINTS : DEG_OPCODE_TRANSFORM_CONSTRAINTS); - - /* add dependencies for each constraint in turn */ + OperationKey constraint_op_key( + id, + component_type, + component_subdata, + (component_type == DEG_NODE_TYPE_BONE) + ? DEG_OPCODE_BONE_CONSTRAINTS + : DEG_OPCODE_TRANSFORM_CONSTRAINTS); + /* Add dependencies for each constraint in turn. */ for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - - /* invalid constraint type... */ - if (cti == NULL) + /* Invalid constraint type. */ + if (cti == NULL) { continue; - - /* special case for camera tracking -- it doesn't use targets to define relations */ - // TODO: we can now represent dependencies in a much richer manner, so review how this is done... - if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { + } + /* Special case for camera tracking -- it doesn't use targets to + * define relations. + */ + /* TODO: we can now represent dependencies in a much richer manner, + * so review how this is done. + */ + if (ELEM(cti->type, + CONSTRAINT_TYPE_FOLLOWTRACK, + CONSTRAINT_TYPE_CAMERASOLVER, + CONSTRAINT_TYPE_OBJECTSOLVER)) + { bool depends_on_camera = false; - if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data; - - if (((data->clip) || (data->flag & FOLLOWTRACK_ACTIVECLIP)) && data->track[0]) + if (((data->clip) || + (data->flag & FOLLOWTRACK_ACTIVECLIP)) && data->track[0]) + { depends_on_camera = true; - + } if (data->depth_ob) { - // DAG_RL_DATA_OB | DAG_RL_OB_OB - ComponentKey depth_key(&data->depth_ob->id, DEG_NODE_TYPE_TRANSFORM); - add_relation(depth_key, constraint_op_key, cti->name); + ComponentKey depth_transform_key(&data->depth_ob->id, + DEG_NODE_TYPE_TRANSFORM); + ComponentKey depth_geometry_key(&data->depth_ob->id, + DEG_NODE_TYPE_GEOMETRY); + add_relation(depth_transform_key, constraint_op_key, cti->name); + add_relation(depth_geometry_key, constraint_op_key, cti->name); } } else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) { depends_on_camera = true; } - if (depends_on_camera && scene->camera) { - // DAG_RL_DATA_OB | DAG_RL_OB_OB ComponentKey camera_key(&scene->camera->id, DEG_NODE_TYPE_TRANSFORM); add_relation(camera_key, constraint_op_key, cti->name); } - - /* TODO(sergey): This is more a TimeSource -> MovieClip -> Constraint dependency chain. */ + /* TODO(sergey): This is more a TimeSource -> MovieClip -> + * Constraint dependency chain. + */ TimeSourceKey time_src_key; add_relation(time_src_key, constraint_op_key, "[TimeSrc -> Animation]"); } else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) { - /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint dependency chain. */ + /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint + * dependency chain. + */ TimeSourceKey time_src_key; add_relation(time_src_key, constraint_op_key, "[TimeSrc -> Animation]"); - bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data; - if (data->cache_file) { ComponentKey cache_key(&data->cache_file->id, DEG_NODE_TYPE_CACHE); add_relation(cache_key, constraint_op_key, cti->name); @@ -721,52 +737,73 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode else if (cti->get_constraint_targets) { ListBase targets = {NULL, NULL}; cti->get_constraint_targets(con, &targets); - LINKLIST_FOREACH (bConstraintTarget *, ct, &targets) { if (ct->tar == NULL) { continue; } - - if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) { - /* ignore IK constraints - these are handled separately (on pose level) */ + if (ELEM(con->type, + CONSTRAINT_TYPE_KINEMATIC, + CONSTRAINT_TYPE_SPLINEIK)) + { + /* Ignore IK constraints - these are handled separately + * (on pose level). + */ } - else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) { - /* these constraints require path geometry data... */ + else if (ELEM(con->type, + CONSTRAINT_TYPE_FOLLOWPATH, + CONSTRAINT_TYPE_CLAMPTO)) + { + /* These constraints require path geometry data. */ ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY); - add_relation(target_key, constraint_op_key, cti->name); // XXX: type = geom_transform - // TODO: path dependency + add_relation(target_key, constraint_op_key, cti->name); + ComponentKey target_transform_key(&ct->tar->id, + DEG_NODE_TYPE_TRANSFORM); + add_relation(target_transform_key, constraint_op_key, cti->name); } else if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) { /* bone */ if (&ct->tar->id == id) { /* same armature */ eDepsOperation_Code target_key_opcode; - - /* Using "done" here breaks in-chain deps, while using "ready" here breaks most production rigs instead... - * So, we do a compromise here, and only do this when an IK chain conflict may occur + /* Using "done" here breaks in-chain deps, while using + * "ready" here breaks most production rigs instead. + * So, we do a compromise here, and only do this when an + * IK chain conflict may occur. */ - if (root_map->has_common_root(component_subdata, ct->subtarget)) { + if (root_map->has_common_root(component_subdata, + ct->subtarget)) + { target_key_opcode = DEG_OPCODE_BONE_READY; } else { target_key_opcode = DEG_OPCODE_BONE_DONE; } - - OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_BONE, ct->subtarget, target_key_opcode); + OperationKey target_key(&ct->tar->id, + DEG_NODE_TYPE_BONE, + ct->subtarget, + target_key_opcode); add_relation(target_key, constraint_op_key, cti->name); } else { - /* different armature - we can safely use the result of that */ - OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_BONE, ct->subtarget, DEG_OPCODE_BONE_DONE); + /* Different armature - we can safely use the result + * of that. + */ + OperationKey target_key(&ct->tar->id, + DEG_NODE_TYPE_BONE, + ct->subtarget, + DEG_OPCODE_BONE_DONE); add_relation(target_key, constraint_op_key, cti->name); } } - else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { - /* vertex group */ - /* NOTE: for now, we don't need to represent vertex groups separately... */ + else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && + (ct->subtarget[0])) + { + /* Vertex group. */ + /* NOTE: for now, we don't need to represent vertex groups + * separately. + */ ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY); add_relation(target_key, constraint_op_key, cti->name); - if (ct->tar->type == OB_MESH) { OperationDepsNode *node2 = find_operation_node(target_key); if (node2 != NULL) { @@ -778,37 +815,48 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode /* Constraints which requires the target object surface. */ ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY); add_relation(target_key, constraint_op_key, cti->name); - - /* NOTE: obdata eval now doesn't necessarily depend on the object's transform... */ - ComponentKey target_transform_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM); + /* NOTE: obdata eval now doesn't necessarily depend on the + * object's transform. + */ + ComponentKey target_transform_key(&ct->tar->id, + DEG_NODE_TYPE_TRANSFORM); add_relation(target_transform_key, constraint_op_key, cti->name); } else { - /* standard object relation */ + /* Standard object relation. */ // TODO: loc vs rot vs scale? if (&ct->tar->id == id) { /* Constraint targetting own object: - * - This case is fine IFF we're dealing with a bone constraint pointing to - * its own armature. In that case, it's just transform -> bone. - * - If however it is a real self targetting case, just make it depend on the - * previous constraint (or the pre-constraint state)... + * - This case is fine IFF we're dealing with a bone + * constraint pointing to its own armature. In that + * case, it's just transform -> bone. + * - If however it is a real self targetting case, just + * make it depend on the previous constraint (or the + * pre-constraint state). */ - if ((ct->tar->type == OB_ARMATURE) && (component_type == DEG_NODE_TYPE_BONE)) { - OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL); + if ((ct->tar->type == OB_ARMATURE) && + (component_type == DEG_NODE_TYPE_BONE)) + { + OperationKey target_key(&ct->tar->id, + DEG_NODE_TYPE_TRANSFORM, + DEG_OPCODE_TRANSFORM_FINAL); add_relation(target_key, constraint_op_key, cti->name); } else { - OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL); + OperationKey target_key(&ct->tar->id, + DEG_NODE_TYPE_TRANSFORM, + DEG_OPCODE_TRANSFORM_LOCAL); add_relation(target_key, constraint_op_key, cti->name); } } else { - /* normal object dependency */ - OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL); + /* Normal object dependency. */ + OperationKey target_key(&ct->tar->id, + DEG_NODE_TYPE_TRANSFORM, + DEG_OPCODE_TRANSFORM_FINAL); add_relation(target_key, constraint_op_key, cti->name); } } - /* Constraints which needs world's matrix for transform. * TODO(sergey): More constraints here? */ @@ -819,14 +867,14 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode CONSTRAINT_TYPE_TRANSLIKE)) { /* TODO(sergey): Add used space check. */ - ComponentKey target_transform_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM); + ComponentKey target_transform_key(&ct->tar->id, + DEG_NODE_TYPE_TRANSFORM); add_relation(target_transform_key, constraint_op_key, cti->name); } - } - - if (cti->flush_constraint_targets) + if (cti->flush_constraint_targets) { cti->flush_constraint_targets(con, &targets, 1); + } } } } @@ -927,16 +975,20 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; - /* create dependency between driver and data affected by it */ + /* Create dependency between driver and data affected by it. */ /* - direct property relationship... */ //RNAPathKey affected_key(id, fcu->rna_path); //add_relation(driver_key, affected_key, "[Driver -> Data] DepsRel"); - /* driver -> data components (for interleaved evaluation - bones/constraints/modifiers) */ - // XXX: this probably should probably be moved out into a separate function + /* Driver -> data components (for interleaved evaluation + * bones/constraints/modifiers). + */ + // XXX: this probably should probably be moved out into a separate function. if (strstr(rna_path, "pose.bones[") != NULL) { /* interleaved drivers during bone eval */ - // TODO: ideally, if this is for a constraint, it goes to said constraint + /* TODO: ideally, if this is for a constraint, it goes to said + * constraint. + */ Object *ob = (Object *)id; char *bone_name; @@ -949,7 +1001,10 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) } if (pchan) { - OperationKey bone_key(id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); + OperationKey bone_key(id, + DEG_NODE_TYPE_BONE, + pchan->name, + DEG_OPCODE_BONE_LOCAL); add_relation(driver_key, bone_key, "[Driver -> Bone]"); } else { @@ -959,30 +1014,36 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) } } else if (GS(id->name) == ID_AR && strstr(rna_path, "bones[")) { - /* drivers on armature-level bone settings (i.e. bbone stuff), - * which will affect the evaluation of corresponding pose bones + /* Drivers on armature-level bone settings (i.e. bbone stuff), + * which will affect the evaluation of corresponding pose bones. */ IDDepsNode *arm_node = m_graph->find_id_node(id); char *bone_name = BLI_str_quoted_substrN(rna_path, "bones["); if (arm_node && bone_name) { - /* find objects which use this, and make their eval callbacks depend on this */ + /* Find objects which use this, and make their eval callbacks + * depend on this. + */ foreach (DepsRelation *rel, arm_node->outlinks) { IDDepsNode *to_node = (IDDepsNode *)rel->to; - - /* we only care about objects with pose data which use this... */ + /* We only care about objects with pose data which use this. */ if (GS(to_node->id->name) == ID_OB) { Object *ob = (Object *)to_node->id; - bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name); // NOTE: ob->pose may be NULL - - if (pchan) { - OperationKey bone_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); - add_relation(driver_key, bone_key, "[Arm Bone -> Driver -> Bone]"); + /* NOTE: ob->pose may be NULL. */ + bPoseChannel *pchan = BKE_pose_channel_find_name( + ob->pose, bone_name); + if (pchan != NULL) { + OperationKey bone_key(&ob->id, + DEG_NODE_TYPE_BONE, + pchan->name, + DEG_OPCODE_BONE_LOCAL); + add_relation(driver_key, + bone_key, + "[Arm Bone -> Driver -> Bone]"); } } } - - /* free temp data */ + /* Free temp data. */ MEM_freeN(bone_name); bone_name = NULL; } @@ -993,7 +1054,9 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) } } else if (GS(id->name) == ID_OB && strstr(rna_path, "modifiers[")) { - OperationKey modifier_key(id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL); + OperationKey modifier_key(id, + DEG_NODE_TYPE_GEOMETRY, + DEG_OPCODE_GEOMETRY_UBEREVAL); if (has_node(modifier_key)) { add_relation(driver_key, modifier_key, "[Driver -> Modifier]"); } @@ -1002,7 +1065,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) } } else if (GS(id->name) == ID_KE && strstr(rna_path, "key_blocks[")) { - /* shape key driver - hook into the base geometry operation */ + /* Shape key driver - hook into the base geometry operation. */ // XXX: double check where this points Key *shape_key = (Key *)id; @@ -1016,33 +1079,44 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) else { if (GS(id->name) == ID_OB) { /* assume that driver affects a transform... */ - OperationKey local_transform_key(id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL); - add_relation(driver_key, local_transform_key, "[Driver -> Transform]"); + OperationKey local_transform_key(id, + DEG_NODE_TYPE_TRANSFORM, + DEG_OPCODE_TRANSFORM_LOCAL); + add_relation(driver_key, + local_transform_key, + "[Driver -> Transform]"); } else if (GS(id->name) == ID_KE) { ComponentKey geometry_key(id, DEG_NODE_TYPE_GEOMETRY); - add_relation(driver_key, geometry_key, "[Driver -> Shapekey Geometry]"); + add_relation(driver_key, + geometry_key, + "[Driver -> Shapekey Geometry]"); } } - - /* ensure that affected prop's update callbacks will be triggered once done */ - // TODO: implement this once the functionality to add these links exists in RNA - // XXX: the data itself could also set this, if it were to be truly initialised later? - - /* loop over variables to get the target relationships */ + /* Ensure that affected prop's update callbacks will be triggered once + * done. + */ + /* TODO: Implement this once the functionality to add these links exists + * RNA. + */ + /* XXX: the data itself could also set this, if it were to be truly + * initialised later? + */ + /* Loop over variables to get the target relationships. */ LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) { - /* only used targets */ + /* Only used targets. */ DRIVER_TARGETS_USED_LOOPER(dvar) { - if (dtar->id == NULL) + if (dtar->id == NULL) { continue; - - /* special handling for directly-named bones */ + } + /* Special handling for directly-named bones. */ if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) { Object *ob = (Object *)dtar->id; - bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); + bPoseChannel *target_pchan = + BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); if (target_pchan != NULL) { - /* get node associated with bone */ + /* Get node associated with bone. */ // XXX: watch the space! /* Some cases can't use final bone transform, for example: * - Driving the bone with itself (addressed here) @@ -1054,55 +1128,75 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) { continue; } - OperationKey target_key(dtar->id, DEG_NODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_DONE); - add_relation(target_key, driver_key, "[Bone Target -> Driver]"); + OperationKey target_key(dtar->id, + DEG_NODE_TYPE_BONE, + target_pchan->name, + DEG_OPCODE_BONE_DONE); + add_relation(target_key, + driver_key, + "[Bone Target -> Driver]"); } } else if (dtar->flag & DTAR_FLAG_STRUCT_REF) { - /* get node associated with the object's transforms */ - OperationKey target_key(dtar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL); + /* Get node associated with the object's transforms. */ + if (dtar->id == id) { + /* Ignore input dependency if we're driving properties of + * the same ID, otherwise we'll be ending up in a cyclic + * dependency here. + */ + continue; + } + OperationKey target_key(dtar->id, + DEG_NODE_TYPE_TRANSFORM, + DEG_OPCODE_TRANSFORM_FINAL); add_relation(target_key, driver_key, "[Target -> Driver]"); } else if (dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) { - /* workaround for ensuring that local bone transforms don't end up - * having to wait for pose eval to finish (to prevent cycles) + /* Workaround for ensuring that local bone transforms don't end + * up having to wait for pose eval to finish (to prevent cycles). */ Object *ob = (Object *)dtar->id; - char *bone_name = BLI_str_quoted_substrN(dtar->rna_path, "pose.bones["); - bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, bone_name); - if (bone_name) { + char *bone_name = BLI_str_quoted_substrN(dtar->rna_path, + "pose.bones["); + bPoseChannel *target_pchan = + BKE_pose_channel_find_name(ob->pose, bone_name); + if (bone_name != NULL) { MEM_freeN(bone_name); bone_name = NULL; } - if (target_pchan) { + if (target_pchan != NULL) { if (dtar->id == id && pchan != NULL && STREQ(pchan->name, target_pchan->name)) { continue; } - OperationKey bone_key(dtar->id, DEG_NODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_LOCAL); + OperationKey bone_key(dtar->id, + DEG_NODE_TYPE_BONE, + target_pchan->name, + DEG_OPCODE_BONE_LOCAL); add_relation(bone_key, driver_key, "[RNA Bone -> Driver]"); } } else { if (dtar->id == id) { - /* Ignore input dependency if we're driving properties of the same ID, - * otherwise we'll be ending up in a cyclic dependency here. + /* Ignore input dependency if we're driving properties of + * the same ID, otherwise we'll be ending up in a cyclic + * dependency here. */ continue; } - /* resolve path to get node */ - RNAPathKey target_key(dtar->id, dtar->rna_path ? dtar->rna_path : ""); + /* Resolve path to get node. */ + RNAPathKey target_key(dtar->id, + dtar->rna_path ? dtar->rna_path : ""); add_relation(target_key, driver_key, "[RNA Target -> Driver]"); } } DRIVER_TARGETS_LOOPER_END } - - /* It's quite tricky to detect if the driver actually depends on time or not, - * so for now we'll be quite conservative here about optimization and consider - * all python drivers to be depending on time. + /* It's quite tricky to detect if the driver actually depends on time or + * not, so for now we'll be quite conservative here about optimization and + * consider all python drivers to be depending on time. */ if ((driver->type == DRIVER_TYPE_PYTHON) && python_driver_depends_on_time(driver)) @@ -1239,6 +1333,13 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) OperationKey obdata_ubereval_key(&ob->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL); + OperationKey eval_init_key(&ob->id, + DEG_NODE_TYPE_EVAL_PARTICLES, + DEG_OPCODE_PSYS_EVAL_INIT); + /* TODO(sergey): Are all particle systems depends on time? + * Hair without dynamics i.e. + */ + add_relation(time_src_key, eval_init_key, "TimeSrc -> PSys"); /* particle systems */ LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) { @@ -1254,10 +1355,7 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) if (!psys_check_enabled(ob, psys, G.is_rendering)) continue; - /* TODO(sergey): Are all particle systems depends on time? - * Hair without dynamics i.e. - */ - add_relation(time_src_key, psys_key, "TimeSrc -> PSys"); + add_relation(eval_init_key, psys_key, "Init -> PSys"); /* TODO(sergey): Currently particle update is just a placeholder, * hook it to the ubereval node so particle system is getting updated @@ -1737,8 +1835,18 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) { void DepsgraphRelationBuilder::build_mask(Mask *mask) { - /* Animation. */ - build_animdata(&mask->id); + ID *mask_id = &mask->id; + /* F-Curve animation. */ + build_animdata(mask_id); + /* Own mask animation. */ + OperationKey mask_animation_key(mask_id, + DEG_NODE_TYPE_ANIMATION, + DEG_OPCODE_MASK_ANIMATION); + TimeSourceKey time_src_key; + add_relation(time_src_key, mask_animation_key, "TimeSrc -> Mask Animation"); + /* Final mask evaluation. */ + ComponentKey parameters_key(mask_id, DEG_NODE_TYPE_PARAMETERS); + add_relation(mask_animation_key, parameters_key, "Mask Animation -> Mask Eval"); } void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index be666165a0b..ca548ed33d0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -83,7 +83,15 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob, * - see notes on direction of rel below... */ bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - OperationKey solver_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER); + OperationKey pchan_local_key(&ob->id, DEG_NODE_TYPE_BONE, + pchan->name, DEG_OPCODE_BONE_LOCAL); + OperationKey init_ik_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK); + OperationKey solver_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, + rootchan->name, + DEG_OPCODE_POSE_IK_SOLVER); + + add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree"); + add_relation(init_ik_key, solver_key, "Init IK -> IK Solver"); /* IK target */ // XXX: this should get handled as part of the constraint code @@ -300,9 +308,11 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) /* attach links between pose operations */ OperationKey init_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); + OperationKey init_ik_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK); OperationKey flush_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - add_relation(init_key, flush_key, "[Pose Init -> Pose Cleanup]"); + add_relation(init_key, init_ik_key, "Pose Init -> Pose Init IK"); + add_relation(init_ik_key, flush_key, "Pose Init IK -> Pose Cleanup"); /* Make sure pose is up-to-date with armature updates. */ OperationKey armature_key(&arm->id, diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 31b4bbc7950..5adcb3a11b3 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -109,7 +109,7 @@ void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag) * nodes for update after relations update and after layer * visibility changes. */ - short idtype = GS(id->name); + ID_Type idtype = GS(id->name); if (idtype == ID_OB) { Object *object = (Object *)id; object->recalc |= (flag & OB_RECALC_ALL); @@ -277,15 +277,20 @@ void DEG_ids_flush_tagged(Main *bmain) scene != NULL; scene = (Scene *)scene->id.next) { - /* TODO(sergey): Only visible scenes? */ - if (scene->depsgraph != NULL) { - DEG::deg_graph_flush_updates( - bmain, - reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph)); - } + DEG_scene_flush_update(bmain, scene); } } +void DEG_scene_flush_update(Main *bmain, Scene *scene) +{ + if (scene->depsgraph == NULL) { + return; + } + DEG::deg_graph_flush_updates( + bmain, + reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph)); +} + /* Update dependency graph when visible scenes/layers changes. */ void DEG_graph_on_visible_update(Main *bmain, Scene *scene) { @@ -347,6 +352,12 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene) GHASH_FOREACH_END(); } scene->lay_updated |= graph->layers; + /* If graph is tagged for update, we don't need to bother with updates here, + * nodes will be re-created. + */ + if (graph->need_update) { + return; + } /* Special trick to get local view to work. */ LINKLIST_FOREACH (Base *, base, &scene->base) { Object *object = base->object; diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc index 77454cd85ec..e177c8c8ec0 100644 --- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc +++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc @@ -108,8 +108,8 @@ static const char *stringify_opcode(eDepsOperation_Code opcode) STRINGIFY_OPCODE(TRANSFORM_FINAL); STRINGIFY_OPCODE(OBJECT_UBEREVAL); STRINGIFY_OPCODE(GEOMETRY_UBEREVAL); - STRINGIFY_OPCODE(GEOMETRY_PATH); STRINGIFY_OPCODE(POSE_INIT); + STRINGIFY_OPCODE(POSE_INIT_IK); STRINGIFY_OPCODE(POSE_DONE); STRINGIFY_OPCODE(POSE_IK_SOLVER); STRINGIFY_OPCODE(POSE_SPLINE_IK_SOLVER); @@ -119,6 +119,9 @@ static const char *stringify_opcode(eDepsOperation_Code opcode) STRINGIFY_OPCODE(BONE_READY); STRINGIFY_OPCODE(BONE_DONE); STRINGIFY_OPCODE(PSYS_EVAL); + STRINGIFY_OPCODE(PSYS_EVAL_INIT); + STRINGIFY_OPCODE(MASK_ANIMATION); + STRINGIFY_OPCODE(MASK_EVAL); case DEG_NUM_OPCODES: return "SpecialCase"; #undef STRINGIFY_OPCODE diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h index c1a42941a7d..ef7b32a8d83 100644 --- a/source/blender/depsgraph/intern/depsgraph_types.h +++ b/source/blender/depsgraph/intern/depsgraph_types.h @@ -176,14 +176,14 @@ typedef enum eDepsOperation_Code { /* XXX: Placeholder - UberEval */ DEG_OPCODE_GEOMETRY_UBEREVAL, - /* Curve Objects - Path Calculation (used for path-following tools, */ - DEG_OPCODE_GEOMETRY_PATH, - /* Pose -------------------------------------------- */ - /* Init IK Trees, etc. */ + /* Init pose, clear flags, etc. */ DEG_OPCODE_POSE_INIT, + /* Initialize IK solver related pose stuff. */ + DEG_OPCODE_POSE_INIT_IK, + /* Free IK Trees + Compute Deform Matrices */ DEG_OPCODE_POSE_DONE, @@ -219,8 +219,13 @@ typedef enum eDepsOperation_Code { /* Particles --------------------------------------- */ /* XXX: placeholder - Particle System eval */ + DEG_OPCODE_PSYS_EVAL_INIT, DEG_OPCODE_PSYS_EVAL, + /* Masks ------------------------------------------- */ + DEG_OPCODE_MASK_ANIMATION, + DEG_OPCODE_MASK_EVAL, + DEG_NUM_OPCODES, } eDepsOperation_Code; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index c230ab4c8fd..0adbadeebba 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -54,6 +54,12 @@ extern "C" { namespace DEG { +enum { + COMPONENT_STATE_NONE = 0, + COMPONENT_STATE_SCHEDULED = 1, + COMPONENT_STATE_DONE = 2, +}; + namespace { // TODO(sergey): De-duplicate with depsgraph_tag,cc @@ -83,7 +89,7 @@ static void flush_init_func(void *data_v, int i) ComponentDepsNode *comp_node = node->owner; IDDepsNode *id_node = comp_node->owner; id_node->done = 0; - comp_node->done = 0; + comp_node->done = COMPONENT_STATE_NONE; node->scheduled = false; } @@ -146,7 +152,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) lib_id_recalc_data_tag(bmain, id); } - if (comp_node->done == 0) { + if (comp_node->done != COMPONENT_STATE_DONE) { Object *object = NULL; if (GS(id->name) == ID_OB) { object = (Object *)id; @@ -190,10 +196,22 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) break; } } + /* When some target changes bone, we might need to re-run the + * whole IK solver, otherwise result might be unpredictable. + */ + if (comp_node->type == DEG_NODE_TYPE_BONE) { + ComponentDepsNode *pose_comp = + id_node->find_component(DEG_NODE_TYPE_EVAL_POSE); + BLI_assert(pose_comp != NULL); + if (pose_comp->done == COMPONENT_STATE_NONE) { + queue.push_front(pose_comp->get_entry_operation()); + pose_comp->done = COMPONENT_STATE_SCHEDULED; + } + } } id_node->done = 1; - comp_node->done = 1; + comp_node->done = COMPONENT_STATE_DONE; /* Flush to nodes along links... */ /* TODO(sergey): This is mainly giving speedup due ot less queue pushes, which diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 5852ee72b19..dba060bfb29 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -4458,8 +4458,8 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle * a callback available (e.g. broken F-Curve rename) */ if (acf->name_prop(ale, &ptr, &prop)) { - const short margin_x = 3 * iroundf(UI_DPI_FAC); - const short channel_height = iroundf(ymaxc - yminc); + const short margin_x = 3 * round_fl_to_int(UI_DPI_FAC); + const short channel_height = round_fl_to_int(ymaxc - yminc); const short width = ac->ar->winx - offset - (margin_x * 2); uiBut *but; diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 2f73eb6b71c..e18560b95af 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -2247,6 +2247,8 @@ static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin } /* TODO: images? */ + default: + break; } } diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index aafd7ebb1f9..efcc3e9477c 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -149,7 +149,7 @@ int ED_markers_post_apply_transform(ListBase *markers, Scene *scene, int mode, f (side == 'L' && marker->frame < cfra) || (side == 'R' && marker->frame >= cfra)) { - marker->frame += iroundf(value); + marker->frame += round_fl_to_int(value); changed_tot++; } break; @@ -157,7 +157,7 @@ int ED_markers_post_apply_transform(ListBase *markers, Scene *scene, int mode, f case TFM_TIME_SCALE: { /* rescale the distance between the marker and the current frame */ - marker->frame = cfra + iroundf((float)(marker->frame - cfra) * value); + marker->frame = cfra + round_fl_to_int((float)(marker->frame - cfra) * value); changed_tot++; break; } @@ -195,7 +195,7 @@ TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x) int ED_markers_find_nearest_marker_time(ListBase *markers, float x) { TimeMarker *nearest = ED_markers_find_nearest_marker(markers, x); - return (nearest) ? (nearest->frame) : iroundf(x); + return (nearest) ? (nearest->frame) : round_fl_to_int(x); } @@ -895,7 +895,7 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *even case PADENTER: case LEFTMOUSE: case MIDDLEMOUSE: - if (WM_modal_tweak_exit(event, mm->event_type)) { + if (WM_event_is_modal_tweak_exit(event, mm->event_type)) { ed_marker_move_exit(C, op); WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL); WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 0eb6508f7b2..fcdd45d4ac3 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -108,7 +108,7 @@ static void change_frame_apply(bContext *C, wmOperator *op) SUBFRA = frame - (int)frame; } else { - CFRA = iroundf(frame); + CFRA = round_fl_to_int(frame); SUBFRA = 0.0f; } FRAMENUMBER_MIN_CLAMP(CFRA); @@ -301,8 +301,8 @@ static int previewrange_define_exec(bContext *C, wmOperator *op) if (efra < sfra) efra = sfra; scene->r.flag |= SCER_PRV_RANGE; - scene->r.psfra = iroundf(sfra); - scene->r.pefra = iroundf(efra); + scene->r.psfra = round_fl_to_int(sfra); + scene->r.pefra = round_fl_to_int(efra); /* send notifiers */ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 21c25f829b1..52b93edae15 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -40,6 +40,7 @@ #include "BLI_string.h" #include "DNA_anim_types.h" +#include "DNA_object_types.h" #include "DNA_texture_types.h" #include "BKE_animsys.h" @@ -1029,6 +1030,11 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op) UI_context_update_anim_flag(C); + DAG_relations_tag_update(CTX_data_main(C)); + DAG_id_tag_update(ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA); + + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); // XXX + MEM_freeN(path); } } diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index c1e82583521..071c5fab9d7 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -52,6 +52,7 @@ #include "BKE_deform.h" #include "RNA_access.h" +#include "RNA_enum_types.h" #include "ED_anim_api.h" #include "ED_keyframing.h" diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index f2a35bb1553..540886196fe 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1073,10 +1073,11 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou /* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor, * is determined by the array index for the F-Curve */ - if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { + PropertySubType prop_subtype = RNA_property_subtype(prop); + if (ELEM(prop_subtype, PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { fcu->color_mode = FCURVE_COLOR_AUTO_RGB; } - else if (RNA_property_subtype(prop), PROP_QUATERNION) { + else if (ELEM(prop_subtype, PROP_QUATERNION)) { fcu->color_mode = FCURVE_COLOR_AUTO_YRGB; } } @@ -1785,7 +1786,9 @@ static int insert_key_button_exec(bContext *C, wmOperator *op) NlaStrip *strip = (NlaStrip *)ptr.data; FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); - success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0); + if (fcu) { + success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0); + } } else if (UI_but_flag_is_set(but, UI_BUT_DRIVEN)) { /* Driven property - Find driver */ @@ -1890,27 +1893,27 @@ static int delete_key_button_exec(bContext *C, wmOperator *op) NlaStrip *strip = (NlaStrip *)ptr.data; FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0); - BLI_assert(fcu != NULL); /* NOTE: This should be true, or else we wouldn't be able to get here */ - - if (BKE_fcurve_is_protected(fcu)) { - BKE_reportf(op->reports, RPT_WARNING, - "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'", - strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2); - } - else { - /* remove the keyframe directly - * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve, - * and delete_keyframe() expects the FCurve to be part of an action - */ - bool found = false; - int i; - - /* try to find index of beztriple to get rid of */ - i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); - if (found) { - /* delete the key at the index (will sanity check + do recalc afterwards) */ - delete_fcurve_key(fcu, i, 1); - success = true; + if (fcu) { + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(op->reports, RPT_WARNING, + "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'", + strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2); + } + else { + /* remove the keyframe directly + * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve, + * and delete_keyframe() expects the FCurve to be part of an action + */ + bool found = false; + int i; + + /* try to find index of beztriple to get rid of */ + i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); + if (found) { + /* delete the key at the index (will sanity check + do recalc afterwards) */ + delete_fcurve_key(fcu, i, 1); + success = true; + } } } } diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index 4408ec26b3f..0a27fe14de7 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -1052,6 +1052,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); break; } + default: + break; } /* send notifiers for updates (this doesn't require context to work!) */ diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 47e73f9b777..51b76563c72 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -66,7 +66,7 @@ /* ************************** Object Tools Exports ******************************* */ /* NOTE: these functions are exported to the Object module to be called from the tools there */ -void ED_armature_apply_transform(Object *ob, float mat[4][4]) +void ED_armature_apply_transform(Object *ob, float mat[4][4], const bool do_props) { bArmature *arm = ob->data; @@ -74,14 +74,14 @@ void ED_armature_apply_transform(Object *ob, float mat[4][4]) ED_armature_to_edit(arm); /* Transform the bones */ - ED_armature_transform_bones(arm, mat); + ED_armature_transform_bones(arm, mat, do_props); /* Turn the list into an armature */ ED_armature_from_edit(arm); ED_armature_edit_free(arm); } -void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4]) +void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props) { EditBone *ebone; float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */ @@ -106,27 +106,29 @@ void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4]) /* apply the transformed roll back */ mat3_to_vec_roll(tmat, NULL, &ebone->roll); - ebone->rad_head *= scale; - ebone->rad_tail *= scale; - ebone->dist *= scale; - - /* we could be smarter and scale by the matrix along the x & z axis */ - ebone->xwidth *= scale; - ebone->zwidth *= scale; + if (do_props) { + ebone->rad_head *= scale; + ebone->rad_tail *= scale; + ebone->dist *= scale; + + /* we could be smarter and scale by the matrix along the x & z axis */ + ebone->xwidth *= scale; + ebone->zwidth *= scale; + } } } -void ED_armature_transform(struct bArmature *arm, float mat[4][4]) +void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props) { if (arm->edbo) { - ED_armature_transform_bones(arm, mat); + ED_armature_transform_bones(arm, mat, do_props); } else { /* Put the armature into editmode */ ED_armature_to_edit(arm); /* Transform the bones */ - ED_armature_transform_bones(arm, mat); + ED_armature_transform_bones(arm, mat, do_props); /* Go back to object mode*/ ED_armature_from_edit(arm); @@ -220,7 +222,7 @@ float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const bool vec_roll_to_mat3_normalized(nor, 0.0f, mat); /* project the new_up_axis along the normal */ - project_v3_v3v3(vec, align_axis, nor); + project_v3_v3v3_normalized(vec, align_axis, nor); sub_v3_v3v3(align_axis_proj, align_axis, vec); if (axis_only) { diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 1c342657eec..417d7c8ba3b 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -380,7 +380,7 @@ int join_armature_exec(bContext *C, wmOperator *op) if (base->object->adt) { if (ob->adt == NULL) { /* no animdata, so just use a copy of the whole thing */ - ob->adt = BKE_animdata_copy(base->object->adt, false); + ob->adt = BKE_animdata_copy(bmain, base->object->adt, false); } else { /* merge in data - we'll fix the drivers manually */ @@ -391,7 +391,7 @@ int join_armature_exec(bContext *C, wmOperator *op) if (curarm->adt) { if (arm->adt == NULL) { /* no animdata, so just use a copy of the whole thing */ - arm->adt = BKE_animdata_copy(curarm->adt, false); + arm->adt = BKE_animdata_copy(bmain, curarm->adt, false); } else { /* merge in data - we'll fix the drivers manually */ diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 8dfcd5acab8..f62073d56ef 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -39,6 +39,7 @@ #include "DNA_scene_types.h" #include "BKE_fcurve.h" +#include "BKE_nla.h" #include "BKE_context.h" #include "BKE_object.h" @@ -94,9 +95,13 @@ typedef struct tPoseSlideOp { ListBase pfLinks; /* links between posechannels and f-curves */ DLRBT_Tree keys; /* binary tree for quicker searching for keyframes (when applicable) */ - int cframe; /* current frame number */ - int prevFrame; /* frame before current frame (blend-from) */ - int nextFrame; /* frame after current frame (blend-to) */ + int cframe; /* current frame number - global time */ + + int prevFrame; /* frame before current frame (blend-from) - global time */ + int nextFrame; /* frame after current frame (blend-to) - global time */ + + float prevFrameF; /* prevFrame, but in local action time (for F-Curve lookups to work) */ + float nextFrameF; /* nextFrame, but in local action time (for F-Curve lookups to work) */ short mode; /* sliding mode (ePoseSlide_Modes) */ short flag; /* unused for now, but can later get used for storing runtime settings.... */ @@ -189,11 +194,15 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode) pso->channels = RNA_enum_get(op->ptr, "channels"); pso->axislock = RNA_enum_get(op->ptr, "axis_lock"); - /* check the settings from the context */ + /* ensure validity of the settings from the context */ if (ELEM(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action)) return 0; - else - act = pso->ob->adt->action; + + act = pso->ob->adt->action; + + /* apply NLA mapping corrections so the frame lookups work */ + pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP); + pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP); /* for each Pose-Channel which gets affected, get the F-Curves for that channel * and set the relevant transform flags... @@ -259,9 +268,9 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val) /* get keyframe values for endpoint poses to blend with */ /* previous/start */ - sVal = evaluate_fcurve(fcu, (float)pso->prevFrame); + sVal = evaluate_fcurve(fcu, pso->prevFrameF); /* next/end */ - eVal = evaluate_fcurve(fcu, (float)pso->nextFrame); + eVal = evaluate_fcurve(fcu, pso->nextFrameF); /* if both values are equal, don't do anything */ if (IS_EQF(sVal, eVal)) { @@ -483,15 +492,15 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) float quat_prev[4], quat_next[4]; /* get 2 quats */ - quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrame); - quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrame); - quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrame); - quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrame); + quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrameF); + quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrameF); + quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrameF); + quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrameF); - quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrame); - quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrame); - quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrame); - quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrame); + quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrameF); + quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrameF); + quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrameF); + quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrameF); /* perform blending */ if (pso->mode == POSESLIDE_BREAKDOWN) { @@ -543,6 +552,10 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso) /* move out one step either side */ pso->prevFrame--; pso->nextFrame++; + + /* apply NLA mapping corrections so the frame lookups work */ + pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP); + pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP); } /* for each link, handle each set of transforms */ @@ -746,6 +759,10 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p pso->nextFrame = (ak->next) ? (ak->next->cfra) : (pso->cframe + 1); RNA_int_set(op->ptr, "next_frame", pso->nextFrame); } + + /* apply NLA mapping corrections so the frame lookups work */ + pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP); + pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP); } else { BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between"); @@ -1464,7 +1481,7 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu, /* stop on matching marker if there is one */ for (ce = modeData.sel_markers.first; ce; ce = ce->next) { - if (ce->cfra == iroundf(bezt->vec[1][0])) + if (ce->cfra == round_fl_to_int(bezt->vec[1][0])) break; } diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h index 856573ffab0..02c76a840f1 100644 --- a/source/blender/editors/curve/curve_intern.h +++ b/source/blender/editors/curve/curve_intern.h @@ -40,7 +40,7 @@ struct wmOperatorType; struct ViewContext; /* editfont.c */ -enum { DEL_ALL, DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL }; +enum { DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_NEXT_WORD, DEL_PREV_WORD, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL }; enum { CASE_LOWER, CASE_UPPER }; enum { LINE_BEGIN, LINE_END, PREV_CHAR, NEXT_CHAR, PREV_WORD, NEXT_WORD, PREV_LINE, NEXT_LINE, PREV_PAGE, NEXT_PAGE }; diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c index fce6425b9be..5d637b113d8 100644 --- a/source/blender/editors/curve/curve_ops.c +++ b/source/blender/editors/curve/curve_ops.c @@ -178,9 +178,10 @@ void ED_keymap_curve(wmKeyConfig *keyconf) RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_style_toggle", PKEY, KM_PRESS, KM_CTRL, 0)->ptr, "style", CU_CHINFO_SMALLCAPS); RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", DELKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_NEXT_SEL); + RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", DELKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_NEXT_WORD); RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_PREV_SEL); RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", DEL_PREV_SEL); /* same as above [#26623] */ - RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_ALL); + RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_PREV_WORD); RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", HOMEKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_BEGIN); RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", ENDKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_END); diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 34e026a3ef4..5c3a694929e 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -70,102 +70,6 @@ /* Distance between start/end points to consider cyclic */ #define STROKE_CYCLIC_DIST_PX 8 - -/* -------------------------------------------------------------------- */ - -/** \name Depth Utilities - * \{ */ - - -static float depth_read_zbuf(const ViewContext *vc, int x, int y) -{ - ViewDepths *vd = vc->rv3d->depths; - - if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) - return vd->depths[y * vd->w + x]; - else - return -1.0f; -} - -static bool depth_unproject( - const ARegion *ar, const bglMats *mats, - const int mval[2], const double depth, - float r_location_world[3]) -{ - double p[3]; - if (gluUnProject( - (double)ar->winrct.xmin + mval[0] + 0.5, - (double)ar->winrct.ymin + mval[1] + 0.5, - depth, mats->modelview, mats->projection, (const GLint *)mats->viewport, - &p[0], &p[1], &p[2])) - { - copy_v3fl_v3db(r_location_world, p); - return true; - } - return false; -} - -static bool depth_read_normal( - const ViewContext *vc, const bglMats *mats, const int mval[2], - float r_normal[3]) -{ - /* pixels surrounding */ - bool depths_valid[9] = {false}; - float coords[9][3] = {{0}}; - - ARegion *ar = vc->ar; - const ViewDepths *depths = vc->rv3d->depths; - - for (int x = 0, i = 0; x < 2; x++) { - for (int y = 0; y < 2; y++) { - const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)}; - - const double depth = (double)depth_read_zbuf(vc, mval_ofs[0], mval_ofs[1]); - if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { - if (depth_unproject(ar, mats, mval_ofs, depth, coords[i])) { - depths_valid[i] = true; - } - } - i++; - } - } - - const int edges[2][6][2] = { - /* x edges */ - {{0, 1}, {1, 2}, - {3, 4}, {4, 5}, - {6, 7}, {7, 8}}, - /* y edges */ - {{0, 3}, {3, 6}, - {1, 4}, {4, 7}, - {2, 5}, {5, 8}}, - }; - - float cross[2][3] = {{0.0f}}; - - for (int i = 0; i < 6; i++) { - for (int axis = 0; axis < 2; axis++) { - if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) { - float delta[3]; - sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]); - add_v3_v3(cross[axis], delta); - } - } - } - - cross_v3_v3v3(r_normal, cross[0], cross[1]); - - if (normalize_v3(r_normal) != 0.0f) { - return true; - } - else { - return false; - } -} - -/** \} */ - - /* -------------------------------------------------------------------- */ /** \name StrokeElem / #RNA_OperatorStrokeElement Conversion Functions @@ -308,9 +212,9 @@ static bool stroke_elem_project( ((unsigned int)mval_i[0] < depths->w) && ((unsigned int)mval_i[1] < depths->h)) { - const double depth = (double)depth_read_zbuf(&cdd->vc, mval_i[0], mval_i[1]); + const double depth = (double)ED_view3d_depth_read_cached(&cdd->vc, mval_i); if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { - if (depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) { + if (ED_view3d_depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) { is_location_world_set = true; if (r_normal_world) { zero_v3(r_normal_world); @@ -319,7 +223,7 @@ static bool stroke_elem_project( if (surface_offset != 0.0f) { const float offset = cdd->project.use_surface_offset_absolute ? 1.0f : radius; float normal[3]; - if (depth_read_normal(&cdd->vc, &cdd->mats, mval_i, normal)) { + if (ED_view3d_depth_read_cached_normal(&cdd->vc, &cdd->mats, mval_i, normal)) { madd_v3_v3fl(r_location_world, normal, offset * surface_offset); if (r_normal_world) { copy_v3_v3(r_normal_world, normal); @@ -627,7 +531,7 @@ static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event) CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW, CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE)) { - if (depth_read_normal(&cdd->vc, &cdd->mats, event->mval, normal)) { + if (ED_view3d_depth_read_cached_normal(&cdd->vc, &cdd->mats, event->mval, normal)) { if (cps->surface_plane == CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW) { float cross_a[3], cross_b[3]; cross_v3_v3v3(cross_a, rv3d->viewinv[2], normal); diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 57e731874b4..535e5d7bd28 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -1170,9 +1170,10 @@ void FONT_OT_line_break(wmOperatorType *ot) /******************* delete operator **********************/ static EnumPropertyItem delete_type_items[] = { - {DEL_ALL, "ALL", 0, "All", ""}, {DEL_NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""}, {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""}, + {DEL_NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""}, + {DEL_PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""}, {DEL_SELECTION, "SELECTION", 0, "Selection", ""}, {DEL_NEXT_SEL, "NEXT_OR_SELECTION", 0, "Next or Selection", ""}, {DEL_PREV_SEL, "PREVIOUS_OR_SELECTION", 0, "Previous or Selection", ""}, @@ -1183,7 +1184,9 @@ static int delete_exec(bContext *C, wmOperator *op) Object *obedit = CTX_data_edit_object(C); Curve *cu = obedit->data; EditFont *ef = cu->editfont; - int x, selstart, selend, type = RNA_enum_get(op->ptr, "type"); + int selstart, selend, type = RNA_enum_get(op->ptr, "type"); + int range[2] = {0, 0}; + bool has_select = false; if (ef->len == 0) return OPERATOR_CANCELLED; @@ -1191,6 +1194,7 @@ static int delete_exec(bContext *C, wmOperator *op) if (BKE_vfont_select_get(obedit, &selstart, &selend)) { if (type == DEL_NEXT_SEL) type = DEL_SELECTION; else if (type == DEL_PREV_SEL) type = DEL_SELECTION; + has_select = true; } else { if (type == DEL_NEXT_SEL) type = DEL_NEXT_CHAR; @@ -1198,10 +1202,6 @@ static int delete_exec(bContext *C, wmOperator *op) } switch (type) { - case DEL_ALL: - ef->len = ef->pos = 0; - ef->textbuf[0] = 0; - break; case DEL_SELECTION: if (!kill_selection(obedit, 0)) return OPERATOR_CANCELLED; @@ -1210,29 +1210,69 @@ static int delete_exec(bContext *C, wmOperator *op) if (ef->pos <= 0) return OPERATOR_CANCELLED; - for (x = ef->pos; x <= ef->len; x++) - ef->textbuf[x - 1] = ef->textbuf[x]; - for (x = ef->pos; x <= ef->len; x++) - ef->textbufinfo[x - 1] = ef->textbufinfo[x]; + range[0] = ef->pos - 1; + range[1] = ef->pos; ef->pos--; - ef->textbuf[--ef->len] = '\0'; break; case DEL_NEXT_CHAR: if (ef->pos >= ef->len) return OPERATOR_CANCELLED; - for (x = ef->pos; x < ef->len; x++) - ef->textbuf[x] = ef->textbuf[x + 1]; - for (x = ef->pos; x < ef->len; x++) - ef->textbufinfo[x] = ef->textbufinfo[x + 1]; + range[0] = ef->pos; + range[1] = ef->pos + 1; + break; + case DEL_NEXT_WORD: + { + int pos = ef->pos; + BLI_str_cursor_step_wchar(ef->textbuf, ef->len, &pos, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, true); + range[0] = ef->pos; + range[1] = pos; + break; + } - ef->textbuf[--ef->len] = '\0'; + case DEL_PREV_WORD: + { + int pos = ef->pos; + BLI_str_cursor_step_wchar(ef->textbuf, ef->len, &pos, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, true); + range[0] = pos; + range[1] = ef->pos; + ef->pos = pos; break; + } default: return OPERATOR_CANCELLED; } + if (range[0] != range[1]) { + BLI_assert(range[0] < range[1]); + int len_remove = range[1] - range[0]; + int len_tail = ef->len - range[1]; + if (has_select) { + for (int i = 0; i < 2; i++) { + int *sel = i ? &ef->selend : &ef->selstart; + if (*sel <= range[0]) { + /* pass */ + } + else if (*sel >= range[1]) { + *sel -= len_remove; + } + else if (*sel < range[1]) { + /* pass */ + *sel = range[0]; + } + } + } + + memmove(&ef->textbuf[range[0]], &ef->textbuf[range[1]], sizeof(*ef->textbuf) * len_tail); + memmove(&ef->textbufinfo[range[0]], &ef->textbufinfo[range[1]], sizeof(*ef->textbufinfo) * len_tail); + + ef->len -= len_remove; + ef->textbuf[ef->len] = '\0'; + + BKE_vfont_select_clamp(obedit); + } + text_update_edited(C, obedit, FO_EDIT); return OPERATOR_FINISHED; @@ -1253,7 +1293,7 @@ void FONT_OT_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_enum(ot->srna, "type", delete_type_items, DEL_ALL, "Type", "Which part of the text to delete"); + RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PREV_CHAR, "Type", "Which part of the text to delete"); } /*********************** insert text operator *************************/ diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index ecab37c729f..c08ed0db400 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -1732,10 +1732,10 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, AReg rctf rectf; ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */ - offsx = iroundf(rectf.xmin); - offsy = iroundf(rectf.ymin); - winx = iroundf(rectf.xmax - rectf.xmin); - winy = iroundf(rectf.ymax - rectf.ymin); + offsx = round_fl_to_int(rectf.xmin); + offsy = round_fl_to_int(rectf.ymin); + winx = round_fl_to_int(rectf.xmax - rectf.xmin); + winy = round_fl_to_int(rectf.ymax - rectf.ymin); } else { offsx = 0; diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index bd4856f1b93..90d44503013 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -252,8 +252,10 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl) for (gpf = gpl->frames.first; gpf; gpf = gpfn) { gpfn = gpf->next; - if (gpf->flag & GP_FRAME_SELECT) - changed |= BKE_gpencil_layer_delframe(gpl, gpf); + if (gpf->flag & GP_FRAME_SELECT) { + BKE_gpencil_layer_delframe(gpl, gpf); + changed = true; + } } return changed; @@ -314,7 +316,7 @@ void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type) */ /* globals for copy/paste data (like for other copy/paste buffers) */ -ListBase gp_anim_copybuf = {NULL, NULL}; +static ListBase gp_anim_copybuf = {NULL, NULL}; static int gp_anim_copy_firstframe = 999999999; static int gp_anim_copy_lastframe = -999999999; static int gp_anim_copy_cfra = 0; diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index 5332bec0c64..e5fb162a96c 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -710,7 +710,7 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in } else { /* ERROR */ - BLI_assert("3D stroke being sculpted in non-3D view"); + BLI_assert(!"3D stroke being sculpted in non-3D view"); } } else { diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index fc6df49cf6c..55a3fc09f2e 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -343,7 +343,7 @@ ListBase gp_strokes_copypastebuf = {NULL, NULL}; * This is needed to prevent dangling and unsafe pointers when pasting across datablocks, * or after a color used by a stroke in the buffer gets deleted (via user action or undo). */ -GHash *gp_strokes_copypastebuf_colors = NULL; +static GHash *gp_strokes_copypastebuf_colors = NULL; /* Free copy/paste buffer data */ void ED_gpencil_strokes_copybuf_free(void) diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 59b5b41f114..83e2a85db49 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -117,8 +117,8 @@ static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_t /* Interpolate all values */ interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor); - pt->pressure = interpf(prev->pressure, next->pressure, factor); - pt->strength = interpf(prev->strength, next->strength, factor); + pt->pressure = interpf(prev->pressure, next->pressure, 1.0f - factor); + pt->strength = interpf(prev->strength, next->strength, 1.0f - factor); CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); } } @@ -284,7 +284,9 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) new_stroke = MEM_dupallocN(gps_from); new_stroke->points = MEM_dupallocN(gps_from->points); new_stroke->triangles = MEM_dupallocN(gps_from->triangles); - + new_stroke->tot_triangles = 0; + new_stroke->flag |= GP_STROKE_RECALC_CACHES; + if (valid) { /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { @@ -302,6 +304,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points)); new_stroke->tot_triangles = 0; new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles)); + new_stroke->flag |= GP_STROKE_RECALC_CACHES; } /* add to strokes */ @@ -986,7 +989,9 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) new_stroke = MEM_dupallocN(gps_from); new_stroke->points = MEM_dupallocN(gps_from->points); new_stroke->triangles = MEM_dupallocN(gps_from->triangles); - + new_stroke->tot_triangles = 0; + new_stroke->flag |= GP_STROKE_RECALC_CACHES; + /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 78e1a0dda36..3a2169798e5 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -99,8 +99,8 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, DKEY); /* Pie Menu - For standard tools */ - WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_tool_palette", QKEY, KM_PRESS, 0, DKEY); - WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_settings_palette", WKEY, KM_PRESS, 0, DKEY); + WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_tool_palette", QKEY, KM_PRESS, 0, DKEY); + WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_settings_palette", WKEY, KM_PRESS, 0, DKEY); /* Add Blank Frame */ /* XXX: BKEY or NKEY? BKEY is easier to reach from DKEY, so we'll use that for now */ @@ -135,7 +135,7 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, 0); /* Pie Menu - For settings/tools easy access */ - WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_sculpt", EKEY, KM_PRESS, 0, DKEY); + WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_sculpt", EKEY, KM_PRESS, 0, DKEY); /* Brush Settings */ /* NOTE: We cannot expose these in the standard keymap, as they will interfere with regular hotkeys diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 4a4ab832b28..68a5dd8a94e 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -124,6 +124,15 @@ typedef struct bAnimListElem { void *key_data; /* motion data - mostly F-Curves, but can be other types too */ + /* NOTE: id here is the "IdAdtTemplate"-style datablock (e.g. Object, Material, Texture, NodeTree) + * from which evaluation of the RNA-paths takes place. It's used to figure out how deep + * channels should be nested (e.g. for Textures/NodeTrees) in the tree, and allows property + * lookups (e.g. for sliders and for inserting keyframes) to work. If we had instead used + * bAction or something similar, none of this would be possible: although it's trivial + * to use an IdAdtTemplate type to find the source action a channel (e.g. F-Curve) comes from + * (i.e. in the AnimEditors, it *must* be the active action, as only that can be edited), + * it's impossible to go the other way (i.e. one action may be used in multiple places). + */ struct ID *id; /* ID block that channel is attached to */ struct AnimData *adt; /* source of the animation data attached to ID block (for convenience) */ @@ -256,7 +265,7 @@ typedef enum eAnimFilter_Flags { ANIMFILTER_TMP_PEEK = (1 << 30), /* ignore ONLYSEL flag from filterflag, (internal use only!) */ - ANIMFILTER_TMP_IGNORE_ONLYSEL = (1 << 31) + ANIMFILTER_TMP_IGNORE_ONLYSEL = (1u << 31) } eAnimFilter_Flags; /* ---------- Flag Checking Macros ------------ */ diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 6b8943421bd..9130336228d 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -158,9 +158,9 @@ void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]); void transform_armature_mirror_update(struct Object *obedit); void ED_armature_origin_set(struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around); -void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4]); -void ED_armature_apply_transform(struct Object *ob, float mat[4][4]); -void ED_armature_transform(struct bArmature *arm, float mat[4][4]); +void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props); +void ED_armature_apply_transform(struct Object *ob, float mat[4][4], const bool do_props); +void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props); #define ARM_GROUPS_NAME 1 #define ARM_GROUPS_ENVELOPE 2 diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 6b1e3051d2b..b5e54a56996 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -285,6 +285,7 @@ bool ED_mesh_uv_texture_remove_active(struct Mesh *me); bool ED_mesh_uv_texture_remove_named(struct Mesh *me, const char *name); void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me); void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum); +bool ED_mesh_color_ensure(struct Mesh *me, const char *name); int ED_mesh_color_add(struct Mesh *me, const char *name, const bool active_set); bool ED_mesh_color_remove_index(struct Mesh *me, const int n); bool ED_mesh_color_remove_active(struct Mesh *me); diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index ebd2a3dcb7a..9a0a7f8f1bb 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -148,7 +148,8 @@ int BIF_countTransformOrientation(const struct bContext *C); #define P_CORRECT_UV (1 << 8) #define P_NO_DEFAULTS (1 << 10) #define P_NO_TEXSPACE (1 << 11) -#define P_GPENCIL_EDIT (1 << 12) +#define P_CENTER (1 << 12) +#define P_GPENCIL_EDIT (1 << 13) void Transform_Properties(struct wmOperatorType *ot, int flags); @@ -159,12 +160,6 @@ void BIF_draw_manipulator(const struct bContext *C); /* Snapping */ -typedef enum SnapSelect { - SNAP_ALL = 0, - SNAP_NOT_SELECTED = 1, - SNAP_NOT_ACTIVE = 2, -} SnapSelect; - #define SNAP_MIN_DISTANCE 30 bool peelObjectsTransform( @@ -187,11 +182,7 @@ bool snapObjectsTransform( /* return args */ float r_loc[3], float r_no[3]); bool snapNodesTransform( - struct TransInfo *t, const int mval[2], SnapSelect snap_select, - /* return args */ - float r_loc[2], float *r_dist_px, char *r_node_border); -bool snapNodesContext( - struct bContext *C, const int mval[2], SnapSelect snap_select, + struct TransInfo *t, const int mval[2], /* return args */ float r_loc[2], float *r_dist_px, char *r_node_border); diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index 8066adf55ce..e440e8c8389 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -40,6 +40,12 @@ struct View3D; /* ED_transform_snap_object_*** API */ +typedef enum SnapSelect { + SNAP_ALL = 0, + SNAP_NOT_SELECTED = 1, + SNAP_NOT_ACTIVE = 2, +} SnapSelect; + /** used for storing multiple hits */ struct SnapObjectHitDepth { struct SnapObjectHitDepth *next, *prev; diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index d5c301d98d6..85fb0ee4447 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -106,7 +106,14 @@ void ED_view3d_lastview_store(struct RegionView3D *rv3d); /* Depth buffer */ void ED_view3d_depth_update(struct ARegion *ar); -float ED_view3d_depth_read_cached(const struct ViewContext *vc, int x, int y); +float ED_view3d_depth_read_cached(const struct ViewContext *vc, const int mval[2]); +bool ED_view3d_depth_read_cached_normal( + const ViewContext *vc, const struct bglMats *mats, const int mval[2], + float r_normal[3]); +bool ED_view3d_depth_unproject( + const struct ARegion *ar, const struct bglMats *mats, + const int mval[2], const double depth, + float r_location_world[3]); void ED_view3d_depth_tag_update(struct RegionView3D *rv3d); /* Projection */ diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 252c199d46c..e14a3a3ff0a 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -212,6 +212,8 @@ enum { UI_BUT_ALIGN_STITCH_TOP = (1 << 18), UI_BUT_ALIGN_STITCH_LEFT = (1 << 19), UI_BUT_ALIGN_ALL = (UI_BUT_ALIGN | UI_BUT_ALIGN_STITCH_TOP | UI_BUT_ALIGN_STITCH_LEFT), + + UI_BUT_BOX_ITEM = (1 << 20), /* This but is "inside" a box item (currently used to change theme colors). */ }; /* scale fixed button widths by this to account for DPI */ @@ -994,7 +996,7 @@ void uiItemsFullEnumO( struct IDProperty *properties, int context, int flag); void uiItemsFullEnumO_items( uiLayout *layout, struct wmOperatorType *ot, PointerRNA ptr, PropertyRNA *prop, - IDProperty *properties, int context, int flag, + struct IDProperty *properties, int context, int flag, const EnumPropertyItem *item_array, int totitem); void uiItemL(uiLayout *layout, const char *name, int icon); /* label */ @@ -1082,7 +1084,7 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p); /* Float precision helpers */ -#define UI_PRECISION_FLOAT_MAX 7 +#define UI_PRECISION_FLOAT_MAX 6 /* For float buttons the 'step' (or a1), is scaled */ #define UI_PRECISION_FLOAT_SCALE 0.01f diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index f8a5f30a596..a0efd586af5 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -303,7 +303,6 @@ enum { TH_EDGE_BEVEL, TH_VERTEX_BEVEL }; -/* XXX WARNING: previous is saved in file, so do not change order! */ /* specific defines per space should have higher define values */ diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 4caacb65f5f..4c0493a881c 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -203,6 +203,7 @@ bool UI_view2d_view_to_region_clip(struct View2D *v2d, float x, float y, int *r void UI_view2d_view_to_region(struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL(); void UI_view2d_view_to_region_fl(struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL(); +void UI_view2d_view_to_region_m4(struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL(); void UI_view2d_view_to_region_rcti(struct View2D *v2d, const struct rctf *rect_src, struct rcti *rect_dst) ATTR_NONNULL(); bool UI_view2d_view_to_region_rcti_clip(struct View2D *v2d, const struct rctf *rect_src, struct rcti *rect_dst) ATTR_NONNULL(); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index bcb1e3e648a..5c05fc8c530 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -488,6 +488,9 @@ static int ui_but_calc_float_precision(uiBut *but, double value) else if (prec == -1) { prec = (but->hardmax < 10.001f) ? 3 : 2; } + else { + CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX); + } return UI_calc_float_precision(prec, value); } @@ -684,7 +687,7 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu if (oldbut->active) { /* flags from the buttons we want to refresh, may want to add more here... */ - const int flag_copy = UI_BUT_REDALERT; + const int flag_copy = UI_BUT_REDALERT | UI_HAS_ICON; found_active = true; @@ -1165,6 +1168,8 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) uiBut *but; char buf[128]; + BLI_assert(block->flag & UI_BLOCK_LOOP); + /* only do it before bounding */ if (block->rect.xmin != block->rect.xmax) return; @@ -1179,6 +1184,9 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) } else { for (but = block->buttons.first; but; but = but->next) { + if (but->dt != UI_EMBOSS_PULLDOWN) { + continue; + } if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) { ui_but_add_shortcut(but, buf, false); @@ -1932,13 +1940,14 @@ void ui_but_value_set(uiBut *but, double value) else { /* first do rounding */ if (but->pointype == UI_BUT_POIN_CHAR) { - value = (char)floor(value + 0.5); + value = round_db_to_uchar_clamp(value); } else if (but->pointype == UI_BUT_POIN_SHORT) { - value = (short)floor(value + 0.5); + value = round_db_to_short_clamp(value); + } + else if (but->pointype == UI_BUT_POIN_INT) { + value = round_db_to_int_clamp(value); } - else if (but->pointype == UI_BUT_POIN_INT) - value = (int)floor(value + 0.5); else if (but->pointype == UI_BUT_POIN_FLOAT) { float fval = (float)value; if (fval >= -0.00001f && fval <= 0.00001f) fval = 0.0f; /* prevent negative zero */ @@ -2146,9 +2155,14 @@ static float ui_get_but_step_unit(uiBut *but, float step_default) /** * \param float_precision For number buttons the precision to use or -1 to fallback to the button default. + * \param use_exp_float Use exponent representation of floats when out of reasonable range (outside of 1e3/1e-3). */ -void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision) +void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision, const bool use_exp_float, bool *r_use_exp_float) { + if (r_use_exp_float) { + *r_use_exp_float = false; + } + if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { PropertyType type; const char *buf = NULL; @@ -2216,17 +2230,38 @@ void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int ui_get_but_string_unit(but, str, maxlen, value, false, float_precision); } else { - const int prec = (float_precision == -1) ? ui_but_calc_float_precision(but, value) : float_precision; - BLI_snprintf(str, maxlen, "%.*f", prec, value); + int prec = (float_precision == -1) ? ui_but_calc_float_precision(but, value) : float_precision; + if (use_exp_float) { + const int int_digits_num = integer_digits_f(value); + if (int_digits_num < -6 || int_digits_num > 12) { + BLI_snprintf(str, maxlen, "%.*g", prec, value); + if (r_use_exp_float) { + *r_use_exp_float = true; + } + } + else { + prec -= int_digits_num; + CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX); + BLI_snprintf(str, maxlen, "%.*f", prec, value); + } + } + else { +#if 0 /* TODO, but will likely break some stuff, so better after 2.79 release. */ + prec -= int_digits_num; + CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX); +#endif + BLI_snprintf(str, maxlen, "%.*f", prec, value); + } } } - else + else { BLI_snprintf(str, maxlen, "%d", (int)value); + } } } void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) { - ui_but_string_get_ex(but, str, maxlen, -1); + ui_but_string_get_ex(but, str, maxlen, -1, false, NULL); } /** @@ -2448,7 +2483,9 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str) return false; } - if (!ui_but_is_float(but)) value = (int)floor(value + 0.5); + if (!ui_but_is_float(but)) { + value = floor(value + 0.5); + } /* not that we use hard limits here */ if (value < (double)but->hardmin) value = but->hardmin; diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index a3f0e29065d..5349744af6c 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1440,87 +1440,82 @@ static bool ui_selectcontext_begin( const bool is_array = RNA_property_array_check(prop); const int rna_type = RNA_property_type(prop); - if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) { - goto finally; - } - - selctx_data->elems_len = BLI_listbase_count(&lb); - if (selctx_data->elems_len == 0) { - goto finally; - } - - selctx_data->elems = MEM_mallocN(sizeof(uiSelectContextElem) * selctx_data->elems_len, __func__); + if (UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path) && + !BLI_listbase_is_empty(&lb)) + { + selctx_data->elems_len = BLI_listbase_count(&lb); + selctx_data->elems = MEM_mallocN(sizeof(uiSelectContextElem) * selctx_data->elems_len, __func__); - for (i = 0, link = lb.first; i < selctx_data->elems_len; i++, link = link->next) { - uiSelectContextElem *other = &selctx_data->elems[i]; - /* TODO,. de-duplicate copy_to_selected_button */ - if (link->ptr.data != ptr.data) { - if (use_path_from_id) { - /* Path relative to ID. */ - lprop = NULL; - RNA_id_pointer_create(link->ptr.id.data, &idptr); - RNA_path_resolve_property(&idptr, path, &lptr, &lprop); - } - else if (path) { - /* Path relative to elements from list. */ - lprop = NULL; - RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); - } - else { - lptr = link->ptr; - lprop = prop; - } + for (i = 0, link = lb.first; i < selctx_data->elems_len; i++, link = link->next) { + uiSelectContextElem *other = &selctx_data->elems[i]; + /* TODO,. de-duplicate copy_to_selected_button */ + if (link->ptr.data != ptr.data) { + if (use_path_from_id) { + /* Path relative to ID. */ + lprop = NULL; + RNA_id_pointer_create(link->ptr.id.data, &idptr); + RNA_path_resolve_property(&idptr, path, &lptr, &lprop); + } + else if (path) { + /* Path relative to elements from list. */ + lprop = NULL; + RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); + } + else { + lptr = link->ptr; + lprop = prop; + } - /* lptr might not be the same as link->ptr! */ - if ((lptr.data != ptr.data) && - (lprop == prop) && - RNA_property_editable(&lptr, lprop)) - { - other->ptr = lptr; - if (is_array) { - if (rna_type == PROP_FLOAT) { - other->val_f = RNA_property_float_get_index(&lptr, lprop, index); - } - else if (rna_type == PROP_INT) { - other->val_i = RNA_property_int_get_index(&lptr, lprop, index); - } - /* ignored for now */ + /* lptr might not be the same as link->ptr! */ + if ((lptr.data != ptr.data) && + (lprop == prop) && + RNA_property_editable(&lptr, lprop)) + { + other->ptr = lptr; + if (is_array) { + if (rna_type == PROP_FLOAT) { + other->val_f = RNA_property_float_get_index(&lptr, lprop, index); + } + else if (rna_type == PROP_INT) { + other->val_i = RNA_property_int_get_index(&lptr, lprop, index); + } + /* ignored for now */ #if 0 - else if (rna_type == PROP_BOOLEAN) { - other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index); - } + else if (rna_type == PROP_BOOLEAN) { + other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index); + } #endif - } - else { - if (rna_type == PROP_FLOAT) { - other->val_f = RNA_property_float_get(&lptr, lprop); } - else if (rna_type == PROP_INT) { - other->val_i = RNA_property_int_get(&lptr, lprop); - } - /* ignored for now */ + else { + if (rna_type == PROP_FLOAT) { + other->val_f = RNA_property_float_get(&lptr, lprop); + } + else if (rna_type == PROP_INT) { + other->val_i = RNA_property_int_get(&lptr, lprop); + } + /* ignored for now */ #if 0 - else if (rna_type == PROP_BOOLEAN) { - other->val_b = RNA_property_boolean_get(&lptr, lprop); - } - else if (rna_type == PROP_ENUM) { - other->val_i = RNA_property_enum_get(&lptr, lprop); - } + else if (rna_type == PROP_BOOLEAN) { + other->val_b = RNA_property_boolean_get(&lptr, lprop); + } + else if (rna_type == PROP_ENUM) { + other->val_i = RNA_property_enum_get(&lptr, lprop); + } #endif - } + } - continue; + continue; + } } + + selctx_data->elems_len -= 1; + i -= 1; } - selctx_data->elems_len -= 1; - i -= 1; + success = (selctx_data->elems_len != 0); } } - success = (selctx_data->elems_len != 0); - -finally: if (selctx_data->elems_len == 0) { MEM_SAFE_FREE(selctx_data->elems); } @@ -2319,7 +2314,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, /* Get many decimal places, then strip trailing zeros. * note: too high values start to give strange results */ char buf_copy[UI_MAX_DRAW_STR]; - ui_but_string_get_ex(but, buf_copy, sizeof(buf_copy), UI_PRECISION_FLOAT_MAX); + ui_but_string_get_ex(but, buf_copy, sizeof(buf_copy), UI_PRECISION_FLOAT_MAX, false, NULL); BLI_str_rstrip_float_zero(buf_copy, '\0'); WM_clipboard_text_set(buf_copy, 0); @@ -3060,6 +3055,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) wmWindow *win = CTX_wm_window(C); int len; const bool is_num_but = ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER); + bool no_zero_strip = false; if (data->str) { MEM_freeN(data->str); @@ -3092,14 +3088,16 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) data->maxlen = ui_but_string_get_max_length(but); if (data->maxlen != 0) { data->str = MEM_callocN(sizeof(char) * data->maxlen, "textedit str"); - ui_but_string_get(but, data->str, data->maxlen); + /* We do not want to truncate precision to default here, it's nice to show value, + * not to edit it - way too much precision is lost then. */ + ui_but_string_get_ex(but, data->str, data->maxlen, UI_PRECISION_FLOAT_MAX, true, &no_zero_strip); } else { data->is_str_dynamic = true; data->str = ui_but_string_get_dynamic(but, &data->maxlen); } - if (ui_but_is_float(but) && !ui_but_is_unit(but) && !ui_but_anim_expression_get(but, NULL, 0)) { + if (ui_but_is_float(but) && !ui_but_is_unit(but) && !ui_but_anim_expression_get(but, NULL, 0) && !no_zero_strip) { BLI_str_rstrip_float_zero(data->str, '\0'); } @@ -4297,7 +4295,7 @@ static bool ui_numedit_but_NUM( if (!is_float) { - temp = iroundf(tempf); + temp = round_fl_to_int(tempf); temp = ui_numedit_apply_snap(temp, softmin, softmax, snap); @@ -4582,7 +4580,7 @@ static bool ui_numedit_but_SLI( tempf = softmin + f * softrange; - temp = iroundf(tempf); + temp = round_fl_to_int(tempf); if (snap) { if (tempf == softmin || tempf == softmax) { @@ -6792,8 +6790,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) /* set the prop and pointer data for python access to the hovered ui element; TODO, index could be supported as well*/ PointerRNA temp_ptr; RNA_pointer_create(NULL, &RNA_Property, but->rnaprop, &temp_ptr); - uiLayoutSetContextPointer(layout,"button_prop", &temp_ptr); - uiLayoutSetContextPointer(layout,"button_pointer", ptr); + uiLayoutSetContextPointer(layout, "button_prop", &temp_ptr); + uiLayoutSetContextPointer(layout, "button_pointer", ptr); /* second slower test, saved people finding keyframe items in menus when its not possible */ if (is_anim) @@ -7012,8 +7010,9 @@ static bool ui_but_menu(bContext *C, uiBut *but) } /* Set the operator pointer for python access */ - if (but->opptr) - uiLayoutSetContextPointer(layout,"button_operator", but->opptr); + if (but->opptr) { + uiLayoutSetContextPointer(layout, "button_operator", but->opptr); + } uiItemS(layout); } @@ -7061,7 +7060,7 @@ static bool ui_but_menu(bContext *C, uiBut *but) } uiItemFullO(layout, "UI_OT_edittranslation_init", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, 0); - mt = WM_menutype_find("WM_MT_button_context", false); + mt = WM_menutype_find("WM_MT_button_context", true); if (mt) { Menu menu = {NULL}; menu.layout = uiLayoutColumn(layout, false); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 067279777ba..ab760c40451 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -473,7 +473,9 @@ extern void ui_hsvcircle_pos_from_vals(struct uiBut *but, const rcti *rect, floa extern void ui_hsvcube_pos_from_vals(struct uiBut *but, const rcti *rect, float *hsv, float *xp, float *yp); bool ui_but_is_colorpicker_display_space(struct uiBut *but); -extern void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision) ATTR_NONNULL(); +extern void ui_but_string_get_ex( + uiBut *but, char *str, const size_t maxlen, + const int float_precision, const bool use_exp_float, bool *r_use_exp_float) ATTR_NONNULL(1, 2); extern void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) ATTR_NONNULL(); extern char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size); extern void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen) ATTR_NONNULL(); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index da43a58bc74..c21a76918e8 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -128,6 +128,8 @@ typedef struct uiItem { enum { UI_ITEM_FIXED = 1 << 0, UI_ITEM_MIN = 1 << 1, + + UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */ }; typedef struct uiButtonItem { @@ -192,8 +194,9 @@ static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_ static int ui_item_fit(int item, int pos, int all, int available, bool is_last, int alignment, float *extra_pixel) { /* available == 0 is unlimited */ - if (available == 0) + if (ELEM(0, available, all)) { return item; + } if (all > available) { /* contents is bigger than available space */ @@ -216,8 +219,9 @@ static int ui_item_fit(int item, int pos, int all, int available, bool is_last, return (int)width; } } - else + else { return item; + } } } @@ -243,7 +247,9 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool variable = (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X); if (variable) { - layout->item.flag |= UI_ITEM_MIN; + if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) { + layout->item.flag |= UI_ITEM_MIN; + } const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; /* it may seem odd that the icon only adds (UI_UNIT_X / 4) * but taking margins into account its fine */ @@ -700,7 +706,7 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *n WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, NULL); } else if (flag & UI_ITEM_R_EVENT) { - uiDefButR_prop(block, UI_BTYPE_KEY_EVENT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL); + but = uiDefButR_prop(block, UI_BTYPE_KEY_EVENT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL); } else if (flag & UI_ITEM_R_FULL_EVENT) { if (RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) { @@ -1720,6 +1726,10 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN UI_but_func_search_set(but, ui_searchbox_create_generic, rna_search_cb, but, NULL, NULL); } + else if (but->type == UI_BTYPE_SEARCH_MENU) { + /* In case we fail to find proper searchprop, so other code might have already set but->type to search menu... */ + but->type = UI_BTYPE_LABEL; + } } void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon) @@ -2306,6 +2316,10 @@ static void ui_litem_layout_column(uiLayout *litem, bool is_box) if (item->next && (!is_box || item != litem->items.first)) y -= litem->space; + + if (is_box) { + item->flag |= UI_ITEM_BOX_ITEM; + } } litem->h = litem->y - y; @@ -2457,7 +2471,6 @@ static void ui_litem_estimate_box(uiLayout *litem) uiStyle *style = litem->root->style; ui_litem_estimate_column(litem, true); - litem->item.flag &= ~UI_ITEM_MIN; litem->w += 2 * style->boxspace; litem->h += 2 * style->boxspace; } @@ -3129,8 +3142,11 @@ static void ui_item_estimate(uiItem *item) for (subitem = litem->items.first; subitem; subitem = subitem->next) ui_item_estimate(subitem); - if (BLI_listbase_is_empty(&litem->items)) + if (BLI_listbase_is_empty(&litem->items)) { + litem->w = 0; + litem->h = 0; return; + } if (litem->scale[0] != 0.0f || litem->scale[1] != 0.0f) ui_item_scale(litem, litem->scale); @@ -3266,8 +3282,18 @@ static void ui_item_layout(uiItem *item) break; } - for (subitem = litem->items.first; subitem; subitem = subitem->next) + for (subitem = litem->items.first; subitem; subitem = subitem->next) { + if (item->flag & UI_ITEM_BOX_ITEM) { + subitem->flag |= UI_ITEM_BOX_ITEM; + } ui_item_layout(subitem); + } + } + else { + if (item->flag & UI_ITEM_BOX_ITEM) { + uiButtonItem *bitem = (uiButtonItem *)item; + bitem->but->drawflag |= UI_BUT_BOX_ITEM; + } } } @@ -3384,8 +3410,9 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but) ui_item_size((uiItem *)bitem, &w, &h); /* XXX uiBut hasn't scaled yet * we can flag the button as not expandable, depending on its size */ - if (w <= 2 * UI_UNIT_X) + if (w <= 2 * UI_UNIT_X && (!but->str || but->str[0] == '\0')) { bitem->item.flag |= UI_ITEM_MIN; + } BLI_addtail(&layout->items, bitem); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index fb95cdf389b..d0c110d1db5 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -360,6 +360,9 @@ bool UI_context_copy_to_selected_list( else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); } + else if (RNA_struct_is_a(ptr->type, &RNA_FCurve)) { + *r_lb = CTX_data_collection_get(C, "selected_editable_fcurves"); + } else if (RNA_struct_is_a(ptr->type, &RNA_Node) || RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { @@ -494,51 +497,51 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll) char *path = NULL; bool use_path_from_id; CollectionPointerLink *link; - ListBase lb; - - if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) - return success; + ListBase lb = {NULL}; - for (link = lb.first; link; link = link->next) { - if (link->ptr.data != ptr.data) { - if (use_path_from_id) { - /* Path relative to ID. */ - lprop = NULL; - RNA_id_pointer_create(link->ptr.id.data, &idptr); - RNA_path_resolve_property(&idptr, path, &lptr, &lprop); - } - else if (path) { - /* Path relative to elements from list. */ - lprop = NULL; - RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); - } - else { - lptr = link->ptr; - lprop = prop; - } + if (UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path) && + !BLI_listbase_is_empty(&lb)) + { + for (link = lb.first; link; link = link->next) { + if (link->ptr.data != ptr.data) { + if (use_path_from_id) { + /* Path relative to ID. */ + lprop = NULL; + RNA_id_pointer_create(link->ptr.id.data, &idptr); + RNA_path_resolve_property(&idptr, path, &lptr, &lprop); + } + else if (path) { + /* Path relative to elements from list. */ + lprop = NULL; + RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); + } + else { + lptr = link->ptr; + lprop = prop; + } - if (lptr.data == ptr.data) { - /* lptr might not be the same as link->ptr! */ - continue; - } + if (lptr.data == ptr.data) { + /* lptr might not be the same as link->ptr! */ + continue; + } - if (lprop == prop) { - if (RNA_property_editable(&lptr, lprop)) { - if (poll) { - success = true; - break; - } - else { - if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) { - RNA_property_update(C, &lptr, prop); + if (lprop == prop) { + if (RNA_property_editable(&lptr, lprop)) { + if (poll) { success = true; + break; + } + else { + if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) { + RNA_property_update(C, &lptr, prop); + success = true; + } } } } } } } - MEM_SAFE_FREE(path); BLI_freelistN(&lb); } diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index c131bcb8e14..d53cdddb26f 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -496,14 +496,14 @@ static void ui_draw_panel_dragwidget(const rctf *rect) const int col_tint = 84; const int px = (int)U.pixelsize; - const int px_zoom = max_ii(iroundf(BLI_rctf_size_y(rect) / 22.0f), 1); + const int px_zoom = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 22.0f), 1); - const int box_margin = max_ii(iroundf((float)(px_zoom * 2.0f)), px); - const int box_size = max_ii(iroundf((BLI_rctf_size_y(rect) / 8.0f) - px), px); + const int box_margin = max_ii(round_fl_to_int((float)(px_zoom * 2.0f)), px); + const int box_size = max_ii(round_fl_to_int((BLI_rctf_size_y(rect) / 8.0f) - px), px); const int x_min = rect->xmin; const int y_min = rect->ymin; - const int y_ofs = max_ii(iroundf(BLI_rctf_size_y(rect) / 3.0f), px); + const int y_ofs = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 3.0f), px); const int x_ofs = y_ofs; int i_x, i_y; @@ -877,8 +877,8 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo for (a = 0; a < tot; a++, ps++) { if ((ps->pa->flag & PNL_SELECT) == 0) { if ((ps->orig->ofsx != ps->pa->ofsx) || (ps->orig->ofsy != ps->pa->ofsy)) { - ps->orig->ofsx = iroundf(fac * (float)ps->pa->ofsx + (1.0f - fac) * (float)ps->orig->ofsx); - ps->orig->ofsy = iroundf(fac * (float)ps->pa->ofsy + (1.0f - fac) * (float)ps->orig->ofsy); + ps->orig->ofsx = round_fl_to_int(fac * (float)ps->pa->ofsx + (1.0f - fac) * (float)ps->orig->ofsx); + ps->orig->ofsy = round_fl_to_int(fac * (float)ps->pa->ofsy + (1.0f - fac) * (float)ps->orig->ofsy); done = true; } } @@ -1615,11 +1615,11 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) PanelCategoryDyn *pc_dyn; const float aspect = ((uiBlock *)ar->uiblocks.first)->aspect; const float zoom = 1.0f / aspect; - const int px = max_ii(1, iroundf(U.pixelsize)); - const int category_tabs_width = iroundf(UI_PANEL_CATEGORY_MARGIN_WIDTH * zoom); + const int px = max_ii(1, round_fl_to_int(U.pixelsize)); + const int category_tabs_width = round_fl_to_int(UI_PANEL_CATEGORY_MARGIN_WIDTH * zoom); const float dpi_fac = UI_DPI_FAC; - const int tab_v_pad_text = iroundf((2 + ((px * 3) * dpi_fac)) * zoom); /* pading of tabs around text */ - const int tab_v_pad = iroundf((4 + (2 * px * dpi_fac)) * zoom); /* padding between tabs */ + const int tab_v_pad_text = round_fl_to_int((2 + ((px * 3) * dpi_fac)) * zoom); /* pading of tabs around text */ + const int tab_v_pad = round_fl_to_int((4 + (2 * px * dpi_fac)) * zoom); /* padding between tabs */ const float tab_curve_radius = ((px * 3) * dpi_fac) * zoom; const int roundboxtype = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT; bool is_alpha; diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 5ed94474726..1dffce43a39 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -342,11 +342,13 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) /* Tip */ if (but_tip.strinfo) { - BLI_strncpy(data->header, but_tip.strinfo, sizeof(data->lines[0])); if (enum_label.strinfo) { BLI_snprintf(data->header, sizeof(data->header), "%s: ", but_tip.strinfo); BLI_strncpy(data->active_info, enum_label.strinfo, sizeof(data->lines[0])); } + else { + BLI_snprintf(data->header, sizeof(data->header), "%s.", but_tip.strinfo); + } data->format[data->totline].style = UI_TIP_STYLE_HEADER; data->totline++; @@ -2440,7 +2442,7 @@ static void ui_block_colorpicker(uiBlock *block, float rgba[4], PointerRNA *ptr, BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, )); yco = -3.0f * UI_UNIT_Y; - bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 7, 0, 0, TIP_("Hex triplet for color (#RRGGBB)")); + bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)")); UI_but_func_set(bt, ui_colorpicker_hex_rna_cb, bt, hexcol); bt->custom_data = cpicker; uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y, butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); @@ -2952,8 +2954,8 @@ uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, co pie->block_radial->puphash = ui_popup_menu_hash(title); pie->block_radial->flag |= UI_BLOCK_RADIAL; - /* if pie is spawned by a left click, it is always assumed to be click style */ - if (event->type == LEFTMOUSE) { + /* if pie is spawned by a left click, release or click event, it is always assumed to be click style */ + if (event->type == LEFTMOUSE || ELEM(event->val, KM_RELEASE, KM_CLICK)) { pie->block_radial->pie_data.flags |= UI_PIE_CLICK_STYLE; pie->block_radial->pie_data.event = EVENT_NONE; win->lock_pie_event = EVENT_NONE; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 131584dd405..3cc16f37736 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2841,7 +2841,7 @@ static void uilist_resize_update_cb(bContext *C, void *arg1, void *UNUSED(arg2)) uiListDyn *dyn_data = ui_list->dyn_data; /* This way we get diff in number of additional items to show (positive) or hide (negative). */ - const int diff = iroundf((float)(dyn_data->resize - dyn_data->resize_prev) / (float)UI_UNIT_Y); + const int diff = round_fl_to_int((float)(dyn_data->resize - dyn_data->resize_prev) / (float)UI_UNIT_Y); if (diff != 0) { ui_list->list_grip += diff; diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index cf16cc9f50d..1927d7280f3 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -265,7 +265,7 @@ int UI_icon_from_report_type(int type) */ int UI_calc_float_precision(int prec, double value) { - static const double pow10_neg[UI_PRECISION_FLOAT_MAX + 1] = {1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7}; + static const double pow10_neg[UI_PRECISION_FLOAT_MAX + 1] = {1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6}; static const double max_pow = 10000000.0; /* pow(10, UI_PRECISION_FLOAT_MAX) */ BLI_assert(prec <= UI_PRECISION_FLOAT_MAX); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index f7f2b422724..51bf09125ba 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -3655,11 +3655,15 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct switch (but->type) { case UI_BTYPE_LABEL: - if (but->block->flag & UI_BLOCK_LOOP) - widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect); - else { - wt = widget_type(UI_WTYPE_LABEL); - fstyle = &style->widgetlabel; + wt = widget_type(UI_WTYPE_LABEL); + fstyle = &style->widgetlabel; + if (but->drawflag & UI_BUT_BOX_ITEM) { + wt->wcol_theme = &tui->wcol_box; + wt->state = widget_state; + } + else if (but->block->flag & UI_BLOCK_LOOP) { + wt->wcol_theme = &tui->wcol_menu_back; + wt->state = widget_state; } break; diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 539284030c2..4b47d0da13e 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -2758,6 +2758,24 @@ void init_userdef_do_versions(void) } } + if (!USER_VERSION_ATLEAST(278, 6)) { + /* Clear preference flags for re-use. */ + U.flag &= ~( + USER_FLAG_DEPRECATED_1 | USER_FLAG_DEPRECATED_2 | USER_FLAG_DEPRECATED_3 | + USER_FLAG_DEPRECATED_6 | USER_FLAG_DEPRECATED_7 | + USER_FLAG_DEPRECATED_9 | USER_FLAG_DEPRECATED_10); + U.uiflag &= ~( + USER_UIFLAG_DEPRECATED_7); + U.transopts &= ~( + USER_TR_DEPRECATED_2 | USER_TR_DEPRECATED_3 | USER_TR_DEPRECATED_4 | + USER_TR_DEPRECATED_6 | USER_TR_DEPRECATED_7); + U.gameflags &= ~( + USER_GL_RENDER_DEPRECATED_0 | USER_GL_RENDER_DEPRECATED_1 | + USER_GL_RENDER_DEPRECATED_3 | USER_GL_RENDER_DEPRECATED_4); + + U.uiflag |= USER_LOCK_CURSOR_ADJUST; + } + /** * Include next version bump. * diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index c78d97ef86f..c704c4ae126 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -2138,6 +2138,14 @@ void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect clamp_rctf_to_rcti(rect_dst, &rect_tmp); } +void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4]) +{ + rctf mask; + unit_m4(matrix); + BLI_rctf_rcti_copy(&mask, &v2d->mask); + BLI_rctf_transform_calc_m4_pivot_min(&v2d->cur, &mask, matrix); +} + bool UI_view2d_view_to_region_rcti_clip(View2D *v2d, const rctf *rect_src, rcti *rect_dst) { const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)}; diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index a5e90ebbe7a..975bbddd893 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -93,7 +93,7 @@ static int cachefile_open_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); - CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename)); + CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename), 0); BLI_strncpy(cache_file->filepath, filename, FILE_MAX); BKE_cachefile_reload(bmain, cache_file); diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index 35de390274c..196285cf02a 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -999,7 +999,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) if (weight) { sub_v2_v2v2(c, offco, p); - project_v2_v2v2(vec, c, no); + project_v2_v2v2_normalized(vec, c, no); w = len_v2(vec); diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index a478526dee0..6c6c106b19a 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -797,25 +797,47 @@ void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTop qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort); - /* Since the loop starts at 2, we must define the last index where the hash's differ */ - last = ((totvert >= 2) && (topo_pairs[0].hash == topo_pairs[1].hash)) ? 0 : 1; + last = 0; /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2, * but you cant ever access the last 'a' index of MirrTopoPairs */ - for (a = 2; a <= totvert; a++) { - /* printf("I %d %ld %d\n", (a-last), MirrTopoPairs[a ].hash, MirrTopoPairs[a ].v_index ); */ - if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { - if (a - last == 2) { - if (em) { - index_lookup[topo_pairs[a - 1].v_index] = (intptr_t)BM_vert_at_index(em->bm, topo_pairs[a - 2].v_index); - index_lookup[topo_pairs[a - 2].v_index] = (intptr_t)BM_vert_at_index(em->bm, topo_pairs[a - 1].v_index); + if (em) { + BMVert **vtable = em->bm->vtable; + for (a = 1; a <= totvert; a++) { + /* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */ + if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { + const int match_count = a - last; + if (match_count == 2) { + const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; + index_lookup[j] = (intptr_t)vtable[k]; + index_lookup[k] = (intptr_t)vtable[j]; + } + else if (match_count == 1) { + /* Center vertex. */ + const int j = topo_pairs[a - 1].v_index; + index_lookup[j] = (intptr_t)vtable[j]; + } + last = a; + } + } + } + else { + /* same as above, for mesh */ + for (a = 1; a <= totvert; a++) { + if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { + const int match_count = a - last; + if (match_count == 2) { + const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; + index_lookup[j] = k; + index_lookup[k] = j; } - else { - index_lookup[topo_pairs[a - 1].v_index] = topo_pairs[a - 2].v_index; - index_lookup[topo_pairs[a - 2].v_index] = topo_pairs[a - 1].v_index; + else if (match_count == 1) { + /* Center vertex. */ + const int j = topo_pairs[a - 1].v_index; + index_lookup[j] = j; } + last = a; } - last = a; } } diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index a81add7a86e..6b4f3516338 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -150,6 +150,7 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) for (i = 0; i < NUM_VALUE_KINDS; i++) { opdata->shift_value[i] = -1.0f; + opdata->initial_length[i] = -1.0f; /* note: scale for OFFSET_VALUE will get overwritten in edbm_bevel_invoke */ opdata->scale[i] = value_scale_per_inch[i] / pixels_per_inch; @@ -300,7 +301,7 @@ static void edbm_bevel_calc_initial_length(wmOperator *op, const wmEvent *event, mlen[1] = opdata->mcenter[1] - event->mval[1]; len = len_v2(mlen); vmode = opdata->value_mode; - if (mode_changed) { + if (mode_changed || opdata->initial_length[vmode] == -1.0f) { /* If current value is not default start value, adjust len so that * the scaling and offset in edbm_bevel_mouse_set_value will * start at current value */ @@ -506,6 +507,8 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) else if (opdata->value_mode == OFFSET_VALUE_PERCENT && type != BEVEL_AMT_PERCENT) opdata->value_mode = OFFSET_VALUE; RNA_property_enum_set(op->ptr, prop, type); + if (opdata->initial_length[opdata->value_mode] == -1.0f) + edbm_bevel_calc_initial_length(op, event, true); } /* Update offset accordingly to new offset_type. */ if (!has_numinput && diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 5e44509e10a..69e8fa03d72 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1206,6 +1206,7 @@ static bool knife_ray_intersect_face( for (; tri_i < tottri; tri_i++) { const float *lv1, *lv2, *lv3; + float ray_tri_uv[2]; tri = kcd->em->looptris[tri_i]; if (tri[0]->f != f) @@ -1217,7 +1218,7 @@ static bool knife_ray_intersect_face( * tesselation edge and might not hit either tesselation tri with * an exact test; * we will exclude hits near real edges by a later test */ - if (isect_ray_tri_epsilon_v3(v1, raydir, lv1, lv2, lv3, &lambda, NULL, KNIFE_FLT_EPS)) { + if (isect_ray_tri_epsilon_v3(v1, raydir, lv1, lv2, lv3, &lambda, ray_tri_uv, KNIFE_FLT_EPS)) { /* check if line coplanar with tri */ normal_tri_v3(tri_norm, lv1, lv2, lv3); plane_from_point_normal_v3(tri_plane, lv1, tri_norm); @@ -1226,8 +1227,7 @@ static bool knife_ray_intersect_face( { return false; } - copy_v3_v3(hit_cageco, v1); - madd_v3_v3fl(hit_cageco, raydir, lambda); + interp_v3_v3v3v3_uv(hit_cageco, lv1, lv2, lv3, ray_tri_uv); /* Now check that far enough away from verts and edges */ lst = knife_get_face_kedges(kcd, f); for (ref = lst->first; ref; ref = ref->next) { @@ -1239,11 +1239,7 @@ static bool knife_ray_intersect_face( return false; } } - - transform_point_by_tri_v3( - hit_co, hit_cageco, - tri[0]->v->co, tri[1]->v->co, tri[2]->v->co, - lv1, lv2, lv3); + interp_v3_v3v3v3_uv(hit_co, tri[0]->v->co, tri[1]->v->co, tri[2]->v->co, ray_tri_uv); return true; } } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 1f90b60a1f5..c513c49aa8e 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -169,7 +169,7 @@ struct EdgeRingOpSubdProps { }; -static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_default) +static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_min, const int cuts_default) { /* Note, these values must match delete_mesh() event values */ static EnumPropertyItem prop_subd_edgering_types[] = { @@ -181,7 +181,7 @@ static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_defa PropertyRNA *prop; - prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", 0, 64); + prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", cuts_min, 64); RNA_def_property_flag(prop, PROP_SKIP_SAVE); RNA_def_enum(ot->srna, "interpolation", prop_subd_edgering_types, SUBD_RING_INTERP_PATH, @@ -248,7 +248,7 @@ void MESH_OT_subdivide_edgering(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - mesh_operator_edgering_props(ot, 10); + mesh_operator_edgering_props(ot, 1, 10); } @@ -5447,7 +5447,7 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot) RNA_def_float(ot->srna, "merge_factor", 0.5f, 0.0f, 1.0f, "Merge Factor", "", 0.0f, 1.0f); RNA_def_int(ot->srna, "twist_offset", 0, -1000, 1000, "Twist", "Twist offset for closed loops", -1000, 1000); - mesh_operator_edgering_props(ot, 0); + mesh_operator_edgering_props(ot, 0, 0); } static int edbm_wireframe_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 772bb1bd308..737c8ac665d 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -252,7 +252,7 @@ void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me) { /* could be ldata or pdata */ CustomData *pdata = GET_CD_DATA(me, pdata); - const int layernum = CustomData_get_active_layer_index(pdata, CD_MTEXPOLY); + const int layernum = CustomData_get_active_layer(pdata, CD_MTEXPOLY); ED_mesh_uv_loop_reset_ex(me, layernum); WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); @@ -464,6 +464,20 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set) return layernum; } +bool ED_mesh_color_ensure(struct Mesh *me, const char *name) +{ + BLI_assert(me->edit_btmesh == NULL); + + if (!me->mloopcol && me->totloop) { + CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name); + BKE_mesh_update_customdata_pointers(me, true); + } + + DAG_id_tag_update(&me->id, 0); + + return (me->mloopcol != NULL); +} + bool ED_mesh_color_remove_index(Mesh *me, const int n) { CustomData *ldata = GET_CD_DATA(me, ldata); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index b5a9c4e9e5b..74da6817185 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1344,89 +1344,87 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, const bool use_hierarchy) { Main *bmain = CTX_data_main(C); - ListBase *lb; + ListBase *lb_duplis; DupliObject *dob; - GHash *dupli_gh = NULL, *parent_gh = NULL; - Object *object; + GHash *dupli_gh, *parent_gh = NULL; - if (!(base->object->transflag & OB_DUPLI)) + if (!(base->object->transflag & OB_DUPLI)) { return; + } - lb = object_duplilist(bmain->eval_ctx, scene, base->object); + lb_duplis = object_duplilist(bmain->eval_ctx, scene, base->object); - if (use_hierarchy || use_base_parent) { - dupli_gh = BLI_ghash_ptr_new(__func__); - if (use_hierarchy) { - if (base->object->transflag & OB_DUPLIGROUP) { - parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); - } - else { - parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); - } + dupli_gh = BLI_ghash_ptr_new(__func__); + if (use_hierarchy) { + if (base->object->transflag & OB_DUPLIGROUP) { + parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); + } + else { + parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); } } - for (dob = lb->first; dob; dob = dob->next) { - Base *basen; - Object *ob = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, dob->ob)); + for (dob = lb_duplis->first; dob; dob = dob->next) { + Object *ob_src = dob->ob; + Object *ob_dst = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, ob_src)); + Base *base_dst; /* font duplis can have a totcol without material, we get them from parent * should be implemented better... */ - if (ob->mat == NULL) ob->totcol = 0; + if (ob_dst->mat == NULL) { + ob_dst->totcol = 0; + } - basen = MEM_dupallocN(base); - basen->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP); - ob->flag = basen->flag; - basen->lay = base->lay; - BLI_addhead(&scene->base, basen); /* addhead: othwise eternal loop */ - basen->object = ob; + base_dst = MEM_dupallocN(base); + base_dst->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP); + ob_dst->flag = base_dst->flag; + base_dst->lay = base->lay; + BLI_addhead(&scene->base, base_dst); /* addhead: othwise eternal loop */ + base_dst->object = ob_dst; /* make sure apply works */ - BKE_animdata_free(&ob->id, true); - ob->adt = NULL; + BKE_animdata_free(&ob_dst->id, true); + ob_dst->adt = NULL; /* Proxies are not to be copied. */ - ob->proxy_from = NULL; - ob->proxy_group = NULL; - ob->proxy = NULL; + ob_dst->proxy_from = NULL; + ob_dst->proxy_group = NULL; + ob_dst->proxy = NULL; - ob->parent = NULL; - BKE_constraints_free(&ob->constraints); - ob->curve_cache = NULL; - ob->transflag &= ~OB_DUPLI; - ob->lay = base->lay; + ob_dst->parent = NULL; + BKE_constraints_free(&ob_dst->constraints); + ob_dst->curve_cache = NULL; + ob_dst->transflag &= ~OB_DUPLI; + ob_dst->lay = base->lay; - copy_m4_m4(ob->obmat, dob->mat); - BKE_object_apply_mat4(ob, ob->obmat, false, false); + copy_m4_m4(ob_dst->obmat, dob->mat); + BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false); - if (dupli_gh) { - BLI_ghash_insert(dupli_gh, dob, ob); - } + BLI_ghash_insert(dupli_gh, dob, ob_dst); if (parent_gh) { void **val; /* Due to nature of hash/comparison of this ghash, a lot of duplis may be considered as 'the same', * this avoids trying to insert same key several time and raise asserts in debug builds... */ if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) { - *val = ob; + *val = ob_dst; } } + } + + for (dob = lb_duplis->first; dob; dob = dob->next) { + Object *ob_src = dob->ob; + Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob); /* Remap new object to itself, and clear again newid pointer of orig object. */ - BKE_libblock_relink_to_newid(&ob->id); - set_sca_new_poins_ob(ob); - BKE_id_clear_newpoin(&dob->ob->id); + BKE_libblock_relink_to_newid(&ob_dst->id); + set_sca_new_poins_ob(ob_dst); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } + DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); - if (use_hierarchy) { - for (dob = lb->first; dob; dob = dob->next) { + if (use_hierarchy) { /* original parents */ - Object *ob_src = dob->ob; Object *ob_src_par = ob_src->parent; - - Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob); Object *ob_dst_par = NULL; /* find parent that was also made real */ @@ -1437,8 +1435,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, dob_key.ob = ob_src_par; if (base->object->transflag & OB_DUPLIGROUP) { memcpy(&dob_key.persistent_id[1], - &dob->persistent_id[1], - sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); + &dob->persistent_id[1], + sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); } else { dob_key.persistent_id[0] = dob->persistent_id[0]; @@ -1462,49 +1460,42 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, ob_dst->parent = base->object; ob_dst->partype = PAROBJECT; } - - if (ob_dst->parent) { - /* note, this may be the parent of other objects, but it should - * still work out ok */ - BKE_object_apply_mat4(ob_dst, dob->mat, false, true); - - /* to set ob_dst->orig and in case theres any other discrepicies */ - DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB); - } } - } - else if (use_base_parent) { - /* since we are ignoring the internal hierarchy - parent all to the - * base object */ - for (dob = lb->first; dob; dob = dob->next) { - /* original parents */ - Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob); - + else if (use_base_parent) { + /* since we are ignoring the internal hierarchy - parent all to the + * base object */ ob_dst->parent = base->object; ob_dst->partype = PAROBJECT; + } - /* similer to the code above, see comments */ + if (ob_dst->parent) { + /* note, this may be the parent of other objects, but it should + * still work out ok */ BKE_object_apply_mat4(ob_dst, dob->mat, false, true); + + /* to set ob_dst->orig and in case theres any other discrepicies */ DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB); } } if (base->object->transflag & OB_DUPLIGROUP && base->object->dup_group) { - for (object = bmain->object.first; object; object = object->id.next) { - if (object->proxy_group == base->object) { - object->proxy = NULL; - object->proxy_from = NULL; - DAG_id_tag_update(&object->id, OB_RECALC_OB); + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + if (ob->proxy_group == base->object) { + ob->proxy = NULL; + ob->proxy_from = NULL; + DAG_id_tag_update(&ob->id, OB_RECALC_OB); } } } - if (dupli_gh) - BLI_ghash_free(dupli_gh, NULL, NULL); - if (parent_gh) + BLI_ghash_free(dupli_gh, NULL, NULL); + if (parent_gh) { BLI_ghash_free(parent_gh, NULL, NULL); + } - free_object_duplilist(lb); + free_object_duplilist(lb_duplis); + + BKE_main_id_clear_newpoins(bmain); base->object->transflag &= ~OB_DUPLI; } @@ -1682,7 +1673,7 @@ static int convert_exec(bContext *C, wmOperator *op) * However, changing this is more design than bugfix, not to mention convoluted code below, * so that will be for later. * But at the very least, do not do that with linked IDs! */ - if ((ID_IS_LINKED_DATABLOCK(ob) || ID_IS_LINKED_DATABLOCK(ob->data)) && !keep_original) { + if ((ID_IS_LINKED_DATABLOCK(ob) || (ob->data && ID_IS_LINKED_DATABLOCK(ob->data))) && !keep_original) { keep_original = true; BKE_reportf(op->reports, RPT_INFO, "Converting some linked object/object data, enforcing 'Keep Original' option to True"); @@ -2198,6 +2189,11 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (didit) { Key *key = BKE_key_from_object(obn); + Key *oldkey = BKE_key_from_object(ob); + if (oldkey != NULL) { + ID_NEW_SET(oldkey, key); + } + if (dupflag & USER_DUP_ACT) { bActuator *act; diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index ad43c48f0b9..122330f7ede 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -625,7 +625,9 @@ static Mesh *bake_mesh_new_from_object(Main *bmain, Scene *scene, Object *ob) ED_object_editmode_load(ob); Mesh *me = BKE_mesh_new_from_object(bmain, scene, ob, 1, 2, 0, 0); - BKE_mesh_split_faces(me, true); + if (me->flag & ME_AUTOSMOOTH) { + BKE_mesh_split_faces(me, true); + } return me; } @@ -1029,7 +1031,7 @@ cage_cleanup: } else { /* if everything else fails, use the material index */ - char tmp[4]; + char tmp[5]; sprintf(tmp, "%d", i % 1000); BLI_path_suffix(name, FILE_MAX, tmp, "_"); } @@ -1159,7 +1161,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) bkr->result = OPERATOR_CANCELLED; - bkr->render = RE_NewRender(bkr->scene->id.name); + bkr->render = RE_NewSceneRender(bkr->scene); /* XXX hack to force saving to always be internal. Whether (and how) to support * external saving will be addressed later */ diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index edd7b5dd1be..4a96a2e2200 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -773,9 +773,9 @@ static void copymenu_logicbricks(Scene *scene, View3D *v3d, Object *ob) /* now copy it, this also works without logicbricks! */ clear_sca_new_poins_ob(ob); - copy_sensors(&base->object->sensors, &ob->sensors); - copy_controllers(&base->object->controllers, &ob->controllers); - copy_actuators(&base->object->actuators, &ob->actuators); + copy_sensors(&base->object->sensors, &ob->sensors, 0); + copy_controllers(&base->object->controllers, &ob->controllers, 0); + copy_actuators(&base->object->actuators, &ob->actuators, 0); set_sca_new_poins_ob(base->object); /* some menu settings */ @@ -934,7 +934,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) base->object->collision_boundtype = ob->collision_boundtype; } base->object->margin = ob->margin; - base->object->bsoft = copy_bulletsoftbody(ob->bsoft); + base->object->bsoft = copy_bulletsoftbody(ob->bsoft, 0); } else if (event == 17) { /* tex space */ @@ -1042,7 +1042,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) base->object->softflag = ob->softflag; if (base->object->soft) sbFree(base->object->soft); - base->object->soft = copy_softbody(ob->soft, false); + base->object->soft = copy_softbody(ob->soft, 0); if (!modifiers_findByType(base->object, eModifierType_Softbody)) { BLI_addhead(&base->object->modifiers, modifier_new(eModifierType_Softbody)); @@ -1158,13 +1158,16 @@ void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object) /* add/remove modifier as needed */ if (!md) { - if (pd && (pd->shape == PFIELD_SHAPE_SURFACE) && ELEM(pd->forcefield, PFIELD_GUIDE, PFIELD_TEXTURE) == 0) - if (ELEM(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE)) + if (pd && (pd->shape == PFIELD_SHAPE_SURFACE) && !ELEM(pd->forcefield, 0, PFIELD_GUIDE, PFIELD_TEXTURE)) { + if (ELEM(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE)) { ED_object_modifier_add(NULL, bmain, scene, object, NULL, eModifierType_Surface); + } + } } else { - if (!pd || pd->shape != PFIELD_SHAPE_SURFACE || pd->forcefield != PFIELD_FORCE) + if (!pd || (pd->shape != PFIELD_SHAPE_SURFACE) || ELEM(pd->forcefield, 0, PFIELD_GUIDE, PFIELD_TEXTURE)) { ED_object_modifier_remove(NULL, bmain, object, md); + } } } @@ -2106,9 +2109,9 @@ static int logicbricks_copy_exec(bContext *C, wmOperator *UNUSED(op)) /* now copy it, this also works without logicbricks! */ clear_sca_new_poins_ob(ob); - copy_sensors(&ob_iter->sensors, &ob->sensors); - copy_controllers(&ob_iter->controllers, &ob->controllers); - copy_actuators(&ob_iter->actuators, &ob->actuators); + copy_sensors(&ob_iter->sensors, &ob->sensors, 0); + copy_controllers(&ob_iter->controllers, &ob->controllers, 0); + copy_actuators(&ob_iter->actuators, &ob->actuators, 0); set_sca_new_poins_ob(ob_iter); /* some menu settings */ @@ -2169,7 +2172,7 @@ static int game_physics_copy_exec(bContext *C, wmOperator *UNUSED(op)) copy_v3_v3(ob_iter->anisotropicFriction, ob->anisotropicFriction); ob_iter->collision_boundtype = ob->collision_boundtype; ob_iter->margin = ob->margin; - ob_iter->bsoft = copy_bulletsoftbody(ob->bsoft); + ob_iter->bsoft = copy_bulletsoftbody(ob->bsoft, 0); if (ob->restrictflag & OB_RESTRICT_RENDER) ob_iter->restrictflag |= OB_RESTRICT_RENDER; else diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 3284af2df69..d5b516257a1 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1581,13 +1581,13 @@ static int make_links_data_exec(bContext *C, wmOperator *op) DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); break; case MAKE_LINKS_ANIMDATA: - BKE_animdata_copy_id((ID *)ob_dst, (ID *)ob_src, false); + BKE_animdata_copy_id(bmain, (ID *)ob_dst, (ID *)ob_src, false); if (ob_dst->data && ob_src->data) { if (ID_IS_LINKED_DATABLOCK(obdata_id)) { is_lib = true; break; } - BKE_animdata_copy_id((ID *)ob_dst->data, (ID *)ob_src->data, false); + BKE_animdata_copy_id(bmain, (ID *)ob_dst->data, (ID *)ob_src->data, false); } DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); break; @@ -2137,7 +2137,9 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo IDP_RelinkProperty(scene->gpd->id.properties); } - IDP_RelinkProperty(scene->world->id.properties); + if (scene->world) { + IDP_RelinkProperty(scene->world->id.properties); + } if (scene->clip) { IDP_RelinkProperty(scene->clip->id.properties); diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 4d7d7df0d2f..6491da4c23c 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -414,7 +414,10 @@ static void ignore_parent_tx(Main *bmain, Scene *scene, Object *ob) } } -static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_loc, bool apply_rot, bool apply_scale) +static int apply_objects_internal( + bContext *C, ReportList *reports, + bool apply_loc, bool apply_rot, bool apply_scale, + bool do_props) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -531,7 +534,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l BKE_mesh_calc_normals(me); } else if (ob->type == OB_ARMATURE) { - ED_armature_apply_transform(ob, mat); + ED_armature_apply_transform(ob, mat, do_props); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; @@ -540,12 +543,12 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l } else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; - BKE_mball_transform(mb, mat); + BKE_mball_transform(mb, mat, do_props); } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; scale = mat3_to_scale(rsmat); - BKE_curve_transform_ex(cu, mat, true, scale); + BKE_curve_transform_ex(cu, mat, true, do_props, scale); } else if (ob->type == OB_FONT) { Curve *cu = ob->data; @@ -561,7 +564,9 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l tb->h *= scale; } - cu->fsize *= scale; + if (do_props) { + cu->fsize *= scale; + } } else if (ob->type == OB_CAMERA) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); @@ -677,9 +682,10 @@ static int object_transform_apply_exec(bContext *C, wmOperator *op) const bool loc = RNA_boolean_get(op->ptr, "location"); const bool rot = RNA_boolean_get(op->ptr, "rotation"); const bool sca = RNA_boolean_get(op->ptr, "scale"); + const bool do_props = RNA_boolean_get(op->ptr, "properties"); if (loc || rot || sca) { - return apply_objects_internal(C, op->reports, loc, rot, sca); + return apply_objects_internal(C, op->reports, loc, rot, sca, do_props); } else { /* allow for redo */ @@ -704,6 +710,8 @@ void OBJECT_OT_transform_apply(wmOperatorType *ot) RNA_def_boolean(ot->srna, "location", 0, "Location", ""); RNA_def_boolean(ot->srna, "rotation", 0, "Rotation", ""); RNA_def_boolean(ot->srna, "scale", 0, "Scale", ""); + RNA_def_boolean(ot->srna, "properties", true, "Apply Properties", + "Modify properties such as curve vertex radius, font size and bone envelope"); } /********************* Set Object Center ************************/ @@ -712,7 +720,8 @@ enum { GEOMETRY_TO_ORIGIN = 0, ORIGIN_TO_GEOMETRY, ORIGIN_TO_CURSOR, - ORIGIN_TO_CENTER_OF_MASS + ORIGIN_TO_CENTER_OF_MASS_SURFACE, + ORIGIN_TO_CENTER_OF_MASS_VOLUME, }; static int object_origin_set_exec(bContext *C, wmOperator *op) @@ -866,10 +875,21 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (obedit == NULL && ob->type == OB_MESH) { Mesh *me = ob->data; - if (centermode == ORIGIN_TO_CURSOR) { /* done */ } - else if (centermode == ORIGIN_TO_CENTER_OF_MASS) { BKE_mesh_center_centroid(me, cent); } - else if (around == V3D_AROUND_CENTER_MEAN) { BKE_mesh_center_median(me, cent); } - else { BKE_mesh_center_bounds(me, cent); } + if (centermode == ORIGIN_TO_CURSOR) { + /* done */ + } + else if (centermode == ORIGIN_TO_CENTER_OF_MASS_SURFACE) { + BKE_mesh_center_of_surface(me, cent); + } + else if (centermode == ORIGIN_TO_CENTER_OF_MASS_VOLUME) { + BKE_mesh_center_of_volume(me, cent); + } + else if (around == V3D_AROUND_CENTER_MEAN) { + BKE_mesh_center_median(me, cent); + } + else { + BKE_mesh_center_bounds(me, cent); + } negate_v3_v3(cent_neg, cent); BKE_mesh_translate(me, cent_neg, 1); @@ -923,8 +943,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) cent[2] = 0.0f; - cu->xof = cu->xof - (cent[0] / cu->fsize); - cu->yof = cu->yof - (cent[1] / cu->fsize); + cu->xof = cu->xof - cent[0]; + cu->yof = cu->yof - cent[1]; tot_change++; cu->id.tag |= LIB_TAG_DOIT; @@ -1077,11 +1097,14 @@ void OBJECT_OT_origin_set(wmOperatorType *ot) static EnumPropertyItem prop_set_center_types[] = { {GEOMETRY_TO_ORIGIN, "GEOMETRY_ORIGIN", 0, "Geometry to Origin", "Move object geometry to object origin"}, {ORIGIN_TO_GEOMETRY, "ORIGIN_GEOMETRY", 0, "Origin to Geometry", - "Move object origin to center of object geometry"}, + "Calculate the center of geometry based on the current pivot point (median, otherwise bounding-box)"}, {ORIGIN_TO_CURSOR, "ORIGIN_CURSOR", 0, "Origin to 3D Cursor", - "Move object origin to position of the 3D cursor"}, - {ORIGIN_TO_CENTER_OF_MASS, "ORIGIN_CENTER_OF_MASS", 0, "Origin to Center of Mass", - "Move object origin to the object center of mass (assuming uniform density)"}, + "Move object origin to position of the 3D cursor"}, + /* Intentional naming mismatch since some scripts refer to this. */ + {ORIGIN_TO_CENTER_OF_MASS_SURFACE, "ORIGIN_CENTER_OF_MASS", 0, "Origin to Center of Mass (Surface)", + "Calculate the center of mass from the surface area"}, + {ORIGIN_TO_CENTER_OF_MASS_VOLUME, "ORIGIN_CENTER_OF_VOLUME", 0, "Origin to Center of Mass (Volume)", + "Calculate the center of mass from the volume (must be manifold geometry with consistent normals)"}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 3c406764157..584176e4b5d 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -50,7 +50,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_linklist_stack.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BKE_context.h" @@ -238,6 +238,9 @@ bool ED_vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, co } return false; } + + default: + break; } } @@ -1712,17 +1715,11 @@ static void vgroup_invert_subset(Object *ob, } } -enum { - WEIGHT_SMOOTH_ALL = -1, - WEIGHT_SMOOTH_DESELECT = false, - WEIGHT_SMOOTH_SELECT = true, -}; - static void vgroup_smooth_subset( Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int subset_count, const float fac, const int repeat, - const float fac_expand, const int source) + const float fac_expand) { const float ifac = 1.0f - fac; MDeformVert **dvert_array = NULL; @@ -1730,6 +1727,8 @@ static void vgroup_smooth_subset( int *vgroup_subset_map = BLI_array_alloca(vgroup_subset_map, subset_count); float *vgroup_subset_weights = BLI_array_alloca(vgroup_subset_weights, subset_count); const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false; + const bool use_select = vertex_group_use_vert_sel(ob); + const bool use_hide = use_select; const int expand_sign = signum_i(fac_expand); const float expand = fabsf(fac_expand); @@ -1773,19 +1772,26 @@ static void vgroup_smooth_subset( verts_used = MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__); STACK_INIT(verts_used, dvert_tot); +#define IS_BM_VERT_READ(v) \ + (use_hide ? (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == 0) : true) +#define IS_BM_VERT_WRITE(v) \ + (use_select ? (BM_elem_flag_test(v, BM_ELEM_SELECT) != 0) : true) + +#define IS_ME_VERT_READ(v) \ + (use_hide ? (((v)->flag & ME_HIDE) == 0) : true) +#define IS_ME_VERT_WRITE(v) \ + (use_select ? (((v)->flag & SELECT) != 0) : true) /* initialize used verts */ if (bm) { for (int i = 0; i < dvert_tot; i++) { BMVert *v = BM_vert_at_index(bm, i); - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + if (IS_BM_VERT_WRITE(v)) { BMIter eiter; BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { BMVert *v_other = BM_edge_other_vert(e, v); - if ((source == WEIGHT_SMOOTH_ALL) || - (source == (BM_elem_flag_test(v_other, BM_ELEM_SELECT) != 0))) - { + if (IS_BM_VERT_READ(v_other)) { STACK_PUSH(verts_used, i); break; } @@ -1795,13 +1801,12 @@ static void vgroup_smooth_subset( } else { for (int i = 0; i < dvert_tot; i++) { - MVert *v = &me->mvert[i]; - if (v->flag & SELECT) { + const MVert *v = &me->mvert[i]; + if (IS_ME_VERT_WRITE(v)) { for (int j = 0; j < emap[i].count; j++) { - MVert *v_other = &me->mvert[emap[i].indices[j]]; - if ((source == WEIGHT_SMOOTH_ALL) || - (source == ((v_other->flag & SELECT) != 0))) - { + const MEdge *e = &me->medge[emap[i].indices[j]]; + const MVert *v_other = &me->mvert[(e->v1 == i) ? e->v2 : e->v1]; + if (IS_ME_VERT_READ(v_other)) { STACK_PUSH(verts_used, i); break; } @@ -1854,13 +1859,11 @@ static void vgroup_smooth_subset( BMEdge *e; /* checked already */ - BLI_assert(BM_elem_flag_test(v, BM_ELEM_SELECT)); + BLI_assert(IS_BM_VERT_WRITE(v)); BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { BMVert *v_other = BM_edge_other_vert(e, v); - if ((source == WEIGHT_SMOOTH_ALL) || - (source == (BM_elem_flag_test(v_other, BM_ELEM_SELECT) != 0))) - { + if (IS_BM_VERT_READ(v_other)) { const int i_other = BM_elem_index_get(v_other); WEIGHT_ACCUMULATE; @@ -1871,16 +1874,14 @@ static void vgroup_smooth_subset( int j; /* checked already */ - BLI_assert(me->mvert[i].flag & SELECT); + BLI_assert(IS_ME_VERT_WRITE(&me->mvert[i])); for (j = 0; j < emap[i].count; j++) { MEdge *e = &me->medge[emap[i].indices[j]]; const int i_other = (e->v1 == i ? e->v2 : e->v1); MVert *v_other = &me->mvert[i_other]; - if ((source == WEIGHT_SMOOTH_ALL) || - (source == ((v_other->flag & SELECT) != 0))) - { + if (IS_ME_VERT_READ(v_other)) { WEIGHT_ACCUMULATE; } } @@ -1904,6 +1905,11 @@ static void vgroup_smooth_subset( ED_vgroup_parray_from_weight_array(dvert_array, dvert_tot, weight_accum_prev, def_nr, true); } +#undef IS_BM_VERT_READ +#undef IS_BM_VERT_WRITE +#undef IS_ME_VERT_READ +#undef IS_ME_VERT_WRITE + MEM_freeN(weight_accum_curr); MEM_freeN(weight_accum_prev); MEM_freeN(verts_used); @@ -2497,7 +2503,7 @@ static int UNUSED_FUNCTION(vertex_group_poll_edit) (bContext *C) } /* editmode _or_ weight paint vertex sel */ -static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_flag) +static int vertex_group_vert_poll_ex(bContext *C, const bool needs_select, const short ob_type_flag) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; @@ -2513,12 +2519,17 @@ static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_fla return true; } else if (ob->mode & OB_MODE_WEIGHT_PAINT) { - if (BKE_object_is_in_wpaint_select_vert(ob)) { - return true; + if (needs_select) { + if (BKE_object_is_in_wpaint_select_vert(ob)) { + return true; + } + else { + CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode"); + return false; + } } else { - CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode"); - return false; + return true; } } else { @@ -2526,15 +2537,31 @@ static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_fla } } +#if 0 +static int vertex_group_vert_poll(bContext *C) +{ + return vertex_group_vert_poll_ex(C, false, 0); +} +#endif + + +static int vertex_group_mesh_vert_poll(bContext *C) +{ + return vertex_group_vert_poll_ex(C, false, (1 << OB_MESH)); +} + static int vertex_group_vert_select_poll(bContext *C) { - return vertex_group_vert_select_poll_ex(C, 0); + return vertex_group_vert_poll_ex(C, true, 0); } +#if 0 static int vertex_group_mesh_vert_select_poll(bContext *C) { - return vertex_group_vert_select_poll_ex(C, (1 << OB_MESH)); + return vertex_group_vert_poll_ex(C, true, (1 << OB_MESH)); } +#endif + /* editmode _or_ weight paint vertex sel and active group unlocked */ static int vertex_group_vert_select_unlocked_poll(bContext *C) @@ -3081,13 +3108,12 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op) const float fac = RNA_float_get(op->ptr, "factor"); const int repeat = RNA_int_get(op->ptr, "repeat"); eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); - const int source = RNA_enum_get(op->ptr, "source"); const float fac_expand = RNA_float_get(op->ptr, "expand"); int subset_count, vgroup_tot; const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); - vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand, source); + vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand); MEM_freeN((void *)vgroup_validmap); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); @@ -3099,20 +3125,13 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op) void OBJECT_OT_vertex_group_smooth(wmOperatorType *ot) { - static EnumPropertyItem smooth_source_item[] = { - {WEIGHT_SMOOTH_ALL, "ALL", 0, "All", ""}, - {WEIGHT_SMOOTH_SELECT, "SELECT", 0, "Only Selected", ""}, - {WEIGHT_SMOOTH_DESELECT, "DESELECT", 0, "Only Deselected", ""}, - {0, NULL, 0, NULL, NULL} - }; - /* identifiers */ ot->name = "Smooth Vertex Weights"; ot->idname = "OBJECT_OT_vertex_group_smooth"; ot->description = "Smooth weights for selected vertices"; /* api callbacks */ - ot->poll = vertex_group_mesh_vert_select_poll; + ot->poll = vertex_group_mesh_vert_poll; ot->exec = vertex_group_smooth_exec; /* flags */ @@ -3123,7 +3142,6 @@ void OBJECT_OT_vertex_group_smooth(wmOperatorType *ot) RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200); RNA_def_float(ot->srna, "expand", 0.0f, -1.0f, 1.0, "Expand/Contract", "Expand/contract weights", -1.0f, 1.0f); - RNA_def_enum(ot->srna, "source", smooth_source_item, -1, "Source", "Vertices to mix with"); } static int vertex_group_clean_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 2541aaa4b11..72c5a74aee9 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -424,7 +424,6 @@ static bool PE_create_shape_tree(PEData *data, Object *shapeob) return false; } - DM_ensure_looptri(dm); return (bvhtree_from_mesh_looptri(&data->shape_bvh, dm, 0.0f, 4, 8) != NULL); } diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 4a4474868a2..29b652e1326 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -1035,7 +1035,7 @@ static bool copy_particle_systems_to_object(Main *bmain, psys_from; psys_from = PSYS_FROM_NEXT(psys_from), ++i) { - psys = BKE_object_copy_particlesystem(psys_from); + psys = BKE_object_copy_particlesystem(psys_from, 0); tmp_psys[i] = psys; if (psys_start == NULL) diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt index 971ab9f3458..ec8bf3e955d 100644 --- a/source/blender/editors/render/CMakeLists.txt +++ b/source/blender/editors/render/CMakeLists.txt @@ -51,16 +51,6 @@ set(SRC render_intern.h ) -if(WITH_CODEC_QUICKTIME) - list(APPEND INC - ../../quicktime - ) - list(APPEND INC_SYS - ${QUICKTIME_INCLUDE_DIRS} - ) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_HEADLESS) add_definitions(-DWITH_HEADLESS) endif() diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 43b1d033d23..26c863d8514 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -305,7 +305,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); lay_override = (v3d && v3d->lay != scene->lay) ? v3d->lay : 0; G.is_break = false; @@ -964,7 +964,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even rj->image = ima; /* setup new render */ - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); RE_test_break_cb(re, rj, render_breakjob); RE_draw_lock_cb(re, rj, render_drawlock); RE_display_update_cb(re, rj, image_rect_update); @@ -1171,7 +1171,7 @@ static void render_update_resolution(Render *re, const RenderPreview *rp, } if (rp->has_freestyle) { - if (rp->resolution_divider == 1) { + if (rp->resolution_divider == BKE_render_preview_pixel_size(&rp->scene->r)) { RE_ChangeModeFlag(re, R_EDGE_FRS, false); } else { @@ -1237,7 +1237,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda use_border = render_view3d_disprect(rp->scene, rp->ar, rp->v3d, rp->rv3d, &cliprct); - if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE)) || rstats->convertdone == 0) { + if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE | PR_UPDATE_VIEW)) || rstats->convertdone == 0) { RenderData rdata; /* no osa, blur, seq, layers, savebuffer etc for preview render */ @@ -1312,11 +1312,12 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda RE_updateRenderInstances(re, ob_inst_update_flag); for (;;) { + int pixel_size = BKE_render_preview_pixel_size(&rp->scene->r); if (first_time == false) { if (restore) RE_DataBase_IncrementalView(re, rp->viewmat, 1); - rp->resolution_divider /= 2; + rp->resolution_divider = MAX2(rp->resolution_divider/2, pixel_size); *do_update = 1; render_update_resolution(re, rp, use_border, &cliprct); @@ -1333,7 +1334,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda first_time = false; - if (*stop || rp->resolution_divider == 1) { + if (*stop || rp->resolution_divider == pixel_size) { break; } } @@ -1435,7 +1436,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); int width = ar->winx, height = ar->winy; - int divider = 1; + int divider = BKE_render_preview_pixel_size(&scene->r); int resolution_threshold = scene->r.preview_start_resolution * scene->r.preview_start_resolution; diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 01050eda70b..a27026878e1 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -681,7 +681,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) } /* create render */ - oglrender->re = RE_NewRender(scene->id.name); + oglrender->re = RE_NewSceneRender(scene); /* create image and image user */ oglrender->ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 0878636d0fa..d252d764b42 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -1298,16 +1298,16 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op) switch (freestyle_get_modifier_type(&ptr)) { case LS_MODIFIER_TYPE_COLOR: - BKE_linestyle_color_modifier_copy(lineset->linestyle, modifier); + BKE_linestyle_color_modifier_copy(lineset->linestyle, modifier, 0); break; case LS_MODIFIER_TYPE_ALPHA: - BKE_linestyle_alpha_modifier_copy(lineset->linestyle, modifier); + BKE_linestyle_alpha_modifier_copy(lineset->linestyle, modifier, 0); break; case LS_MODIFIER_TYPE_THICKNESS: - BKE_linestyle_thickness_modifier_copy(lineset->linestyle, modifier); + BKE_linestyle_thickness_modifier_copy(lineset->linestyle, modifier, 0); break; case LS_MODIFIER_TYPE_GEOMETRY: - BKE_linestyle_geometry_modifier_copy(lineset->linestyle, modifier); + BKE_linestyle_geometry_modifier_copy(lineset->linestyle, modifier, 0); break; default: BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier"); @@ -1781,6 +1781,8 @@ static void copy_mtex_copybuf(ID *id) case ID_LS: mtex = &(((FreestyleLineStyle *)id)->mtex[(int)((FreestyleLineStyle *)id)->texact]); break; + default: + break; } if (mtex && *mtex) { @@ -1818,7 +1820,7 @@ static void paste_mtex_copybuf(ID *id) mtex = &(((FreestyleLineStyle *)id)->mtex[(int)((FreestyleLineStyle *)id)->texact]); break; default: - BLI_assert("invalid id type"); + BLI_assert(!"invalid id type"); return; } diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index c165bbfd301..293e507c2b3 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -54,6 +54,7 @@ #include "ED_armature.h" #include "ED_gpencil.h" +#include "ED_anim_api.h" #include "WM_api.h" #include "UI_interface.h" @@ -87,7 +88,7 @@ const char *screen_context_dir[] = { "visible_gpencil_layers", "editable_gpencil_layers", "editable_gpencil_strokes", "active_gpencil_layer", "active_gpencil_frame", "active_gpencil_palette", "active_gpencil_palettecolor", "active_gpencil_brush", - "active_operator", + "active_operator", "selected_editable_fcurves", NULL}; int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result) @@ -608,6 +609,30 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult return 1; } } + else if (CTX_data_equals(member, "selected_editable_fcurves")) + { + bAnimContext ac; + + if (ANIM_animdata_get_context(C, &ac) && ELEM(ac.spacetype, SPACE_ACTION, SPACE_IPO)) { + bAnimListElem *ale; + ListBase anim_data = {NULL, NULL}; + + int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS | ANIMFILTER_SEL) | + (ac.spacetype == SPACE_IPO ? ANIMFILTER_CURVE_VISIBLE : ANIMFILTER_LIST_VISIBLE); + + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + for (ale = anim_data.first; ale; ale = ale->next) { + if (ale->type == ANIMTYPE_FCURVE) + CTX_data_list_add(result, ale->id, &RNA_FCurve, ale->data); + } + + ANIM_animdata_freelist(&anim_data); + + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + } else { return 0; /* not found */ } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index f469686b0b2..71b00a0a7c6 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -467,7 +467,7 @@ bScreen *ED_screen_add(wmWindow *win, Scene *scene, const char *name) bScreen *sc; ScrVert *sv1, *sv2, *sv3, *sv4; - sc = BKE_libblock_alloc(G.main, ID_SCR, name); + sc = BKE_libblock_alloc(G.main, ID_SCR, name, 0); sc->scene = scene; sc->do_refresh = true; sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN; @@ -1894,17 +1894,28 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s if (sa && sa->full) { /* restoring back to SCREENNORMAL */ - ScrArea *old; - sc = sa->full; /* the old screen to restore */ oldscreen = win->screen; /* the one disappearing */ sc->state = SCREENNORMAL; - /* find old area */ - for (old = sc->areabase.first; old; old = old->next) - if (old->full) break; - if (old == NULL) { + /* find old area to restore from */ + ScrArea *fullsa = NULL; + for (ScrArea *old = sc->areabase.first; old; old = old->next) { + /* area to restore from is always first */ + if (old->full && !fullsa) { + fullsa = old; + } + + /* clear full screen state */ + old->full = NULL; + old->flag &= ~AREA_TEMP_INFO; + } + + sa->flag &= ~AREA_TEMP_INFO; + sa->full = NULL; + + if (fullsa == NULL) { if (G.debug & G_DEBUG) printf("%s: something wrong in areafullscreen\n", __func__); return NULL; @@ -1917,9 +1928,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s } } - ED_area_data_swap(old, sa); - if (sa->flag & AREA_TEMP_INFO) sa->flag &= ~AREA_TEMP_INFO; - old->full = NULL; + ED_area_data_swap(fullsa, sa); /* animtimer back */ sc->animtimer = oldscreen->animtimer; diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index c99d9add432..27e19ca1fc3 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2260,25 +2260,28 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op) BLI_dlrbTree_linkedlist_sync(&keys); /* find matching keyframe in the right direction */ - do { - if (next) - ak = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfra); - else - ak = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfra); - - if (ak) { - if (CFRA != (int)ak->cfra) { - /* this changes the frame, so set the frame and we're done */ - CFRA = (int)ak->cfra; - done = true; + if (next) + ak = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfra); + else + ak = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfra); + + while ((ak != NULL) && (done == false)) { + if (CFRA != (int)ak->cfra) { + /* this changes the frame, so set the frame and we're done */ + CFRA = (int)ak->cfra; + done = true; + } + else { + /* take another step... */ + if (next) { + ak = ak->next; } else { - /* make this the new starting point for the search */ - cfra = ak->cfra; + ak = ak->prev; } } - } while ((ak != NULL) && (done == false)); - + } + /* free temp stuff */ BLI_dlrbTree_free(&keys); diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 46753df4e13..69f14c950bb 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -52,6 +52,10 @@ set(SRC paint_undo.c paint_utils.c paint_vertex.c + paint_vertex_color_ops.c + paint_vertex_color_utils.c + paint_vertex_weight_ops.c + paint_vertex_weight_utils.c paint_vertex_proj.c sculpt.c sculpt_undo.c diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index bf344e1f721..79ce440251d 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -1448,7 +1448,20 @@ void PAINT_OT_texture_paint_toggle(wmOperatorType *ot) static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op)) { UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; - Brush *br = image_paint_brush(C); + + Brush *br; + Object *ob = CTX_data_active_object(C); + if (!(ob && (ob->mode & OB_MODE_VERTEX_PAINT))) { + br = image_paint_brush(C); + } + else { + /* At the moment, wpaint does not support the color flipper. + * So for now we're only handling vpaint */ + ToolSettings *ts = CTX_data_tool_settings(C); + VPaint *vp = ts->vpaint; + br = BKE_paint_brush(&vp->paint); + } + if (ups->flag & UNIFIED_PAINT_COLOR) { swap_v3_v3(ups->rgb, ups->secondary_rgb); } @@ -1467,7 +1480,12 @@ static int brush_colors_flip_poll(bContext *C) if (br->imagepaint_tool == PAINT_TOOL_DRAW) return 1; } - + else { + Object *ob = CTX_data_active_object(C); + if (ob && (ob->mode & OB_MODE_VERTEX_PAINT)) { + return 1; + } + } return 0; } diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 4f93c12385d..09b0847b306 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -797,6 +797,7 @@ static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus float map_alpha = (rgb[3] == 0.0f) ? rrgbf[3] : rrgbf[3] / rgb[3]; mul_v3_v3fl(rrgbf, rgb, map_alpha); + rrgbf[3] = rgb[3]; } else { unsigned char straight[4]; @@ -806,6 +807,7 @@ static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus rrgb[0] = straight[0]; rrgb[1] = straight[1]; rrgb[2] = straight[2]; + rrgb[3] = straight[3]; } } @@ -995,7 +997,7 @@ static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short tile) IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, NULL, 0, region[a].destx, region[a].desty, region[a].destx, region[a].desty, region[a].srcx, region[a].srcy, - region[a].width, region[a].height, IMB_BLEND_COPY_RGB, false); + region[a].width, region[a].height, IMB_BLEND_COPY, false); } static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos) @@ -1096,6 +1098,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign /* lift from canvas */ if (s->tool == PAINT_TOOL_SOFTEN) { paint_2d_lift_soften(s, s->canvas, ibufb, bpos, tile); + blend = IMB_BLEND_INTERPOLATE; } else if (s->tool == PAINT_TOOL_SMEAR) { if (lastpos[0] == pos[0] && lastpos[1] == pos[1]) @@ -1103,6 +1106,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign paint_2d_convert_brushco(ibufb, lastpos, blastpos); paint_2d_lift_smear(s->canvas, ibufb, blastpos, tile); + blend = IMB_BLEND_INTERPOLATE; } else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) { liftpos[0] = pos[0] - offset[0] * s->canvas->x; diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index b43581170d0..8586eb42bec 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -4295,7 +4295,7 @@ static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, f return; } else { - blend_color_interpolate_float(rgba, rgba, projPixel->pixel.f_pt, mask); + blend_color_interpolate_float(rgba, projPixel->pixel.f_pt, rgba, mask); } BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena); @@ -4754,6 +4754,9 @@ static void *do_projectpaint_thread(void *ph_v) copy_v3_v3(texrgb, texrgba); mask *= texrgba[3]; } + else { + zero_v3(texrgb); + } /* extra mask for normal, layer stencil, .. */ mask *= ((float)projPixel->mask) * (1.0f / 65535.0f); diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 7e05ab929ae..bd35218bb64 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -96,21 +96,11 @@ int weight_paint_mode_poll(struct bContext *C); int vertex_paint_poll(struct bContext *C); int vertex_paint_mode_poll(struct bContext *C); -bool ED_vpaint_fill(struct Object *ob, unsigned int paintcol); -bool ED_wpaint_fill(struct VPaint *wp, struct Object *ob, float paintweight); - -bool ED_vpaint_smooth(struct Object *ob); - typedef void (*VPaintTransform_Callback)(const float col[3], const void *user_data, float r_col[3]); -bool ED_vpaint_color_transform(struct Object *ob, VPaintTransform_Callback vpaint_tx_fn, const void *user_data); - void PAINT_OT_weight_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_weight_paint(struct wmOperatorType *ot); void PAINT_OT_weight_set(struct wmOperatorType *ot); -void PAINT_OT_weight_from_bones(struct wmOperatorType *ot); -void PAINT_OT_weight_sample(struct wmOperatorType *ot); -void PAINT_OT_weight_sample_group(struct wmOperatorType *ot); enum { WPAINT_GRADIENT_TYPE_LINEAR, @@ -123,6 +113,44 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot); unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp); +/* paint_vertex_color_utils.c */ +unsigned int ED_vpaint_blend_tool( + const int tool, const uint col, + const uint paintcol, const int alpha_i); +bool ED_vpaint_color_transform( + struct Object *ob, VPaintTransform_Callback vpaint_tx_fn, const void *user_data); + +/* paint_vertex_weight_utils.c */ +float ED_wpaint_blend_tool( + const int tool, + const float weight, + const float paintval, const float alpha); +/* Utility for tools to ensure vertex groups exist before they begin. */ +enum eWPaintFlag { + WPAINT_ENSURE_MIRROR = (1 << 0), +}; +struct WPaintVGroupIndex { + int active; + int mirror; +}; +bool ED_wpaint_ensure_data( + struct bContext *C, struct ReportList *reports, + enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index); +int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, const int vgroup_active); + +/* paint_vertex_color_ops.c */ +void PAINT_OT_vertex_color_set(struct wmOperatorType *ot); +void PAINT_OT_vertex_color_from_weight(struct wmOperatorType *ot); +void PAINT_OT_vertex_color_smooth(struct wmOperatorType *ot); +void PAINT_OT_vertex_color_brightness_contrast(struct wmOperatorType *ot); +void PAINT_OT_vertex_color_hsv(struct wmOperatorType *ot); +void PAINT_OT_vertex_color_invert(struct wmOperatorType *ot); +void PAINT_OT_vertex_color_levels(struct wmOperatorType *ot); + +/* paint_vertex_weight_ops.c */ +void PAINT_OT_weight_from_bones(struct wmOperatorType *ot); +void PAINT_OT_weight_sample(struct wmOperatorType *ot); +void PAINT_OT_weight_sample_group(struct wmOperatorType *ot); /* paint_vertex_proj.c */ struct VertProjHandle; @@ -160,7 +188,7 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr); void imapaint_region_tiles(struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th); int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy); void *paint_2d_new_stroke(struct bContext *, struct wmOperator *, int mode); -void paint_2d_redraw(const bContext *C, void *ps, bool final); +void paint_2d_redraw(const struct bContext *C, void *ps, bool final); void paint_2d_stroke_done(void *ps); void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float size); void paint_2d_bucket_fill(const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps); @@ -217,7 +245,7 @@ float paint_calc_object_space_radius(struct ViewContext *vc, const float center[ float paint_get_tex_pixel(struct MTex *mtex, float u, float v, struct ImagePool *pool, int thread); void paint_get_tex_pixel_col(struct MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool, int thread, bool convert, struct ColorSpace *colorspace); -void paint_sample_color(bContext *C, struct ARegion *ar, int x, int y, bool texpaint_proj, bool palette); +void paint_sample_color(struct bContext *C, struct ARegion *ar, int x, int y, bool texpaint_proj, bool palette); void paint_stroke_operator_properties(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index f88b64129e7..4f6b3d100c5 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -256,300 +256,6 @@ static void PALETTE_OT_color_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - - -static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Scene *scene = CTX_data_scene(C); - Object *obact = CTX_data_active_object(C); - unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint); - - if (ED_vpaint_fill(obact, paintcol)) { - ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static void PAINT_OT_vertex_color_set(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Set Vertex Colors"; - ot->idname = "PAINT_OT_vertex_color_set"; - ot->description = "Fill the active vertex color layer with the current paint color"; - - /* api callbacks */ - ot->exec = vertex_color_set_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obact = CTX_data_active_object(C); - if (ED_vpaint_smooth(obact)) { - ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static void PAINT_OT_vertex_color_smooth(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Smooth Vertex Colors"; - ot->idname = "PAINT_OT_vertex_color_smooth"; - ot->description = "Smooth colors across vertices"; - - /* api callbacks */ - ot->exec = vertex_color_smooth_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - - -/** \name Vertex Color Transformations - * \{ */ - -struct VPaintTx_BrightContrastData { - /* pre-calculated */ - float gain; - float offset; -}; - -static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3]) -{ - const struct VPaintTx_BrightContrastData *data = user_data; - - for (int i = 0; i < 3; i++) { - r_col[i] = data->gain * col[i] + data->offset; - } -} - -static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op) -{ - Object *obact = CTX_data_active_object(C); - - float gain, offset; - { - float brightness = RNA_float_get(op->ptr, "brightness"); - float contrast = RNA_float_get(op->ptr, "contrast"); - brightness /= 100.0f; - float delta = contrast / 200.0f; - gain = 1.0f - delta * 2.0f; - /* - * The algorithm is by Werner D. Streidt - * (http://visca.com/ffactory/archives/5-99/msg00021.html) - * Extracted of OpenCV demhist.c - */ - if (contrast > 0) { - gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON); - offset = gain * (brightness - delta); - } - else { - delta *= -1; - offset = gain * (brightness + delta); - } - } - - const struct VPaintTx_BrightContrastData user_data = { - .gain = gain, - .offset = offset, - }; - - if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) { - ED_region_tag_redraw(CTX_wm_region(C)); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Vertex Paint Bright/Contrast"; - ot->idname = "PAINT_OT_vertex_color_brightness_contrast"; - ot->description = "Adjust vertex color brightness/contrast"; - - /* api callbacks */ - ot->exec = vertex_color_brightness_contrast_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* params */ - const float min = -100, max = +100; - prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max); - prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max); - RNA_def_property_ui_range(prop, min, max, 1, 1); -} - -struct VPaintTx_HueSatData { - float hue; - float sat; - float val; -}; - -static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3]) -{ - const struct VPaintTx_HueSatData *data = user_data; - float hsv[3]; - rgb_to_hsv_v(col, hsv); - - hsv[0] += (data->hue - 0.5f); - if (hsv[0] > 1.0f) { - hsv[0] -= 1.0f; - } - else if (hsv[0] < 0.0f) { - hsv[0] += 1.0f; - } - hsv[1] *= data->sat; - hsv[2] *= data->val; - - hsv_to_rgb_v(hsv, r_col); -} - -static int vertex_color_hsv_exec(bContext *C, wmOperator *op) -{ - Object *obact = CTX_data_active_object(C); - - const struct VPaintTx_HueSatData user_data = { - .hue = RNA_float_get(op->ptr, "h"), - .sat = RNA_float_get(op->ptr, "s"), - .val = RNA_float_get(op->ptr, "v"), - }; - - if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) { - ED_region_tag_redraw(CTX_wm_region(C)); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static void PAINT_OT_vertex_color_hsv(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Paint Hue Saturation Value"; - ot->idname = "PAINT_OT_vertex_color_hsv"; - ot->description = "Adjust vertex color HSV values"; - - /* api callbacks */ - ot->exec = vertex_color_hsv_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* params */ - RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f); - RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f); - RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f); -} - -static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3]) -{ - for (int i = 0; i < 3; i++) { - r_col[i] = 1.0f - col[i]; - } -} - -static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obact = CTX_data_active_object(C); - - if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) { - ED_region_tag_redraw(CTX_wm_region(C)); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static void PAINT_OT_vertex_color_invert(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Paint Invert"; - ot->idname = "PAINT_OT_vertex_color_invert"; - ot->description = "Invert RGB values"; - - /* api callbacks */ - ot->exec = vertex_color_invert_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - - -struct VPaintTx_LevelsData { - float gain; - float offset; -}; - -static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3]) -{ - const struct VPaintTx_LevelsData *data = user_data; - for (int i = 0; i < 3; i++) { - r_col[i] = data->gain * (col[i] + data->offset); - } -} - -static int vertex_color_levels_exec(bContext *C, wmOperator *op) -{ - Object *obact = CTX_data_active_object(C); - - const struct VPaintTx_LevelsData user_data = { - .gain = RNA_float_get(op->ptr, "gain"), - .offset = RNA_float_get(op->ptr, "offset"), - }; - - if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) { - ED_region_tag_redraw(CTX_wm_region(C)); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static void PAINT_OT_vertex_color_levels(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Paint Levels"; - ot->idname = "PAINT_OT_vertex_color_levels"; - ot->description = "Adjust levels of vertex colors"; - - /* api callbacks */ - ot->exec = vertex_color_levels_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* params */ - RNA_def_float(ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f); - RNA_def_float(ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f); -} - -/** \} */ - - static int brush_reset_exec(bContext *C, wmOperator *UNUSED(op)) { Paint *paint = BKE_paint_get_active_from_context(C); @@ -821,8 +527,6 @@ static int brush_uv_sculpt_tool_set_exec(bContext *C, wmOperator *op) static void BRUSH_OT_uv_sculpt_tool_set(wmOperatorType *ot) { - /* from rna_scene.c */ - extern EnumPropertyItem uv_sculpt_tool_items[]; /* identifiers */ ot->name = "UV Sculpt Tool Set"; ot->description = "Set the UV sculpt tool"; @@ -836,7 +540,7 @@ static void BRUSH_OT_uv_sculpt_tool_set(wmOperatorType *ot) ot->flag = 0; /* props */ - ot->prop = RNA_def_enum(ot->srna, "tool", uv_sculpt_tool_items, 0, "Tool", ""); + ot->prop = RNA_def_enum(ot->srna, "tool", rna_enum_uv_sculpt_tool_items, 0, "Tool", ""); } /***** Stencil Control *****/ @@ -1351,6 +1055,7 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_vertex_color_hsv); WM_operatortype_append(PAINT_OT_vertex_color_invert); WM_operatortype_append(PAINT_OT_vertex_color_levels); + WM_operatortype_append(PAINT_OT_vertex_color_from_weight); /* face-select */ WM_operatortype_append(PAINT_OT_face_select_linked); @@ -1615,6 +1320,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) keymap->poll = vertex_paint_mode_poll; WM_keymap_verify_item(keymap, "PAINT_OT_vertex_paint", LEFTMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PAINT_OT_brush_colors_flip", XKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "PAINT_OT_sample_color", SKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 05270dbfa09..bb2cd52a41e 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -580,7 +580,10 @@ static float paint_stroke_integrate_overlap(Brush *br, float factor) max = overlap; } - return 1.0f / max; + if (max == 0.0f) + return 1.0f; + else + return 1.0f / max; } static float paint_space_stroke_spacing_variable(const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length) diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 31c471c3517..10628d8cccb 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -426,7 +426,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr Scene *scene = CTX_data_scene(C); Paint *paint = BKE_paint_get_active_from_context(C); Palette *palette = BKE_paint_palette(paint); - PaletteColor *color; + PaletteColor *color = NULL; Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C)); unsigned int col; const unsigned char *cp; diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 729dd9dc57b..4d6222a4301 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -27,20 +27,20 @@ /** \file blender/editors/sculpt_paint/paint_vertex.c * \ingroup edsculpt + * + * Used for vertex color & weight paint and mode switching. + * + * \note This file is already big, + * use `paint_vertex_color_ops.c` & `paint_vertex_weight_ops.c` for general purpose operators. */ #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" +#include "BLI_listbase.h" +#include "BLI_rect.h" #include "BLI_math.h" #include "BLI_array_utils.h" -#include "BLI_bitmap.h" -#include "BLI_stack.h" -#include "BLI_string_utils.h" - -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" -#include "IMB_colormanagement.h" +#include "BLI_task.h" #include "DNA_armature_types.h" #include "DNA_mesh_types.h" @@ -51,39 +51,50 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" -#include "BKE_DerivedMesh.h" -#include "BKE_action.h" #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_deform.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" -#include "BKE_modifier.h" #include "BKE_object_deform.h" #include "BKE_paint.h" #include "BKE_report.h" -#include "BKE_colortools.h" +#include "BKE_subsurf.h" #include "WM_api.h" #include "WM_types.h" -#include "ED_armature.h" #include "ED_object.h" #include "ED_mesh.h" #include "ED_screen.h" #include "ED_view3d.h" +#include "bmesh.h" +#include "BKE_ccg.h" + +#include "sculpt_intern.h" #include "paint_intern.h" /* own include */ -/* small structure to defer applying weight-paint results */ -struct WPaintDefer { - int index; - float alpha, weight; +/* Use for 'blur' brush, align with PBVH nodes, created and freed on each update. */ +struct VPaintAverageAccum { + uint len; + uint value[3]; +}; + +struct WPaintAverageAccum { + uint len; + double value; }; +static void defweight_prev_init(const MDeformWeight *dw, float *weight_prev) +{ + if (UNLIKELY(*weight_prev == -1.0f)) { + *weight_prev = dw ? dw->weight : 0.0f; + } +} + /* check if we can do partial updates and have them draw realtime * (without rebuilding the 'derivedFinal') */ static bool vertex_paint_use_fast_update_check(Object *ob) @@ -174,629 +185,38 @@ static VPaint *new_vpaint(int wpaint) return vp; } -static int *get_indexarray(Mesh *me) -{ - return MEM_mallocN(sizeof(int) * (me->totpoly + 1), "vertexpaint"); -} - -unsigned int vpaint_get_current_col(Scene *scene, VPaint *vp) +uint vpaint_get_current_col(Scene *scene, VPaint *vp) { Brush *brush = BKE_paint_brush(&vp->paint); - unsigned char col[4]; + uchar col[4]; rgb_float_to_uchar(col, BKE_brush_color_get(scene, brush)); col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */ - return *(unsigned int *)col; -} - -static void do_shared_vertexcol(Mesh *me, bool *mlooptag) -{ - const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - MPoly *mp; - int (*scol)[4]; - int i, j; - bool has_shared = false; - - /* if no mloopcol: do not do */ - /* if mtexpoly: only the involved faces, otherwise all */ - - if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) return; - - scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol"); - - for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) { - if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) { - MLoop *ml = me->mloop + mp->loopstart; - MLoopCol *lcol = me->mloopcol + mp->loopstart; - for (j = 0; j < mp->totloop; j++, ml++, lcol++) { - scol[ml->v][0] += lcol->r; - scol[ml->v][1] += lcol->g; - scol[ml->v][2] += lcol->b; - scol[ml->v][3] += 1; - has_shared = 1; - } - } - } - - if (has_shared) { - for (i = 0; i < me->totvert; i++) { - if (scol[i][3] != 0) { - scol[i][0] = divide_round_i(scol[i][0], scol[i][3]); - scol[i][1] = divide_round_i(scol[i][1], scol[i][3]); - scol[i][2] = divide_round_i(scol[i][2], scol[i][3]); - } - } - - for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) { - if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) { - MLoop *ml = me->mloop + mp->loopstart; - MLoopCol *lcol = me->mloopcol + mp->loopstart; - for (j = 0; j < mp->totloop; j++, ml++, lcol++) { - if (mlooptag[mp->loopstart + j]) { - lcol->r = scol[ml->v][0]; - lcol->g = scol[ml->v][1]; - lcol->b = scol[ml->v][2]; - } - } - } - } - } - - MEM_freeN(scol); -} - -static bool make_vertexcol(Object *ob) /* single ob */ -{ - Mesh *me; - - if (ID_IS_LINKED_DATABLOCK(ob) || - ((me = BKE_mesh_from_object(ob)) == NULL) || - (me->totpoly == 0) || - (me->edit_btmesh)) - { - return false; - } - - /* copies from shadedisplist to mcol */ - if (!me->mloopcol && me->totloop) { - CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop); - BKE_mesh_update_customdata_pointers(me, true); - } - - DAG_id_tag_update(&me->id, 0); - - return (me->mloopcol != NULL); -} - -/* mirror_vgroup is set to -1 when invalid */ -static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) -{ - bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active); - - if (defgroup) { - int mirrdef; - char name_flip[MAXBONENAME]; - - BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip)); - mirrdef = defgroup_name_index(ob, name_flip); - if (mirrdef == -1) { - if (BKE_defgroup_new(ob, name_flip)) { - mirrdef = BLI_listbase_count(&ob->defbase) - 1; - } - } - - /* curdef should never be NULL unless this is - * a lamp and BKE_object_defgroup_add_name fails */ - return mirrdef; - } - - return -1; -} - -static void free_vpaint_prev(VPaint *vp) -{ - if (vp->vpaint_prev) { - MEM_freeN(vp->vpaint_prev); - vp->vpaint_prev = NULL; - vp->tot = 0; - } -} - -static void free_wpaint_prev(VPaint *vp) -{ - if (vp->wpaint_prev) { - BKE_defvert_array_free(vp->wpaint_prev, vp->tot); - vp->wpaint_prev = NULL; - vp->tot = 0; - } -} - -static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot) -{ - free_vpaint_prev(vp); - - vp->tot = tot; - - if (lcol == NULL || tot == 0) return; - - vp->vpaint_prev = MEM_mallocN(sizeof(int) * tot, "vpaint_prev"); - memcpy(vp->vpaint_prev, lcol, sizeof(int) * tot); - -} - -static void copy_wpaint_prev(VPaint *wp, MDeformVert *dverts, int dcount) -{ - free_wpaint_prev(wp); - - if (dverts && dcount) { - - wp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev"); - wp->tot = dcount; - BKE_defvert_array_copy(wp->wpaint_prev, dverts, dcount); - } -} - -bool ED_vpaint_fill(Object *ob, unsigned int paintcol) -{ - Mesh *me; - MPoly *mp; - int i, j; - bool selected; - - if (((me = BKE_mesh_from_object(ob)) == NULL) || - (me->mloopcol == NULL && (make_vertexcol(ob) == false))) - { - return false; - } - - selected = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - - mp = me->mpoly; - for (i = 0; i < me->totpoly; i++, mp++) { - MLoopCol *lcol = me->mloopcol + mp->loopstart; - - if (selected && !(mp->flag & ME_FACE_SEL)) - continue; - - for (j = 0; j < mp->totloop; j++, lcol++) { - *(int *)lcol = paintcol; - } - } - - /* remove stale me->mcol, will be added later */ - BKE_mesh_tessface_clear(me); - - DAG_id_tag_update(&me->id, 0); - - return true; -} - - -/* fills in the selected faces with the current weight and vertex group */ -bool ED_wpaint_fill(VPaint *wp, Object *ob, float paintweight) -{ - Mesh *me = ob->data; - MPoly *mp; - MDeformWeight *dw, *dw_prev; - int vgroup_active, vgroup_mirror = -1; - unsigned int index; - const bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - - /* mutually exclusive, could be made into a */ - const short paint_selmode = ME_EDIT_PAINT_SEL_MODE(me); - - if (me->totpoly == 0 || me->dvert == NULL || !me->mpoly) { - return false; - } - - vgroup_active = ob->actdef - 1; - - /* if mirror painting, find the other group */ - if (me->editflag & ME_EDIT_MIRROR_X) { - vgroup_mirror = wpaint_mirror_vgroup_ensure(ob, vgroup_active); - } - - copy_wpaint_prev(wp, me->dvert, me->totvert); - - for (index = 0, mp = me->mpoly; index < me->totpoly; index++, mp++) { - unsigned int fidx = mp->totloop - 1; - - if ((paint_selmode == SCE_SELECT_FACE) && !(mp->flag & ME_FACE_SEL)) { - continue; - } - - do { - unsigned int vidx = me->mloop[mp->loopstart + fidx].v; - - if (!me->dvert[vidx].flag) { - if ((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) { - continue; - } - - dw = defvert_verify_index(&me->dvert[vidx], vgroup_active); - if (dw) { - dw_prev = defvert_verify_index(wp->wpaint_prev + vidx, vgroup_active); - dw_prev->weight = dw->weight; /* set the undo weight */ - dw->weight = paintweight; - - if (me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */ - int j = mesh_get_x_mirror_vert(ob, NULL, vidx, topology); - if (j >= 0) { - /* copy, not paint again */ - if (vgroup_mirror != -1) { - dw = defvert_verify_index(me->dvert + j, vgroup_mirror); - dw_prev = defvert_verify_index(wp->wpaint_prev + j, vgroup_mirror); - } - else { - dw = defvert_verify_index(me->dvert + j, vgroup_active); - dw_prev = defvert_verify_index(wp->wpaint_prev + j, vgroup_active); - } - dw_prev->weight = dw->weight; /* set the undo weight */ - dw->weight = paintweight; - } - } - } - me->dvert[vidx].flag = 1; - } - - } while (fidx--); - } - - { - MDeformVert *dv = me->dvert; - for (index = me->totvert; index != 0; index--, dv++) { - dv->flag = 0; - } - } - - copy_wpaint_prev(wp, NULL, 0); - - DAG_id_tag_update(&me->id, 0); - - return true; -} - -bool ED_vpaint_smooth(Object *ob) -{ - Mesh *me; - MPoly *mp; - - int i, j; - - bool *mlooptag; - bool selected; - - if (((me = BKE_mesh_from_object(ob)) == NULL) || - (me->mloopcol == NULL && (make_vertexcol(ob) == false))) - { - return false; - } - - selected = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - - mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag"); - - /* simply tag loops of selected faces */ - mp = me->mpoly; - for (i = 0; i < me->totpoly; i++, mp++) { - MLoop *ml = me->mloop + mp->loopstart; - int ml_index = mp->loopstart; - - if (selected && !(mp->flag & ME_FACE_SEL)) - continue; - - for (j = 0; j < mp->totloop; j++, ml_index++, ml++) { - mlooptag[ml_index] = true; - } - } - - /* remove stale me->mcol, will be added later */ - BKE_mesh_tessface_clear(me); - - do_shared_vertexcol(me, mlooptag); - - MEM_freeN(mlooptag); - - DAG_id_tag_update(&me->id, 0); - - return true; -} - -/** - * Apply callback to each vertex of the active vertex color layer. - */ -bool ED_vpaint_color_transform( - struct Object *ob, - VPaintTransform_Callback vpaint_tx_fn, - const void *user_data) -{ - Mesh *me; - const MPoly *mp; - - if (((me = BKE_mesh_from_object(ob)) == NULL) || - (me->mloopcol == NULL && (make_vertexcol(ob) == false))) - { - return false; - } - - const bool do_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - mp = me->mpoly; - - for (int i = 0; i < me->totpoly; i++, mp++) { - MLoopCol *lcol = &me->mloopcol[mp->loopstart]; - - if (do_face_sel && !(mp->flag & ME_FACE_SEL)) { - continue; - } - - for (int j = 0; j < mp->totloop; j++, lcol++) { - float col[3]; - rgb_uchar_to_float(col, &lcol->r); - - vpaint_tx_fn(col, user_data, col); - - rgb_float_to_uchar(&lcol->r, col); - } - } - - /* remove stale me->mcol, will be added later */ - BKE_mesh_tessface_clear(me); - - DAG_id_tag_update(&me->id, 0); - - return true; -} - -/* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator */ -#if 0 -void vpaint_dogamma(Scene *scene) -{ - VPaint *vp = scene->toolsettings->vpaint; - Mesh *me; - Object *ob; - float igam, fac; - int a, temp; - unsigned char *cp, gamtab[256]; - - ob = OBACT; - me = BKE_mesh_from_object(ob); - - if (!(ob->mode & OB_MODE_VERTEX_PAINT)) return; - if (me == 0 || me->mcol == 0 || me->totface == 0) return; - - igam = 1.0 / vp->gamma; - for (a = 0; a < 256; a++) { - - fac = ((float)a) / 255.0; - fac = vp->mul * pow(fac, igam); - - temp = 255.9 * fac; - - if (temp <= 0) gamtab[a] = 0; - else if (temp >= 255) gamtab[a] = 255; - else gamtab[a] = temp; - } - - a = 4 * me->totface; - cp = (unsigned char *)me->mcol; - while (a--) { - - cp[1] = gamtab[cp[1]]; - cp[2] = gamtab[cp[2]]; - cp[3] = gamtab[cp[3]]; - - cp += 4; - } -} -#endif - -BLI_INLINE unsigned int mcol_blend(unsigned int col1, unsigned int col2, int fac) -{ - unsigned char *cp1, *cp2, *cp; - int mfac; - unsigned int col = 0; - - if (fac == 0) { - return col1; - } - - if (fac >= 255) { - return col2; - } - - mfac = 255 - fac; - - cp1 = (unsigned char *)&col1; - cp2 = (unsigned char *)&col2; - cp = (unsigned char *)&col; - - cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255); - cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255); - cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255); - cp[3] = 255; - - return col; -} - -BLI_INLINE unsigned int mcol_add(unsigned int col1, unsigned int col2, int fac) -{ - unsigned char *cp1, *cp2, *cp; - int temp; - unsigned int col = 0; - - if (fac == 0) { - return col1; - } - - cp1 = (unsigned char *)&col1; - cp2 = (unsigned char *)&col2; - cp = (unsigned char *)&col; - - temp = cp1[0] + divide_round_i((fac * cp2[0]), 255); - cp[0] = (temp > 254) ? 255 : temp; - temp = cp1[1] + divide_round_i((fac * cp2[1]), 255); - cp[1] = (temp > 254) ? 255 : temp; - temp = cp1[2] + divide_round_i((fac * cp2[2]), 255); - cp[2] = (temp > 254) ? 255 : temp; - cp[3] = 255; - - return col; -} - -BLI_INLINE unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac) -{ - unsigned char *cp1, *cp2, *cp; - int temp; - unsigned int col = 0; - - if (fac == 0) { - return col1; - } - - cp1 = (unsigned char *)&col1; - cp2 = (unsigned char *)&col2; - cp = (unsigned char *)&col; - - temp = cp1[0] - divide_round_i((fac * cp2[0]), 255); - cp[0] = (temp < 0) ? 0 : temp; - temp = cp1[1] - divide_round_i((fac * cp2[1]), 255); - cp[1] = (temp < 0) ? 0 : temp; - temp = cp1[2] - divide_round_i((fac * cp2[2]), 255); - cp[2] = (temp < 0) ? 0 : temp; - cp[3] = 255; - - return col; -} - -BLI_INLINE unsigned int mcol_mul(unsigned int col1, unsigned int col2, int fac) -{ - unsigned char *cp1, *cp2, *cp; - int mfac; - unsigned int col = 0; - - if (fac == 0) { - return col1; - } - - mfac = 255 - fac; - - cp1 = (unsigned char *)&col1; - cp2 = (unsigned char *)&col2; - cp = (unsigned char *)&col; - - /* first mul, then blend the fac */ - cp[0] = divide_round_i(mfac * cp1[0] * 255 + fac * cp2[0] * cp1[0], 255 * 255); - cp[1] = divide_round_i(mfac * cp1[1] * 255 + fac * cp2[1] * cp1[1], 255 * 255); - cp[2] = divide_round_i(mfac * cp1[2] * 255 + fac * cp2[2] * cp1[2], 255 * 255); - cp[3] = 255; - - return col; -} - -BLI_INLINE unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int fac) -{ - unsigned char *cp1, *cp2, *cp; - int mfac; - unsigned int col = 0; - - if (fac == 0) { - return col1; - } - else if (fac >= 255) { - return col2; - } - - mfac = 255 - fac; - - cp1 = (unsigned char *)&col1; - cp2 = (unsigned char *)&col2; - cp = (unsigned char *)&col; - - /* See if are lighter, if so mix, else don't do anything. - * if the paint col is darker then the original, then ignore */ - if (IMB_colormanagement_get_luminance_byte(cp1) > IMB_colormanagement_get_luminance_byte(cp2)) { - return col1; - } - - cp[0] = divide_round_i(mfac * cp1[0] + fac * cp2[0], 255); - cp[1] = divide_round_i(mfac * cp1[1] + fac * cp2[1], 255); - cp[2] = divide_round_i(mfac * cp1[2] + fac * cp2[2], 255); - cp[3] = 255; - - return col; -} - -BLI_INLINE unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac) -{ - unsigned char *cp1, *cp2, *cp; - int mfac; - unsigned int col = 0; - - if (fac == 0) { - return col1; - } - else if (fac >= 255) { - return col2; - } - - mfac = 255 - fac; - - cp1 = (unsigned char *)&col1; - cp2 = (unsigned char *)&col2; - cp = (unsigned char *)&col; - - /* See if were darker, if so mix, else don't do anything. - * if the paint col is brighter then the original, then ignore */ - if (IMB_colormanagement_get_luminance_byte(cp1) < IMB_colormanagement_get_luminance_byte(cp2)) { - return col1; - } - - cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255); - cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255); - cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255); - cp[3] = 255; - return col; -} - -/* wpaint has 'wpaint_blend_tool' */ -static unsigned int vpaint_blend_tool(const int tool, const unsigned int col, - const unsigned int paintcol, const int alpha_i) -{ - switch (tool) { - case PAINT_BLEND_MIX: - case PAINT_BLEND_BLUR: return mcol_blend(col, paintcol, alpha_i); - case PAINT_BLEND_ADD: return mcol_add(col, paintcol, alpha_i); - case PAINT_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i); - case PAINT_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i); - case PAINT_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i); - case PAINT_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i); - default: - BLI_assert(0); - return 0; - } + return *(uint *)col; } /* wpaint has 'wpaint_blend' */ -static unsigned int vpaint_blend(VPaint *vp, unsigned int col, unsigned int colorig, const - unsigned int paintcol, const int alpha_i, - /* pre scaled from [0-1] --> [0-255] */ - const int brush_alpha_value_i) +static uint vpaint_blend( + VPaint *vp, uint color_curr, uint color_orig, + uint color_paint, const int alpha_i, + /* pre scaled from [0-1] --> [0-255] */ + const int brush_alpha_value_i) { Brush *brush = BKE_paint_brush(&vp->paint); const int tool = brush->vertexpaint_tool; - col = vpaint_blend_tool(tool, col, paintcol, alpha_i); + uint color_blend = ED_vpaint_blend_tool(tool, color_curr, color_paint, alpha_i); /* if no spray, clip color adding with colorig & orig alpha */ if ((vp->flag & VP_SPRAY) == 0) { - unsigned int testcol, a; + uint color_test, a; char *cp, *ct, *co; - - testcol = vpaint_blend_tool(tool, colorig, paintcol, brush_alpha_value_i); - - cp = (char *)&col; - ct = (char *)&testcol; - co = (char *)&colorig; - + + color_test = ED_vpaint_blend_tool(tool, color_orig, color_paint, brush_alpha_value_i); + + cp = (char *)&color_blend; + ct = (char *)&color_test; + co = (char *)&color_orig; + for (a = 0; a < 4; a++) { if (ct[a] < co[a]) { if (cp[a] < ct[a]) cp[a] = ct[a]; @@ -809,53 +229,23 @@ static unsigned int vpaint_blend(VPaint *vp, unsigned int col, unsigned int colo } } - return col; -} - - -static int sample_backbuf_area(ViewContext *vc, int *indexar, int totpoly, int x, int y, float size) -{ - struct ImBuf *ibuf; - int a, tot = 0, index; - - /* brecht: disabled this because it obviously fails for - * brushes with size > 64, why is this here? */ - /*if (size > 64.0) size = 64.0;*/ - - ibuf = ED_view3d_backbuf_read(vc, x - size, y - size, x + size, y + size); - if (ibuf) { - unsigned int *rt = ibuf->rect; - - memset(indexar, 0, sizeof(int) * (totpoly + 1)); - - size = ibuf->x * ibuf->y; - while (size--) { - - if (*rt) { - index = *rt; - if (index > 0 && index <= totpoly) { - indexar[index] = 1; - } - } - - rt++; - } - - for (a = 1; a <= totpoly; a++) { - if (indexar[a]) { - indexar[tot++] = a; - } - } - - IMB_freeImBuf(ibuf); + if ((brush->flag & BRUSH_LOCK_ALPHA) && + !ELEM(tool, PAINT_BLEND_ALPHA_SUB, PAINT_BLEND_ALPHA_ADD)) + { + char *cp, *cc; + cp = (char *)&color_blend; + cc = (char *)&color_curr; + cp[3] = cc[3]; } - - return tot; + + return color_blend; } + /* whats _dl mean? */ -static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co[3], - const float mval[2], const float brush_size_pressure, float rgba[4]) +static float calc_vp_strength_col_dl( + VPaint *vp, const ViewContext *vc, const float co[3], + const float mval[2], const float brush_size_pressure, float rgba[4]) { float co_ss[2]; /* screenspace */ @@ -891,10 +281,11 @@ static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co return 0.0f; } -static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc, - float vpimat[3][3], const DMCoNo *v_co_no, - const float mval[2], - const float brush_size_pressure, const float brush_alpha_pressure, float rgba[4]) +static float calc_vp_alpha_col_dl( + VPaint *vp, const ViewContext *vc, + float vpimat[3][3], const DMCoNo *v_co_no, + const float mval[2], + const float brush_size_pressure, const float brush_alpha_pressure, float rgba[4]) { float strength = calc_vp_strength_col_dl(vp, vc, v_co_no->co, mval, brush_size_pressure, rgba); @@ -923,59 +314,10 @@ static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc, return 0.0f; } - -BLI_INLINE float wval_blend(const float weight, const float paintval, const float alpha) -{ - const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */ - return (paintval * talpha) + (weight * (1.0f - talpha)); -} -BLI_INLINE float wval_add(const float weight, const float paintval, const float alpha) -{ - return weight + (paintval * alpha); -} -BLI_INLINE float wval_sub(const float weight, const float paintval, const float alpha) -{ - return weight - (paintval * alpha); -} -BLI_INLINE float wval_mul(const float weight, const float paintval, const float alpha) -{ /* first mul, then blend the fac */ - return ((1.0f - alpha) + (alpha * paintval)) * weight; -} -BLI_INLINE float wval_lighten(const float weight, const float paintval, const float alpha) -{ - return (weight < paintval) ? wval_blend(weight, paintval, alpha) : weight; -} -BLI_INLINE float wval_darken(const float weight, const float paintval, const float alpha) -{ - return (weight > paintval) ? wval_blend(weight, paintval, alpha) : weight; -} - - -/* vpaint has 'vpaint_blend_tool' */ -/* result is not clamped from [0-1] */ -static float wpaint_blend_tool(const int tool, - /* dw->weight */ - const float weight, - const float paintval, const float alpha) -{ - switch (tool) { - case PAINT_BLEND_MIX: - case PAINT_BLEND_BLUR: return wval_blend(weight, paintval, alpha); - case PAINT_BLEND_ADD: return wval_add(weight, paintval, alpha); - case PAINT_BLEND_SUB: return wval_sub(weight, paintval, alpha); - case PAINT_BLEND_MUL: return wval_mul(weight, paintval, alpha); - case PAINT_BLEND_LIGHTEN: return wval_lighten(weight, paintval, alpha); - case PAINT_BLEND_DARKEN: return wval_darken(weight, paintval, alpha); - default: - BLI_assert(0); - return 0.0f; - } -} - /* vpaint has 'vpaint_blend' */ -static float wpaint_blend(VPaint *wp, float weight, float weight_prev, +static float wpaint_blend(VPaint *wp, float weight, const float alpha, float paintval, - const float brush_alpha_value, + const float UNUSED(brush_alpha_value), const short do_flip) { Brush *brush = BKE_paint_brush(&wp->paint); @@ -996,256 +338,19 @@ static float wpaint_blend(VPaint *wp, float weight, float weight_prev, } } - weight = wpaint_blend_tool(tool, weight, paintval, alpha); + weight = ED_wpaint_blend_tool(tool, weight, paintval, alpha); CLAMP(weight, 0.0f, 1.0f); - /* if no spray, clip result with orig weight & orig alpha */ - if ((wp->flag & VP_SPRAY) == 0) { - float testw = wpaint_blend_tool(tool, weight_prev, paintval, brush_alpha_value); - - CLAMP(testw, 0.0f, 1.0f); - if (testw < weight_prev) { - if (weight < testw) weight = testw; - else if (weight > weight_prev) weight = weight_prev; - } - else { - if (weight > testw) weight = testw; - else if (weight < weight_prev) weight = weight_prev; - } - } - return weight; } /* ----------------------------------------------------- */ - -/* sets wp->weight to the closest weight value to vertex */ -/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */ -static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ViewContext vc; - Mesh *me; - bool changed = false; - - view3d_set_viewcontext(C, &vc); - me = BKE_mesh_from_object(vc.obact); - - if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) { - const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; - int v_idx_best = -1; - unsigned int index; - - view3d_operator_needs_opengl(C); - ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d); - - if (use_vert_sel) { - if (ED_mesh_pick_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, true)) { - v_idx_best = index; - } - } - else { - if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { - v_idx_best = index; - } - else if (ED_mesh_pick_face(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { - /* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */ - BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations"); - } - } - - if (v_idx_best != -1) { /* should always be valid */ - ToolSettings *ts = vc.scene->toolsettings; - Brush *brush = BKE_paint_brush(&ts->wpaint->paint); - const int vgroup_active = vc.obact->actdef - 1; - float vgroup_weight = defvert_find_weight(&me->dvert[v_idx_best], vgroup_active); - - /* use combined weight in multipaint mode, since that's what is displayed to the user in the colors */ - if (ts->multipaint) { - int defbase_tot_sel; - const int defbase_tot = BLI_listbase_count(&vc.obact->defbase); - bool *defbase_sel = BKE_object_defgroup_selected_get(vc.obact, defbase_tot, &defbase_tot_sel); - - if (defbase_tot_sel > 1) { - if (me->editflag & ME_EDIT_MIRROR_X) { - BKE_object_defgroup_mirror_selection( - vc.obact, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel); - } - - vgroup_weight = BKE_defvert_multipaint_collective_weight( - &me->dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, ts->auto_normalize); - - /* if autonormalize is enabled, but weights are not normalized, the value can exceed 1 */ - CLAMP(vgroup_weight, 0.0f, 1.0f); - } - - MEM_freeN(defbase_sel); - } - - BKE_brush_weight_set(vc.scene, brush, vgroup_weight); - changed = true; - } - } - - if (changed) { - /* not really correct since the brush didnt change, but redraws the toolbar */ - WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); /* ts->wpaint->paint.brush */ - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -void PAINT_OT_weight_sample(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Weight Paint Sample Weight"; - ot->idname = "PAINT_OT_weight_sample"; - ot->description = "Use the mouse to sample a weight in the 3D view"; - - /* api callbacks */ - ot->invoke = weight_sample_invoke; - ot->poll = weight_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_UNDO; -} - -/* samples cursor location, and gives menu with vertex groups to activate */ -static bool weight_paint_sample_enum_itemf__helper(const MDeformVert *dvert, const int defbase_tot, int *groups) -{ - /* this func fills in used vgroup's */ - bool found = false; - int i = dvert->totweight; - MDeformWeight *dw; - for (dw = dvert->dw; i > 0; dw++, i--) { - if (dw->def_nr < defbase_tot) { - groups[dw->def_nr] = true; - found = true; - } - } - return found; -} -static EnumPropertyItem *weight_paint_sample_enum_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - if (C) { - wmWindow *win = CTX_wm_window(C); - if (win && win->eventstate) { - ViewContext vc; - Mesh *me; - - view3d_set_viewcontext(C, &vc); - me = BKE_mesh_from_object(vc.obact); - - if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) { - const int defbase_tot = BLI_listbase_count(&vc.obact->defbase); - const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; - int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups"); - bool found = false; - unsigned int index; - - const int mval[2] = { - win->eventstate->x - vc.ar->winrct.xmin, - win->eventstate->y - vc.ar->winrct.ymin, - }; - - view3d_operator_needs_opengl(C); - ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d); - - if (use_vert_sel) { - if (ED_mesh_pick_vert(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, true)) { - MDeformVert *dvert = &me->dvert[index]; - found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups); - } - } - else { - if (ED_mesh_pick_face(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { - MPoly *mp = &me->mpoly[index]; - unsigned int fidx = mp->totloop - 1; - - do { - MDeformVert *dvert = &me->dvert[me->mloop[mp->loopstart + fidx].v]; - found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups); - } while (fidx--); - } - } - - if (found == false) { - MEM_freeN(groups); - } - else { - EnumPropertyItem *item = NULL, item_tmp = {0}; - int totitem = 0; - int i = 0; - bDeformGroup *dg; - for (dg = vc.obact->defbase.first; dg && i < defbase_tot; i++, dg = dg->next) { - if (groups[i]) { - item_tmp.identifier = item_tmp.name = dg->name; - item_tmp.value = i; - RNA_enum_item_add(&item, &totitem, &item_tmp); - } - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - MEM_freeN(groups); - return item; - } - } - } - } - - return DummyRNA_NULL_items; -} - -static int weight_sample_group_exec(bContext *C, wmOperator *op) -{ - int type = RNA_enum_get(op->ptr, "group"); - ViewContext vc; - view3d_set_viewcontext(C, &vc); - - BLI_assert(type + 1 >= 0); - vc.obact->actdef = type + 1; - - DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, vc.obact); - return OPERATOR_FINISHED; -} - -/* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active rather than its own operator */ -void PAINT_OT_weight_sample_group(wmOperatorType *ot) -{ - PropertyRNA *prop = NULL; - - /* identifiers */ - ot->name = "Weight Paint Sample Group"; - ot->idname = "PAINT_OT_weight_sample_group"; - ot->description = "Select one of the vertex groups available under current mouse position"; - - /* api callbacks */ - ot->exec = weight_sample_group_exec; - ot->invoke = WM_menu_invoke; - ot->poll = weight_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_UNDO; - - /* keyingset to use (dynamic enum) */ - prop = RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); - RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; -} - static void do_weight_paint_normalize_all(MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap) { float sum = 0.0f, fac; - unsigned int i, tot = 0; + uint i, tot = 0; MDeformWeight *dw; for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) { @@ -1291,7 +396,7 @@ static bool do_weight_paint_normalize_all_locked( float sum = 0.0f, fac; float sum_unlock = 0.0f; float lock_weight = 0.0f; - unsigned int i, tot = 0; + uint i, tot = 0; MDeformWeight *dw; if (lock_flags == NULL) { @@ -1476,7 +581,7 @@ static void multipaint_apply_change(MDeformVert *dvert, const int defbase_tot, f * Variables stored both for 'active' and 'mirror' sides. */ struct WeightPaintGroupData { - /** index of active group or its mirror + /** index of active group or its mirror * * - 'active' is always `ob->actdef`. * - 'mirror' is -1 when 'ME_EDIT_MIRROR_X' flag id disabled, @@ -1524,14 +629,14 @@ static void do_weight_paint_vertex_single( /* vars which remain the same for every vert */ VPaint *wp, Object *ob, const WeightPaintInfo *wpi, /* vars which change on each stroke */ - const unsigned int index, float alpha, float paintweight + const uint index, float alpha, float paintweight ) { Mesh *me = ob->data; MDeformVert *dv = &me->dvert[index]; bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - - MDeformWeight *dw, *dw_prev; + + MDeformWeight *dw; /* mirror vars */ int index_mirr; @@ -1542,14 +647,12 @@ static void do_weight_paint_vertex_single( if (wp->flag & VP_ONLYVGROUP) { dw = defvert_find_index(dv, wpi->active.index); - dw_prev = defvert_find_index(wp->wpaint_prev + index, wpi->active.index); } else { dw = defvert_verify_index(dv, wpi->active.index); - dw_prev = defvert_verify_index(wp->wpaint_prev + index, wpi->active.index); } - if (dw == NULL || dw_prev == NULL) { + if (dw == NULL) { return; } @@ -1607,7 +710,7 @@ static void do_weight_paint_vertex_single( * then there is no need to run the more complicated checks */ { - dw->weight = wpaint_blend(wp, dw->weight, dw_prev->weight, alpha, paintweight, + dw->weight = wpaint_blend(wp, dw->weight, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip); /* WATCH IT: take care of the ordering of applying mirror -> normalize, @@ -1669,11 +772,10 @@ static void do_weight_paint_vertex_multi( /* vars which remain the same for every vert */ VPaint *wp, Object *ob, const WeightPaintInfo *wpi, /* vars which change on each stroke */ - const unsigned int index, float alpha, float paintweight) + const uint index, float alpha, float paintweight) { Mesh *me = ob->data; MDeformVert *dv = &me->dvert[index]; - MDeformVert *dv_prev = &wp->wpaint_prev[index]; bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; /* mirror vars */ @@ -1681,7 +783,7 @@ static void do_weight_paint_vertex_multi( MDeformVert *dv_mirr = NULL; /* weights */ - float oldw, curw, neww, change, curw_mirr, change_mirr; + float curw, neww, change, curw_mirr, change_mirr; /* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */ if (me->editflag & ME_EDIT_MIRROR_X) { @@ -1693,8 +795,6 @@ static void do_weight_paint_vertex_multi( } /* compute weight change by applying the brush to average or sum of group weights */ - oldw = BKE_defvert_multipaint_collective_weight( - dv_prev, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize); curw = BKE_defvert_multipaint_collective_weight( dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize); @@ -1703,7 +803,7 @@ static void do_weight_paint_vertex_multi( return; } - neww = wpaint_blend(wp, curw, oldw, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip); + neww = wpaint_blend(wp, curw, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip); change = neww / curw; @@ -1759,7 +859,7 @@ static void do_weight_paint_vertex( /* vars which remain the same for every vert */ VPaint *wp, Object *ob, const WeightPaintInfo *wpi, /* vars which change on each stroke */ - const unsigned int index, float alpha, float paintweight) + const uint index, float alpha, float paintweight) { if (wpi->do_multipaint) { do_weight_paint_vertex_multi(wp, ob, wpi, index, alpha, paintweight); @@ -1769,6 +869,103 @@ static void do_weight_paint_vertex( } } + +/* Toggle operator for turning vertex paint mode on or off (copied from sculpt.c) */ +static void vertex_paint_init_session(Scene *scene, Object *ob) +{ + if (ob->sculpt == NULL) { + ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); + BKE_sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, 0, false); + } +} + +static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob) +{ + /* Create maps */ + struct SculptVertexPaintGeomMap *gmap = NULL; + const Brush *brush = NULL; + if (ob->mode == OB_MODE_VERTEX_PAINT) { + gmap = &ob->sculpt->mode.vpaint.gmap; + brush = BKE_paint_brush(&ts->vpaint->paint); + ob->sculpt->mode_type = OB_MODE_VERTEX_PAINT; + } + else if (ob->mode == OB_MODE_WEIGHT_PAINT) { + gmap = &ob->sculpt->mode.wpaint.gmap; + brush = BKE_paint_brush(&ts->wpaint->paint); + ob->sculpt->mode_type = OB_MODE_WEIGHT_PAINT; + } + else { + ob->sculpt->mode_type = 0; + BLI_assert(0); + return; + } + + Mesh *me = ob->data; + + if (gmap->vert_to_loop == NULL) { + gmap->vert_map_mem = NULL; + gmap->vert_to_loop = NULL; + gmap->poly_map_mem = NULL; + gmap->vert_to_poly = NULL; + BKE_mesh_vert_loop_map_create( + &gmap->vert_to_loop, + &gmap->vert_map_mem, + me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop); + BKE_mesh_vert_poly_map_create( + &gmap->vert_to_poly, + &gmap->poly_map_mem, + me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop); + } + + /* Create average brush arrays */ + if (ob->mode == OB_MODE_VERTEX_PAINT) { + if ((ts->vpaint->flag & VP_SPRAY) == 0) { + if (ob->sculpt->mode.vpaint.previous_color == NULL) { + ob->sculpt->mode.vpaint.previous_color = + MEM_callocN(me->totloop * sizeof(uint), __func__); + } + } + else { + MEM_SAFE_FREE(ob->sculpt->mode.vpaint.previous_color); + } + + if (brush && brush->flag & BRUSH_ACCUMULATE) { + if (ob->sculpt->mode.vpaint.previous_accum == NULL) { + ob->sculpt->mode.vpaint.previous_accum = + MEM_callocN(me->totloop * sizeof(float), __func__); + } + } + else { + MEM_SAFE_FREE(ob->sculpt->mode.vpaint.previous_accum); + } + } + else if (ob->mode == OB_MODE_WEIGHT_PAINT) { + if ((ts->wpaint->flag & VP_SPRAY) == 0) { + if (ob->sculpt->mode.wpaint.alpha_weight == NULL) { + ob->sculpt->mode.wpaint.alpha_weight = + MEM_callocN(me->totvert * sizeof(float), __func__); + } + if (ob->sculpt->mode.wpaint.previous_weight == NULL) { + ob->sculpt->mode.wpaint.previous_weight = + MEM_mallocN(me->totvert * sizeof(float), __func__); + } + } + else { + MEM_SAFE_FREE(ob->sculpt->mode.wpaint.alpha_weight); + } + if (brush && brush->flag & BRUSH_ACCUMULATE) { + if (ob->sculpt->mode.wpaint.previous_accum == NULL) { + ob->sculpt->mode.wpaint.previous_accum = + MEM_callocN(me->totvert * sizeof(float), __func__); + } + } + else { + MEM_SAFE_FREE(ob->sculpt->mode.wpaint.previous_accum); + } + } + +} + /* *************** set wpaint operator ****************** */ /** @@ -1805,6 +1002,14 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e'); ED_mesh_mirror_topo_table(NULL, NULL, 'e'); + /* If the cache is not released by a cancel or a done, free it now. */ + if (ob->sculpt->cache) { + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; + } + + BKE_sculptsession_free(ob); + paint_cursor_delete_textures(); } else { @@ -1820,6 +1025,12 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) /* weight paint specific */ ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's'); ED_vgroup_sync_from_pose(ob); + + /* Create vertex/weight paint mode session data */ + if (ob->sculpt) { + BKE_sculptsession_free(ob); + } + vertex_paint_init_session(scene, ob); } /* Weightpaint works by overriding colors in mesh, @@ -1866,18 +1077,8 @@ void PAINT_OT_weight_paint_toggle(wmOperatorType *ot) /* ************ weight paint operator ********** */ -enum eWPaintFlag { - WPAINT_ENSURE_MIRROR = (1 << 0), -}; - -struct WPaintVGroupIndex { - int active; - int mirror; -}; - struct WPaintData { ViewContext vc; - int *indexar; struct WeightPaintGroupData active, mirror; @@ -1895,110 +1096,136 @@ struct WPaintData { int defbase_tot_sel; /* number of selected groups */ bool do_multipaint; /* true if multipaint enabled and multiple groups selected */ - /* variables for blur */ - struct { - MeshElemMap *vmap; - int *vmap_mem; - } blur_data; - - BLI_Stack *accumulate_stack; /* for reuse (WPaintDefer) */ - int defbase_tot; }; -/* ensure we have data on wpaint start, add if needed */ -static bool wpaint_ensure_data( - bContext *C, wmOperator *op, - enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index) +/* Initialize the stroke cache invariants from operator properties */ +static void vwpaint_update_cache_invariants( + bContext *C, VPaint *vd, SculptSession *ss, wmOperator *op, const float mouse[2]) { + StrokeCache *cache; Scene *scene = CTX_data_scene(C); + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; + Brush *brush = BKE_paint_brush(&vd->paint); + ViewContext *vc = paint_stroke_view_context(op->customdata); Object *ob = CTX_data_active_object(C); - Mesh *me = BKE_mesh_from_object(ob); + float mat[3][3]; + float view_dir[3] = {0.0f, 0.0f, 1.0f}; + int mode; - if (vgroup_index) { - vgroup_index->active = -1; - vgroup_index->mirror = -1; + /* VW paint needs to allocate stroke cache before update is called. */ + if (!ss->cache) { + cache = MEM_callocN(sizeof(StrokeCache), "stroke cache"); + ss->cache = cache; } - - if (scene->obedit) { - return false; + else { + cache = ss->cache; } - if (me == NULL || me->totpoly == 0) { - return false; - } + /* Initial mouse location */ + if (mouse) + copy_v2_v2(cache->initial_mouse, mouse); + else + zero_v2(cache->initial_mouse); - /* if nothing was added yet, we make dverts and a vertex deform group */ - if (!me->dvert) { - BKE_object_defgroup_data_create(&me->id); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); - } + mode = RNA_enum_get(op->ptr, "mode"); + cache->invert = mode == BRUSH_STROKE_INVERT; + cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH; + /* not very nice, but with current events system implementation + * we can't handle brush appearance inversion hotkey separately (sergey) */ + if (cache->invert) ups->draw_inverted = true; + else ups->draw_inverted = false; - /* this happens on a Bone select, when no vgroup existed yet */ - if (ob->actdef <= 0) { - Object *modob; - if ((modob = modifiers_isDeformedByArmature(ob))) { - Bone *actbone = ((bArmature *)modob->data)->act_bone; - if (actbone) { - bPoseChannel *pchan = BKE_pose_channel_find_name(modob->pose, actbone->name); + copy_v2_v2(cache->mouse, cache->initial_mouse); + /* Truly temporary data that isn't stored in properties */ + cache->vc = vc; + cache->brush = brush; + cache->first_time = 1; - if (pchan) { - bDeformGroup *dg = defgroup_find_name(ob, pchan->name); - if (dg == NULL) { - dg = BKE_object_defgroup_add_name(ob, pchan->name); /* sets actdef */ - } - else { - int actdef = 1 + BLI_findindex(&ob->defbase, dg); - BLI_assert(actdef >= 0); - ob->actdef = actdef; - } - } - } - } - } - if (BLI_listbase_is_empty(&ob->defbase)) { - BKE_object_defgroup_add(ob); - } + /* cache projection matrix */ + ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat); - /* ensure we don't try paint onto an invalid group */ - if (ob->actdef <= 0) { - BKE_report(op->reports, RPT_WARNING, "No active vertex group for painting, aborting"); - return false; + invert_m4_m4(ob->imat, ob->obmat); + copy_m3_m4(mat, cache->vc->rv3d->viewinv); + mul_m3_v3(mat, view_dir); + copy_m3_m4(mat, ob->imat); + mul_m3_v3(mat, view_dir); + normalize_v3_v3(cache->true_view_normal, view_dir); + + copy_v3_v3(cache->view_normal, cache->true_view_normal); + cache->bstrength = BKE_brush_alpha_get(scene, brush); + cache->is_last_valid = false; +} + +/* Initialize the stroke cache variants from operator properties */ +static void vwpaint_update_cache_variants(bContext *C, VPaint *vd, Object *ob, PointerRNA *ptr) +{ + Scene *scene = CTX_data_scene(C); + SculptSession *ss = ob->sculpt; + StrokeCache *cache = ss->cache; + Brush *brush = BKE_paint_brush(&vd->paint); + + /* This effects the actual brush radius, so things farther away + * are compared with a larger radius and vise versa. */ + if (cache->first_time) { + RNA_float_get_array(ptr, "location", cache->true_location); } - if (vgroup_index) { - vgroup_index->active = ob->actdef - 1; + RNA_float_get_array(ptr, "mouse", cache->mouse); + + /* XXX: Use pressure value from first brush step for brushes which don't + * support strokes (grab, thumb). They depends on initial state and + * brush coord/pressure/etc. + * It's more an events design issue, which doesn't split coordinate/pressure/angle + * changing events. We should avoid this after events system re-design */ + if (paint_supports_dynamic_size(brush, ePaintSculpt) || cache->first_time) { + cache->pressure = RNA_float_get(ptr, "pressure"); } - if (flag & WPAINT_ENSURE_MIRROR) { - if (me->editflag & ME_EDIT_MIRROR_X) { - int mirror = wpaint_mirror_vgroup_ensure(ob, ob->actdef - 1); - if (vgroup_index) { - vgroup_index->mirror = mirror; - } + /* Truly temporary data that isn't stored in properties */ + if (cache->first_time) { + if (!BKE_brush_use_locked_size(scene, brush)) { + cache->initial_radius = paint_calc_object_space_radius( + cache->vc, cache->true_location, BKE_brush_size_get(scene, brush)); + BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius); + } + else { + cache->initial_radius = BKE_brush_unprojected_radius_get(scene, brush); } } - return true; + if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, ePaintSculpt)) { + cache->radius = cache->initial_radius * cache->pressure; + } + else { + cache->radius = cache->initial_radius; + } + + cache->radius_squared = cache->radius * cache->radius; + + if (ss->pbvh) { + BKE_pbvh_update(ss->pbvh, PBVH_UpdateRedraw, NULL); + BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL); + } } -static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2])) +static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2]) { Scene *scene = CTX_data_scene(C); struct PaintStroke *stroke = op->customdata; ToolSettings *ts = scene->toolsettings; - VPaint *wp = ts->wpaint; Object *ob = CTX_data_active_object(C); Mesh *me = BKE_mesh_from_object(ob); struct WPaintData *wpd; struct WPaintVGroupIndex vgroup_index; int defbase_tot, defbase_tot_sel; bool *defbase_sel; - const Brush *brush = BKE_paint_brush(&wp->paint); + SculptSession *ss = ob->sculpt; + VPaint *vd = CTX_data_tool_settings(C)->wpaint; float mat[4][4], imat[4][4]; - if (wpaint_ensure_data(C, op, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) { + if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) { return false; } @@ -2094,62 +1321,483 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UN } /* painting on subsurfs should give correct points too, this returns me->totvert amount */ + ob->sculpt->building_vp_handle = true; wpd->vp_handle = ED_vpaint_proj_handle_create(scene, ob, &wpd->vertexcosnos); - - wpd->indexar = get_indexarray(me); - copy_wpaint_prev(wp, me->dvert, me->totvert); - - if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { - BKE_mesh_vert_edge_vert_map_create( - &wpd->blur_data.vmap, &wpd->blur_data.vmap_mem, - me->medge, me->totvert, me->totedge); - } - - if ((brush->vertexpaint_tool == PAINT_BLEND_BLUR) && - (brush->flag & BRUSH_ACCUMULATE)) - { - wpd->accumulate_stack = BLI_stack_new(sizeof(struct WPaintDefer), __func__); - } + ob->sculpt->building_vp_handle = false; /* imat for normals */ mul_m4_m4m4(mat, wpd->vc.rv3d->viewmat, ob->obmat); invert_m4_m4(imat, mat); copy_m3_m4(wpd->wpimat, imat); + /* If not previously created, create vertex/weight paint mode session data */ + vertex_paint_init_session(scene, ob); + vwpaint_update_cache_invariants(C, vd, ss, op, mouse); + vertex_paint_init_session_data(ts, ob); + + if (ss->mode.wpaint.previous_weight != NULL) { + copy_vn_fl(ss->mode.wpaint.previous_weight, me->totvert, -1.0f); + } + return true; } -static float wpaint_blur_weight_single(const MDeformVert *dv, const WeightPaintInfo *wpi) +static float dot_vf3vs3(const float brushNormal[3], const short vertexNormal[3]) { - return defvert_find_weight(dv, wpi->active.index); + float normal[3]; + normal_short_to_float_v3(normal, vertexNormal); + return dot_v3v3(brushNormal, normal); } -static float wpaint_blur_weight_multi(const MDeformVert *dv, const WeightPaintInfo *wpi) +static void get_brush_alpha_data( + Scene *scene, SculptSession *ss, Brush *brush, + float *r_brush_size_pressure, float *r_brush_alpha_value, float *r_brush_alpha_pressure) { - float weight = BKE_defvert_multipaint_collective_weight( - dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize); - CLAMP(weight, 0.0f, 1.0f); - return weight; + *r_brush_size_pressure = + BKE_brush_size_get(scene, brush) * + (BKE_brush_use_size_pressure(scene, brush) ? ss->cache->pressure : 1.0f); + *r_brush_alpha_value = + BKE_brush_alpha_get(scene, brush); + *r_brush_alpha_pressure = + (BKE_brush_use_alpha_pressure(scene, brush) ? ss->cache->pressure : 1.0f); } -static float wpaint_blur_weight_calc_from_connected( - const MDeformVert *dvert, WeightPaintInfo *wpi, struct WPaintData *wpd, const unsigned int vidx, - float (*blur_weight_func)(const MDeformVert *, const WeightPaintInfo *)) +static void do_wpaint_brush_blur_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) { - const MeshElemMap *map = &wpd->blur_data.vmap[vidx]; - float paintweight; - if (map->count != 0) { - paintweight = 0.0f; - for (int j = 0; j < map->count; j++) { - paintweight += blur_weight_func(&dvert[map->indices[j]], wpi); + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap; + + Brush *brush = data->brush; + StrokeCache *cache = ss->cache; + Scene *scene = CTX_data_scene(data->C); + + const float brush_strength = cache->bstrength; + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test_sq(&test, vd.co)) { + /* For grid based pbvh, take the vert whose loop coopresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + const char v_flag = data->me->mvert[v_index].flag; + /* If the vertex is selected */ + if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { + /* Get the average poly weight */ + int total_hit_loops = 0; + float weight_final = 0.0f; + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + const int p_index = gmap->vert_to_poly[v_index].indices[j]; + const MPoly *mp = &data->me->mpoly[p_index]; + + total_hit_loops += mp->totloop; + for (int k = 0; k < mp->totloop; k++) { + const int l_index = mp->loopstart + k; + const MLoop *ml = &data->me->mloop[l_index]; + const MDeformVert *dv = &data->me->dvert[ml->v]; + weight_final += defvert_find_weight(dv, data->wpi->active.index); + } + } + + /* Apply the weight to the vertex. */ + if (total_hit_loops != 0) { + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0f) { + const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); + float final_alpha = + view_dot * brush_fade * brush_strength * + grid_alpha * brush_alpha_pressure; + + if (brush->flag & BRUSH_ACCUMULATE) { + float mask_accum = ss->mode.wpaint.previous_accum[v_index]; + final_alpha = min_ff(final_alpha + mask_accum, brush_strength); + ss->mode.wpaint.previous_accum[v_index] = final_alpha; + } + + weight_final /= total_hit_loops; + /* Only paint visable verts */ + do_weight_paint_vertex( + data->vp, data->ob, data->wpi, + v_index, final_alpha, weight_final); + } + } + } } - paintweight /= map->count; } - else { - paintweight = blur_weight_func(&dvert[vidx], wpi); + BKE_pbvh_vertex_iter_end; +} + +static void do_wpaint_brush_smear_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap; + + Brush *brush = data->brush; + Scene *scene = CTX_data_scene(data->C); + StrokeCache *cache = ss->cache; + const float brush_strength = cache->bstrength; + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + float brush_dir[3]; + + sub_v3_v3v3(brush_dir, cache->location, cache->last_location); + project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal); + + if (normalize_v3(brush_dir) != 0.0f) { + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test_fast(&test, vd.co)) { + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0f) { + bool do_color = false; + + /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + const MVert *mv_curr = &data->me->mvert[v_index]; + + /* If the vertex is selected */ + if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) { + /* Minimum dot product between brush direction and current + * to neighbor direction is 0.0, meaning orthogonal. */ + float stroke_dot_max = 0.0f; + + /* Get the color of the loop in the opposite direction of the brush movement + * (this callback is specifically for smear.) */ + float weight_final = 0.0; + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + const int p_index = gmap->vert_to_poly[v_index].indices[j]; + const MPoly *mp = &data->me->mpoly[p_index]; + const MLoop *ml_other = &data->me->mloop[mp->loopstart]; + for (int k = 0; k < mp->totloop; k++, ml_other++) { + const uint v_other_index = ml_other->v; + if (v_other_index != v_index) { + const MVert *mv_other = &data->me->mvert[v_other_index]; + + /* Get the direction from the selected vert to the neighbor. */ + float other_dir[3]; + sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co); + project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal); + + normalize_v3(other_dir); + + const float stroke_dot = dot_v3v3(other_dir, brush_dir); + + if (stroke_dot > stroke_dot_max) { + stroke_dot_max = stroke_dot; + MDeformVert *dv = &data->me->dvert[v_other_index]; + weight_final = defvert_find_weight(dv, data->wpi->active.index); + do_color = true; + } + } + } + } + /* Apply weight to vertex */ + if (do_color) { + const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); + const float final_alpha = + view_dot * brush_fade * brush_strength * + grid_alpha * brush_alpha_pressure; + do_weight_paint_vertex( + data->vp, data->ob, data->wpi, + v_index, final_alpha, (float)weight_final); + } + } + } + } + } + BKE_pbvh_vertex_iter_end; + } +} + +static void do_wpaint_brush_draw_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + Scene *scene = CTX_data_scene(data->C); + + Brush *brush = data->brush; + StrokeCache *cache = ss->cache; + const float brush_strength = cache->bstrength; + const float paintweight = BKE_brush_weight_get(scene, brush); + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test_sq(&test, vd.co)) { + /* Note: grids are 1:1 with corners (aka loops). + * For multires, take the vert whose loop cooresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + + const char v_flag = data->me->mvert[v_index].flag; + /* If the vertex is selected */ + if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0f) { + const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); + float final_alpha = view_dot * brush_fade * brush_strength * grid_alpha * brush_alpha_pressure; + + if (brush->flag & BRUSH_ACCUMULATE) { + float mask_accum = ss->mode.wpaint.previous_accum[v_index]; + final_alpha = min_ff(final_alpha + mask_accum, brush_strength); + ss->mode.wpaint.previous_accum[v_index] = final_alpha; + } + + /* Non-spray logic. */ + if ((data->vp->flag & VP_SPRAY) == 0) { + /* Only paint if we have greater alpha. */ + if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) { + ss->mode.wpaint.alpha_weight[v_index] = final_alpha; + } + else { + continue; + } + + MDeformVert *dv = &data->me->dvert[v_index]; + MDeformWeight *dw = defvert_find_index(dv, data->wpi->active.index); + float *weight_prev = &ss->mode.wpaint.previous_weight[v_index]; + defweight_prev_init(dw, weight_prev); + if (dw) { + dw->weight = *weight_prev; + } + } + + do_weight_paint_vertex( + data->vp, data->ob, data->wpi, + v_index, final_alpha, paintweight); + } + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_wpaint_brush_calc_average_weight_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + StrokeCache *cache = ss->cache; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + + struct WPaintAverageAccum *accum = (struct WPaintAverageAccum *)data->custom_data + n; + accum->len = 0; + accum->value = 0.0; + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test_sq(&test, vd.co)) { + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0 && BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) { + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + // const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + const char v_flag = data->me->mvert[v_index].flag; + + /* If the vertex is selected. */ + if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { + const MDeformVert *dv = &data->me->dvert[v_index]; + accum->len += 1; + accum->value += defvert_find_weight(dv, data->wpi->active.index); + } + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void calculate_average_weight(SculptThreadedTaskData *data, PBVHNode **UNUSED(nodes), int totnode) +{ + Scene *scene = CTX_data_scene(data->C); + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + + struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); + data->custom_data = accum; + + BLI_task_parallel_range_ex( + 0, totnode, data, NULL, 0, do_wpaint_brush_calc_average_weight_cb_ex, + ((data->sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + + uint accum_len = 0; + double accum_weight = 0.0; + for (int i = 0; i < totnode; i++) { + accum_len += accum[i].len; + accum_weight += accum[i].value; + } + if (accum_len != 0) { + accum_weight /= accum_len; + if (ups->flag & UNIFIED_PAINT_WEIGHT) + ups->weight = (float)accum_weight; + else + data->brush->weight = (float)accum_weight; } - return paintweight; + MEM_SAFE_FREE(data->custom_data); /* 'accum' */ +} + + +static void wpaint_paint_leaves( + bContext *C, Object *ob, Sculpt *sd, VPaint *vp, struct WPaintData *wpd, WeightPaintInfo *wpi, + Mesh *me, PBVHNode **nodes, int totnode) +{ + Brush *brush = ob->sculpt->cache->brush; + + /* threaded loop over nodes */ + SculptThreadedTaskData data = { + .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .wpd = wpd, .wpi = wpi, .me = me, .C = C, + }; + + switch (brush->vertexpaint_tool) { + case PAINT_BLEND_AVERAGE: + calculate_average_weight(&data, nodes, totnode); + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_wpaint_brush_draw_task_cb_ex, true, false); + break; + case PAINT_BLEND_SMEAR: + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_wpaint_brush_smear_task_cb_ex, true, false); + break; + case PAINT_BLEND_BLUR: + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_wpaint_brush_blur_task_cb_ex, true, false); + break; + default: + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_wpaint_brush_draw_task_cb_ex, true, false); + break; + } +} + +static void wpaint_do_paint( + bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi, + Mesh *me, Brush *brush, const char symm, const int axis, const int i, const float angle) +{ + SculptSession *ss = ob->sculpt; + ss->cache->radial_symmetry_pass = i; + sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle); + + SculptSearchSphereData data; + PBVHNode **nodes = NULL; + int totnode; + + + /* Build a list of all nodes that are potentially within the brush's area of influence */ + data.ss = ss; + data.sd = sd; + data.radius_squared = ss->cache->radius_squared; + data.original = true; + BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); + + sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, ss->cache->sculpt_normal_symm); + wpaint_paint_leaves(C, ob, sd, wp, wpd, wpi, me, nodes, totnode); + + if (nodes) + MEM_freeN(nodes); +} + +static void wpaint_do_radial_symmetry( + bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi, + Mesh *me, Brush *brush, const char symm, const int axis) +{ + for (int i = 1; i < wp->radial_symm[axis - 'X']; i++) { + const float angle = (2.0 * M_PI) * i / wp->radial_symm[axis - 'X']; + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, axis, i, angle); + } +} + +/* near duplicate of: sculpt.c's, 'do_symmetrical_brush_actions' and 'vpaint_do_symmetrical_brush_actions'. */ +static void wpaint_do_symmetrical_brush_actions( + bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi) +{ + Brush *brush = BKE_paint_brush(&wp->paint); + Mesh *me = ob->data; + SculptSession *ss = ob->sculpt; + StrokeCache *cache = ss->cache; + const char symm = wp->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + int i = 0; + + /* initial stroke */ + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X', 0, 0); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X'); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Y'); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Z'); + + cache->symmetry = symm; + + /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ + for (i = 1; i <= symm; i++) { + if ((symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) { + cache->mirror_symmetry_pass = i; + cache->radial_symmetry_pass = 0; + sculpt_cache_calc_brushdata_symm(cache, i, 0, 0); + + if (i & (1 << 0)) { + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X', 0, 0); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X'); + } + if (i & (1 << 1)) { + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y', 0, 0); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y'); + } + if (i & (1 << 2)) { + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z', 0, 0); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z'); + } + } + } + copy_v3_v3(cache->true_last_location, cache->true_location); + cache->is_last_valid = true; } static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) @@ -2160,24 +1808,17 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P Brush *brush = BKE_paint_brush(&wp->paint); struct WPaintData *wpd = paint_stroke_mode_data(stroke); ViewContext *vc; - Object *ob; - Mesh *me; + Object *ob = CTX_data_active_object(C); + + SculptSession *ss = ob->sculpt; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + + vwpaint_update_cache_variants(C, wp, ob, itemptr); + float mat[4][4]; - float paintweight; - int *indexar; - unsigned int index, totindex; float mval[2]; - const bool use_blur = (brush->vertexpaint_tool == PAINT_BLEND_BLUR); - bool use_vert_sel; - bool use_face_sel; - bool use_depth; - - const float pressure = RNA_float_get(itemptr, "pressure"); - const float brush_size_pressure = - BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f); + const float brush_alpha_value = BKE_brush_alpha_get(scene, brush); - const float brush_alpha_pressure = - brush_alpha_value * (BKE_brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f); /* intentionally don't initialize as NULL, make sure we initialize all members below */ WeightPaintInfo wpi; @@ -2190,13 +1831,8 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P return; } - float (*blur_weight_func)(const MDeformVert *, const WeightPaintInfo *) = - wpd->do_multipaint ? wpaint_blur_weight_multi : wpaint_blur_weight_single; - vc = &wpd->vc; ob = vc->obact; - me = ob->data; - indexar = wpd->indexar; view3d_operator_needs_opengl(C); ED_view3d_init_mats_rv3d(ob, vc->rv3d); @@ -2204,7 +1840,6 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P /* load projection matrix */ mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); - RNA_float_get_array(itemptr, "mouse", mval); /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */ wpi.defbase_tot = wpd->defbase_tot; @@ -2222,180 +1857,49 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P wpi.brush_alpha_value = brush_alpha_value; /* *** done setting up WeightPaintInfo *** */ + wpaint_do_symmetrical_brush_actions(C, ob, wp, sd, wpd, &wpi); + swap_m4m4(vc->rv3d->persmat, mat); - swap_m4m4(wpd->vc.rv3d->persmat, mat); - - use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; - use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - use_depth = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0; - - /* which faces are involved */ - if (use_depth) { - char editflag_prev = me->editflag; - - /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */ - me->editflag &= ~ME_EDIT_PAINT_VERT_SEL; - if (use_vert_sel) { - /* Ugly x2, we need this so hidden faces don't draw */ - me->editflag |= ME_EDIT_PAINT_FACE_SEL; - } - totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); - me->editflag = editflag_prev; - - if (use_face_sel && me->totpoly) { - MPoly *mpoly = me->mpoly; - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mp = &mpoly[indexar[index] - 1]; - - if ((mp->flag & ME_FACE_SEL) == 0) { - indexar[index] = 0; - } - } - } - } - } - else { - indexar = NULL; - } - - /* incase we have modifiers */ - ED_vpaint_proj_handle_update(wpd->vp_handle, vc->ar, mval); - - /* make sure each vertex gets treated only once */ - /* and calculate filter weight */ - paintweight = BKE_brush_weight_get(scene, brush); + /* calculate pivot for rotation around seletion if needed */ + /* also needed for "View Selected" on last stroke */ + paint_last_stroke_update(scene, vc->ar, mval); - if (use_depth) { - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = me->mpoly + (indexar[index] - 1); - MLoop *ml = me->mloop + mpoly->loopstart; - int i; + DAG_id_tag_update(ob->data, 0); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + swap_m4m4(wpd->vc.rv3d->persmat, mat); - if (use_vert_sel) { - for (i = 0; i < mpoly->totloop; i++, ml++) { - me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT); - } - } - else { - for (i = 0; i < mpoly->totloop; i++, ml++) { - me->dvert[ml->v].flag = 1; - } - } - } + rcti r; + if (sculpt_get_redraw_rect(vc->ar, CTX_wm_region_view3d(C), ob, &r)) { + if (ss->cache) { + ss->cache->current_r = r; } - } - else { - const unsigned int totvert = me->totvert; - unsigned int i; - /* in the case of face selection we need to flush */ - if (use_vert_sel || use_face_sel) { - for (i = 0; i < totvert; i++) { - me->dvert[i].flag = me->mvert[i].flag & SELECT; - } - } - else { - for (i = 0; i < totvert; i++) { - me->dvert[i].flag = SELECT; - } + /* previous is not set in the current cache else + * the partial rect will always grow */ + if (ss->cache) { + if (!BLI_rcti_is_empty(&ss->cache->previous_r)) + BLI_rcti_union(&r, &ss->cache->previous_r); } - } - /* accumulate means we refer to the previous, - * which is either the last update, or when we started painting */ - BLI_Stack *accumulate_stack = wpd->accumulate_stack; - const bool use_accumulate = (accumulate_stack != NULL); - BLI_assert(accumulate_stack == NULL || BLI_stack_is_empty(accumulate_stack)); - - const MDeformVert *dvert_prev = use_accumulate ? me->dvert : wp->wpaint_prev; - -#define WP_PAINT(v_idx_var) \ - { \ - unsigned int vidx = v_idx_var; \ - if (me->dvert[vidx].flag) { \ - const float alpha = calc_vp_alpha_col_dl( \ - wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \ - mval, brush_size_pressure, brush_alpha_pressure, NULL); \ - if (alpha) { \ - if (use_blur) { \ - paintweight = wpaint_blur_weight_calc_from_connected( \ - dvert_prev, &wpi, wpd, vidx, blur_weight_func); \ - } \ - if (use_accumulate) { \ - struct WPaintDefer *dweight = BLI_stack_push_r(accumulate_stack); \ - dweight->index = vidx; \ - dweight->alpha = alpha; \ - dweight->weight = paintweight; \ - } \ - else { \ - do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \ - } \ - } \ - me->dvert[vidx].flag = 0; \ - } \ - } (void)0 - - if (use_depth) { - for (index = 0; index < totindex; index++) { - - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = me->mpoly + (indexar[index] - 1); - MLoop *ml = me->mloop + mpoly->loopstart; - int i; - - for (i = 0; i < mpoly->totloop; i++, ml++) { - WP_PAINT(ml->v); - } - } - } - } - else { - const unsigned int totvert = me->totvert; - unsigned int i; - - for (i = 0; i < totvert; i++) { - WP_PAINT(i); - } - } -#undef WP_PAINT + r.xmin += vc->ar->winrct.xmin - 2; + r.xmax += vc->ar->winrct.xmin + 2; + r.ymin += vc->ar->winrct.ymin - 2; + r.ymax += vc->ar->winrct.ymin + 2; - if (use_accumulate) { - unsigned int defer_count = BLI_stack_count(accumulate_stack); - while (defer_count--) { - struct WPaintDefer *dweight = BLI_stack_peek(accumulate_stack); - do_weight_paint_vertex(wp, ob, &wpi, dweight->index, dweight->alpha, dweight->weight); - BLI_stack_discard(accumulate_stack); - } + ss->partial_redraw = 1; } - - - /* *** free wpi members */ - /* *** done freeing wpi members */ - - - swap_m4m4(vc->rv3d->persmat, mat); - - /* calculate pivot for rotation around seletion if needed */ - /* also needed for "View Selected" on last stroke */ - paint_last_stroke_update(scene, vc->ar, mval); - - DAG_id_tag_update(ob->data, 0); - ED_region_tag_redraw(vc->ar); + ED_region_tag_redraw_partial(vc->ar, &r); } static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) { - ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); struct WPaintData *wpd = paint_stroke_mode_data(stroke); if (wpd) { ED_vpaint_proj_handle_free(wpd->vp_handle); - MEM_freeN(wpd->indexar); - + if (wpd->defbase_sel) MEM_freeN((void *)wpd->defbase_sel); if (wpd->vgroup_validmap) @@ -2407,23 +1911,9 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) if (wpd->mirror.lock) MEM_freeN((void *)wpd->mirror.lock); - if (wpd->blur_data.vmap) { - MEM_freeN(wpd->blur_data.vmap); - } - if (wpd->blur_data.vmap_mem) { - MEM_freeN(wpd->blur_data.vmap_mem); - } - - if (wpd->accumulate_stack) { - BLI_stack_free(wpd->accumulate_stack); - } - MEM_freeN(wpd); } - /* frees prev buffer */ - copy_wpaint_prev(ts->wpaint, NULL, 0); - /* and particles too */ if (ob->particlesystem.first) { ParticleSystem *psys; @@ -2442,6 +1932,9 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) DAG_id_tag_update(ob->data, 0); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; } @@ -2449,9 +1942,10 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; - op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start, - wpaint_stroke_update_step, NULL, - wpaint_stroke_done, event->type); + op->customdata = paint_stroke_new( + C, op, sculpt_stroke_get_location, wpaint_stroke_test_start, + wpaint_stroke_update_step, NULL, + wpaint_stroke_done, event->type); if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { paint_stroke_data_free(op); @@ -2468,9 +1962,10 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int wpaint_exec(bContext *C, wmOperator *op) { - op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start, - wpaint_stroke_update_step, NULL, - wpaint_stroke_done, 0); + op->customdata = paint_stroke_new( + C, op, sculpt_stroke_get_location, wpaint_stroke_test_start, + wpaint_stroke_update_step, NULL, + wpaint_stroke_done, 0); /* frees op->customdata */ paint_stroke_exec(C, op); @@ -2480,6 +1975,12 @@ static int wpaint_exec(bContext *C, wmOperator *op) static void wpaint_cancel(bContext *C, wmOperator *op) { + Object *ob = CTX_data_active_object(C); + if (ob->sculpt->cache) { + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; + } + paint_stroke_cancel(C, op); } @@ -2504,42 +2005,6 @@ void PAINT_OT_weight_paint(wmOperatorType *ot) paint_stroke_operator_properties(ot); } -static int weight_paint_set_exec(bContext *C, wmOperator *op) -{ - struct Scene *scene = CTX_data_scene(C); - Object *obact = CTX_data_active_object(C); - ToolSettings *ts = CTX_data_tool_settings(C); - Brush *brush = BKE_paint_brush(&ts->wpaint->paint); - float vgroup_weight = BKE_brush_weight_get(scene, brush); - - if (wpaint_ensure_data(C, op, WPAINT_ENSURE_MIRROR, NULL) == false) { - return OPERATOR_CANCELLED; - } - - if (ED_wpaint_fill(scene->toolsettings->wpaint, obact, vgroup_weight)) { - ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */ - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -void PAINT_OT_weight_set(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Set Weight"; - ot->idname = "PAINT_OT_weight_set"; - ot->description = "Fill the active vertex group with the current paint weight"; - - /* api callbacks */ - ot->exec = weight_paint_set_exec; - ot->poll = mask_paint_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - /* ************ set / clear vertex paint mode ********** */ /** @@ -2569,15 +2034,24 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { BKE_mesh_flush_select_from_polys(me); } + else if (me->editflag & ME_EDIT_PAINT_VERT_SEL) { + BKE_mesh_flush_select_from_verts(me); + } + + /* If the cache is not released by a cancel or a done, free it now. */ + if (ob->sculpt->cache) { + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; + } + + BKE_sculptsession_free(ob); paint_cursor_delete_textures(); } else { ob->mode |= mode_flag; - if (me->mloopcol == NULL) { - make_vertexcol(ob); - } + ED_mesh_color_ensure(me, NULL); if (vp == NULL) vp = scene->toolsettings->vpaint = new_vpaint(0); @@ -2585,6 +2059,16 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) paint_cursor_start(C, vertex_paint_poll); BKE_paint_init(scene, ePaintVertex, PAINT_CURSOR_VERTEX_PAINT); + + /* Create vertex/weight paint mode session data */ + if (ob->sculpt) { + if (ob->sculpt->cache) { + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; + } + BKE_sculptsession_free(ob); + } + vertex_paint_init_session(scene, ob); } /* update modifier stack for mapping requirements */ @@ -2638,13 +2122,12 @@ typedef struct PolyFaceMap { int facenr; } PolyFaceMap; -typedef struct VPaintData { +struct VPaintData { ViewContext vc; - unsigned int paintcol; - int *indexar; + uint paintcol; struct VertProjHandle *vp_handle; - DMCoNo *vertexcosnos; + struct DMCoNo *vertexcosnos; float vpimat[3][3]; @@ -2657,9 +2140,9 @@ typedef struct VPaintData { bool *mlooptag; bool is_texbrush; -} VPaintData; +}; -static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float UNUSED(mouse[2])) +static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2]) { Scene *scene = CTX_data_scene(C); ToolSettings *ts = scene->toolsettings; @@ -2670,25 +2153,22 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f Object *ob = CTX_data_active_object(C); Mesh *me; float mat[4][4], imat[4][4]; + SculptSession *ss = ob->sculpt; /* context checks could be a poll() */ me = BKE_mesh_from_object(ob); if (me == NULL || me->totpoly == 0) return false; - if (me->mloopcol == NULL) - make_vertexcol(ob); + ED_mesh_color_ensure(me, NULL); if (me->mloopcol == NULL) return false; /* make mode data storage */ - vpd = MEM_callocN(sizeof(struct VPaintData), "VPaintData"); + vpd = MEM_callocN(sizeof(*vpd), "VPaintData"); paint_stroke_set_mode_data(stroke, vpd); view3d_set_viewcontext(C, &vpd->vc); - vpd->vp_handle = ED_vpaint_proj_handle_create(vpd->vc.scene, ob, &vpd->vertexcosnos); - - vpd->indexar = get_indexarray(me); vpd->paintcol = vpaint_get_current_col(scene, vp); vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) && @@ -2710,84 +2190,551 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f vpd->mlooptag = MEM_mallocN(sizeof(bool) * me->totloop, "VPaintData mlooptag"); } - /* for filtering */ - copy_vpaint_prev(vp, (unsigned int *)me->mloopcol, me->totloop); - + /* Create projection handle */ + if (vpd->is_texbrush) { + ob->sculpt->building_vp_handle = true; + vpd->vp_handle = ED_vpaint_proj_handle_create(scene, ob, &vpd->vertexcosnos); + ob->sculpt->building_vp_handle = false; + } + /* some old cruft to sort out later */ mul_m4_m4m4(mat, vpd->vc.rv3d->viewmat, ob->obmat); invert_m4_m4(imat, mat); copy_m3_m4(vpd->vpimat, imat); + /* If not previously created, create vertex/weight paint mode session data */ + vertex_paint_init_session(scene, ob); + vwpaint_update_cache_invariants(C, vp, ss, op, mouse); + vertex_paint_init_session_data(ts, ob); + + if (ob->sculpt->mode.vpaint.previous_color != NULL) { + memset(ob->sculpt->mode.vpaint.previous_color, 0, sizeof(uint) * me->totloop); + } + return 1; } -static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me, - const unsigned int index, const float mval[2], - const float brush_size_pressure, const float brush_alpha_pressure) +static void do_vpaint_brush_calc_average_color_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) { - ViewContext *vc = &vpd->vc; - Brush *brush = BKE_paint_brush(&vp->paint); - MPoly *mpoly = &me->mpoly[index]; - MLoop *ml; - unsigned int *lcol = ((unsigned int *)me->mloopcol) + mpoly->loopstart; - unsigned int *lcolorig = ((unsigned int *)vp->vpaint_prev) + mpoly->loopstart; - bool *mlooptag = (vpd->mlooptag) ? vpd->mlooptag + mpoly->loopstart : NULL; - float alpha; - int i, j; - int totloop = mpoly->totloop; + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; - int brush_alpha_pressure_i = (int)(brush_alpha_pressure * 255.0f); + StrokeCache *cache = ss->cache; + uint *lcol = data->lcol; + char *col; + const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; - if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { - unsigned int blend[4] = {0}; - unsigned int tcol; - char *col; - - for (j = 0; j < totloop; j++) { - col = (char *)(lcol + j); - blend[0] += col[0]; - blend[1] += col[1]; - blend[2] += col[2]; - blend[3] += col[3]; - } - - blend[0] = divide_round_i(blend[0], totloop); - blend[1] = divide_round_i(blend[1], totloop); - blend[2] = divide_round_i(blend[2], totloop); - blend[3] = divide_round_i(blend[3], totloop); - col = (char *)&tcol; - col[0] = blend[0]; - col[1] = blend[1]; - col[2] = blend[2]; - col[3] = blend[3]; - - vpd->paintcol = *((unsigned int *)col); - } - - ml = me->mloop + mpoly->loopstart; - for (i = 0; i < totloop; i++, ml++) { - float rgba[4]; - unsigned int paintcol; - alpha = calc_vp_alpha_col_dl(vp, vc, vpd->vpimat, - &vpd->vertexcosnos[ml->v], mval, - brush_size_pressure, brush_alpha_pressure, rgba); - - if (vpd->is_texbrush) { - float rgba_br[3]; - rgb_uchar_to_float(rgba_br, (const unsigned char *)&vpd->paintcol); - mul_v3_v3(rgba_br, rgba); - rgb_float_to_uchar((unsigned char *)&paintcol, rgba_br); + struct VPaintAverageAccum *accum = (struct VPaintAverageAccum *)data->custom_data + n; + accum->len = 0; + memset(accum->value, 0, sizeof(accum->value)); + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test_fast(&test, vd.co)) { + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + if (BKE_brush_curve_strength(data->brush, test.dist, cache->radius) > 0.0) { + /* If the vertex is selected for painting. */ + const MVert *mv = &data->me->mvert[v_index]; + if (!use_vert_sel || mv->flag & SELECT) { + accum->len += gmap->vert_to_loop[v_index].count; + /* if a vertex is within the brush region, then add it's color to the blend. */ + for (int j = 0; j < gmap->vert_to_loop[v_index].count; j++) { + const int l_index = gmap->vert_to_loop[v_index].indices[j]; + col = (char *)(&lcol[l_index]); + /* Color is squared to compensate the sqrt color encoding. */ + accum->value[0] += col[0] * col[0]; + accum->value[1] += col[1] * col[1]; + accum->value[2] += col[2] * col[2]; + } + } + } } - else - paintcol = vpd->paintcol; + } + BKE_pbvh_vertex_iter_end; +} + +static void handle_texture_brush( + SculptThreadedTaskData *data, PBVHVertexIter vd, float size_pressure, float alpha_pressure, + float *r_alpha, uint *r_color) +{ + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + + float rgba[4]; + float rgba_br[3]; + + *r_alpha = calc_vp_alpha_col_dl( + data->vp, &data->vpd->vc, data->vpd->vpimat, + &data->vpd->vertexcosnos[v_index], ss->cache->mouse, size_pressure, alpha_pressure, rgba); + rgb_uchar_to_float(rgba_br, (const uchar *)&data->vpd->paintcol); + mul_v3_v3(rgba_br, rgba); + rgb_float_to_uchar((uchar *)r_color, rgba_br); +} + +static void do_vpaint_brush_draw_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; + + Brush *brush = data->brush; + StrokeCache *cache = ss->cache; + const float brush_strength = cache->bstrength; + uint *lcol = data->lcol; + Scene *scene = CTX_data_scene(data->C); + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - if (alpha > 0.0f) { - const int alpha_i = (int)(alpha * 255.0f); - lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], paintcol, alpha_i, brush_alpha_pressure_i); + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); - if (mlooptag) mlooptag[i] = 1; + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test(&test, vd.co)) { + /* Note: Grids are 1:1 with corners (aka loops). + * For grid based pbvh, take the vert whose loop cooresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + const MVert *mv = &data->me->mvert[v_index]; + + /* If the vertex is selected for painting. */ + if (!use_vert_sel || mv->flag & SELECT) { + /* Calc the dot prod. between ray norm on surf and current vert + * (ie splash prevention factor), and only paint front facing verts. */ + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0f) { + const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); + uint color_final = data->vpd->paintcol; + + /* If we're painting with a texture, sample the texture color and alpha. */ + float tex_alpha = 1.0; + if (data->vpd->is_texbrush) { + handle_texture_brush( + data, vd, brush_size_pressure, brush_alpha_pressure, + &tex_alpha, &color_final); + } + /* For each poly owning this vert, paint each loop belonging to this vert. */ + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + const int p_index = gmap->vert_to_poly[v_index].indices[j]; + const int l_index = gmap->vert_to_loop[v_index].indices[j]; + BLI_assert(data->me->mloop[l_index].v == v_index); + const MPoly *mp = &data->me->mpoly[p_index]; + if (!use_face_sel || mp->flag & ME_FACE_SEL) { + uint color_orig = 0; /* unused when array is NULL */ + if (ss->mode.vpaint.previous_color != NULL) { + /* Get the previous loop color */ + if (ss->mode.vpaint.previous_color[l_index] == 0) { + ss->mode.vpaint.previous_color[l_index] = lcol[l_index]; + } + color_orig = ss->mode.vpaint.previous_color[l_index]; + } + float final_alpha = + 255 * brush_fade * brush_strength * view_dot * + tex_alpha * brush_alpha_pressure * grid_alpha; + + if (brush->flag & BRUSH_ACCUMULATE) { + float mask_accum = ss->mode.vpaint.previous_accum[l_index]; + final_alpha = min_ff(final_alpha + mask_accum, 255.0f * brush_strength); + ss->mode.vpaint.previous_accum[l_index] = final_alpha; + } + + /* Mix the new color with the original based on final_alpha. */ + lcol[l_index] = vpaint_blend( + data->vp, lcol[l_index], color_orig, color_final, + final_alpha, 255 * brush_strength); + } + } + } + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_vpaint_brush_blur_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + + Scene *scene = CTX_data_scene(data->C); + const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; + Brush *brush = data->brush; + StrokeCache *cache = ss->cache; + const float brush_strength = cache->bstrength; + uint *lcol = data->lcol; + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test(&test, vd.co)) { + /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + const MVert *mv = &data->me->mvert[v_index]; + + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0f) { + const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); + + /* If the vertex is selected for painting. */ + if (!use_vert_sel || mv->flag & SELECT) { + /* Get the average poly color */ + uint color_final = 0; + int total_hit_loops = 0; + uint blend[4] = {0}; + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + int p_index = gmap->vert_to_poly[v_index].indices[j]; + const MPoly *mp = &data->me->mpoly[p_index]; + if (!use_face_sel || mp->flag & ME_FACE_SEL) { + total_hit_loops += mp->totloop; + for (int k = 0; k < mp->totloop; k++) { + const uint l_index = mp->loopstart + k; + const char *col = (const char *)(&lcol[l_index]); + /* Color is squared to compensate the sqrt color encoding. */ + blend[0] += (uint)col[0] * (uint)col[0]; + blend[1] += (uint)col[1] * (uint)col[1]; + blend[2] += (uint)col[2] * (uint)col[2]; + blend[3] += (uint)col[3] * (uint)col[3]; + } + } + } + if (total_hit_loops != 0) { + /* Use rgb^2 color averaging. */ + char *col = (char *)(&color_final); + col[0] = round_fl_to_uchar(sqrtf(divide_round_i(blend[0], total_hit_loops))); + col[1] = round_fl_to_uchar(sqrtf(divide_round_i(blend[1], total_hit_loops))); + col[2] = round_fl_to_uchar(sqrtf(divide_round_i(blend[2], total_hit_loops))); + col[3] = round_fl_to_uchar(sqrtf(divide_round_i(blend[3], total_hit_loops))); + + /* For each poly owning this vert, paint each loop belonging to this vert. */ + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + const int p_index = gmap->vert_to_poly[v_index].indices[j]; + const int l_index = gmap->vert_to_loop[v_index].indices[j]; + BLI_assert(data->me->mloop[l_index].v == v_index); + const MPoly *mp = &data->me->mpoly[p_index]; + if (!use_face_sel || mp->flag & ME_FACE_SEL) { + uint color_orig = 0; /* unused when array is NULL */ + if (ss->mode.vpaint.previous_color != NULL) { + /* Get the previous loop color */ + if (ss->mode.vpaint.previous_color[l_index] == 0) { + ss->mode.vpaint.previous_color[l_index] = lcol[l_index]; + } + color_orig = ss->mode.vpaint.previous_color[l_index]; + } + const float final_alpha = + 255 * brush_fade * brush_strength * view_dot * + brush_alpha_pressure * grid_alpha; + /* Mix the new color with the original + * based on the brush strength and the curve. */ + lcol[l_index] = vpaint_blend( + data->vp, lcol[l_index], color_orig, *((uint *)col), + final_alpha, 255 * brush_strength); + } + } + } + } + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_vpaint_brush_smear_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + + Scene *scene = CTX_data_scene(data->C); + const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; + Brush *brush = data->brush; + StrokeCache *cache = ss->cache; + const float brush_strength = cache->bstrength; + uint *lcol = data->lcol; + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + float brush_dir[3]; + const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + + sub_v3_v3v3(brush_dir, cache->location, cache->last_location); + project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal); + + if (normalize_v3(brush_dir) != 0.0f) { + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test(&test, vd.co)) { + /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + const MVert *mv_curr = &data->me->mvert[v_index]; + + /* if the vertex is selected for painting. */ + if (!use_vert_sel || mv_curr->flag & SELECT) { + /* Calc the dot prod. between ray norm on surf and current vert + * (ie splash prevention factor), and only paint front facing verts. */ + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0f) { + const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); + + bool do_color = false; + /* Minimum dot product between brush direction and current + * to neighbor direction is 0.0, meaning orthogonal. */ + float stroke_dot_max = 0.0f; + + /* Get the color of the loop in the opposite direction of the brush movement */ + uint color_final = 0; + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + const int p_index = gmap->vert_to_poly[v_index].indices[j]; + const int l_index = gmap->vert_to_loop[v_index].indices[j]; + BLI_assert(data->me->mloop[l_index].v == v_index); + const MPoly *mp = &data->me->mpoly[p_index]; + if (!use_face_sel || mp->flag & ME_FACE_SEL) { + const MLoop *ml_other = &data->me->mloop[mp->loopstart]; + for (int k = 0; k < mp->totloop; k++, ml_other++) { + const uint v_other_index = ml_other->v; + if (v_other_index != v_index) { + const MVert *mv_other = &data->me->mvert[v_other_index]; + + /* Get the direction from the selected vert to the neighbor. */ + float other_dir[3]; + sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co); + project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal); + + normalize_v3(other_dir); + + const float stroke_dot = dot_v3v3(other_dir, brush_dir); + + if (stroke_dot > stroke_dot_max) { + stroke_dot_max = stroke_dot; + color_final = lcol[mp->loopstart + k]; + do_color = true; + } + } + } + } + } + + if (do_color) { + /* For each poly owning this vert, paint each loop belonging to this vert. */ + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + const int p_index = gmap->vert_to_poly[v_index].indices[j]; + const int l_index = gmap->vert_to_loop[v_index].indices[j]; + BLI_assert(data->me->mloop[l_index].v == v_index); + const MPoly *mp = &data->me->mpoly[p_index]; + if (!use_face_sel || mp->flag & ME_FACE_SEL) { + /* Get the previous loop color */ + uint color_orig = 0; /* unused when array is NULL */ + if (ss->mode.vpaint.previous_color != NULL) { + /* Get the previous loop color */ + if (ss->mode.vpaint.previous_color[l_index] == 0) { + ss->mode.vpaint.previous_color[l_index] = lcol[l_index]; + } + color_orig = ss->mode.vpaint.previous_color[l_index]; + } + const float final_alpha = + 255 * brush_fade * brush_strength * + view_dot * brush_alpha_pressure * grid_alpha; + /* Mix the new color with the original + * based on the brush strength and the curve. */ + lcol[l_index] = vpaint_blend( + data->vp, lcol[l_index], color_orig, color_final, + final_alpha, 255 * brush_strength); + } + } + } + } + } + } + } + BKE_pbvh_vertex_iter_end; + } +} + +static void calculate_average_color(SculptThreadedTaskData *data, PBVHNode **UNUSED(nodes), int totnode) +{ + struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); + data->custom_data = accum; + + BLI_task_parallel_range_ex( + 0, totnode, data, NULL, 0, do_vpaint_brush_calc_average_color_cb_ex, + true, false); + + uint accum_len = 0; + uint accum_value[3] = {0}; + uchar blend[4] = {0}; + for (int i = 0; i < totnode; i++) { + accum_len += accum[i].len; + accum_value[0] += accum[i].value[0]; + accum_value[1] += accum[i].value[1]; + accum_value[2] += accum[i].value[2]; + } + if (accum_len != 0) { + blend[0] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[0], accum_len))); + blend[1] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[1], accum_len))); + blend[2] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[2], accum_len))); + blend[3] = 255; + data->vpd->paintcol = *((uint *)blend); + } + + MEM_SAFE_FREE(data->custom_data); /* 'accum' */ +} + +static void vpaint_paint_leaves( + bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd, + Object *ob, Mesh *me, PBVHNode **nodes, int totnode) +{ + Brush *brush = ob->sculpt->cache->brush; + + SculptThreadedTaskData data = { + .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd, + .lcol = (uint *)me->mloopcol, .me = me, .C = C, + }; + switch (brush->vertexpaint_tool) { + case PAINT_BLEND_AVERAGE: + calculate_average_color(&data, nodes, totnode); + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_vpaint_brush_draw_task_cb_ex, true, false); + break; + case PAINT_BLEND_BLUR: + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_vpaint_brush_blur_task_cb_ex, true, false); + break; + case PAINT_BLEND_SMEAR: + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_vpaint_brush_smear_task_cb_ex, true, false); + break; + default: + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_vpaint_brush_draw_task_cb_ex, true, false); + break; + } +} + +static void vpaint_do_paint( + bContext *C, Sculpt *sd, VPaint *vd, struct VPaintData *vpd, + Object *ob, Mesh *me, Brush *brush, const char symm, const int axis, const int i, const float angle) +{ + SculptSession *ss = ob->sculpt; + ss->cache->radial_symmetry_pass = i; + sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle); + SculptSearchSphereData data; + PBVHNode **nodes = NULL; + int totnode; + + /* Build a list of all nodes that are potentially within the brush's area of influence */ + data.ss = ss; + data.sd = sd; + data.radius_squared = ss->cache->radius_squared; + data.original = true; + BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); + + sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, ss->cache->sculpt_normal_symm); + + /* Paint those leaves. */ + vpaint_paint_leaves(C, sd, vd, vpd, ob, me, nodes, totnode); + + if (nodes) { + MEM_freeN(nodes); + } +} + +static void vpaint_do_radial_symmetry( + bContext *C, Sculpt *sd, VPaint *vd, struct VPaintData *vpd, Object *ob, Mesh *me, + Brush *brush, const char symm, const int axis) +{ + for (int i = 1; i < vd->radial_symm[axis - 'X']; i++) { + const float angle = (2.0 * M_PI) * i / vd->radial_symm[axis - 'X']; + vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, symm, axis, i, angle); + } +} + +/* near duplicate of: sculpt.c's, 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */ +static void vpaint_do_symmetrical_brush_actions( + bContext *C, Sculpt *sd, VPaint *vd, struct VPaintData *vpd, Object *ob) +{ + Brush *brush = BKE_paint_brush(&vd->paint); + Mesh *me = ob->data; + SculptSession *ss = ob->sculpt; + StrokeCache *cache = ss->cache; + const char symm = vd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + int i = 0; + + /* initial stroke */ + vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, i, 'X', 0, 0); + vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'X'); + vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'Y'); + vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'Z'); + + cache->symmetry = symm; + + /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ + for (i = 1; i <= symm; i++) { + if (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5))) { + cache->mirror_symmetry_pass = i; + cache->radial_symmetry_pass = 0; + sculpt_cache_calc_brushdata_symm(cache, i, 0, 0); + + if (i & (1 << 0)) { + vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, i, 'X', 0, 0); + vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'X'); + } + if (i & (1 << 1)) { + vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, i, 'Y', 0, 0); + vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'Y'); + } + if (i & (1 << 2)) { + vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, i, 'Z', 0, 0); + vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'Z'); + } } } + + copy_v3_v3(cache->true_last_location, cache->true_location); + cache->is_last_valid = true; } static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) @@ -2796,65 +2743,26 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P ToolSettings *ts = CTX_data_tool_settings(C); struct VPaintData *vpd = paint_stroke_mode_data(stroke); VPaint *vp = ts->vpaint; - Brush *brush = BKE_paint_brush(&vp->paint); ViewContext *vc = &vpd->vc; Object *ob = vc->obact; - Mesh *me = ob->data; - float mat[4][4]; - int *indexar = vpd->indexar; - int totindex, index; - float mval[2]; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - const float pressure = RNA_float_get(itemptr, "pressure"); - const float brush_size_pressure = - BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f); - const float brush_alpha_pressure = - BKE_brush_alpha_get(scene, brush) * (BKE_brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f); + vwpaint_update_cache_variants(C, vp, ob, itemptr); - RNA_float_get_array(itemptr, "mouse", mval); + float mat[4][4]; + float mval[2]; - view3d_operator_needs_opengl(C); ED_view3d_init_mats_rv3d(ob, vc->rv3d); /* load projection matrix */ mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); - /* which faces are involved */ - totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); - - if ((me->editflag & ME_EDIT_PAINT_FACE_SEL) && me->mpoly) { - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - const MPoly *mpoly = &me->mpoly[indexar[index] - 1]; - - if ((mpoly->flag & ME_FACE_SEL) == 0) - indexar[index] = 0; - } - } - } - swap_m4m4(vc->rv3d->persmat, mat); - /* incase we have modifiers */ - ED_vpaint_proj_handle_update(vpd->vp_handle, vc->ar, mval); - - /* clear modified tag for blur tool */ - if (vpd->mlooptag) - memset(vpd->mlooptag, 0, sizeof(bool) * me->totloop); + vpaint_do_symmetrical_brush_actions(C, sd, vp, vpd, ob); - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - vpaint_paint_poly(vp, vpd, me, indexar[index] - 1, mval, brush_size_pressure, brush_alpha_pressure); - } - } - swap_m4m4(vc->rv3d->persmat, mat); - /* was disabled because it is slow, but necessary for blur */ - if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { - do_shared_vertexcol(me, vpd->mlooptag); - } - /* calculate pivot for rotation around seletion if needed */ /* also needed for "View Selected" on last stroke */ paint_last_stroke_update(scene, vc->ar, mval); @@ -2874,32 +2782,26 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) { - ToolSettings *ts = CTX_data_tool_settings(C); struct VPaintData *vpd = paint_stroke_mode_data(stroke); ViewContext *vc = &vpd->vc; Object *ob = vc->obact; - Mesh *me = ob->data; - - ED_vpaint_proj_handle_free(vpd->vp_handle); - MEM_freeN(vpd->indexar); - - /* frees prev buffer */ - copy_vpaint_prev(ts->vpaint, NULL, 0); if (vpd->mlooptag) MEM_freeN(vpd->mlooptag); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - DAG_id_tag_update(&me->id, 0); MEM_freeN(vpd); + + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; } static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; - op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, vpaint_stroke_test_start, vpaint_stroke_update_step, NULL, vpaint_stroke_done, event->type); @@ -2919,7 +2821,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int vpaint_exec(bContext *C, wmOperator *op) { - op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, vpaint_stroke_test_start, vpaint_stroke_update_step, NULL, vpaint_stroke_done, 0); @@ -2931,6 +2833,12 @@ static int vpaint_exec(bContext *C, wmOperator *op) static void vpaint_cancel(bContext *C, wmOperator *op) { + Object *ob = CTX_data_active_object(C); + if (ob->sculpt->cache) { + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; + } + paint_stroke_cancel(C, op); } @@ -2953,369 +2861,3 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot) paint_stroke_operator_properties(ot); } - -/* ********************** weight from bones operator ******************* */ - -static int weight_from_bones_poll(bContext *C) -{ - Object *ob = CTX_data_active_object(C); - - return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob)); -} - -static int weight_from_bones_exec(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - Object *armob = modifiers_isDeformedByArmature(ob); - Mesh *me = ob->data; - int type = RNA_enum_get(op->ptr, "type"); - - create_vgroups_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X)); - - DAG_id_tag_update(&me->id, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); - - return OPERATOR_FINISHED; -} - -void PAINT_OT_weight_from_bones(wmOperatorType *ot) -{ - static EnumPropertyItem type_items[] = { - {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"}, - {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"}, - {0, NULL, 0, NULL, NULL}}; - - /* identifiers */ - ot->name = "Weight from Bones"; - ot->idname = "PAINT_OT_weight_from_bones"; - ot->description = "Set the weights of the groups matching the attached armature's selected bones, " - "using the distance between the vertices and the bones"; - - /* api callbacks */ - ot->exec = weight_from_bones_exec; - ot->invoke = WM_menu_invoke; - ot->poll = weight_from_bones_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights"); -} - -/* *** VGroups Gradient *** */ -typedef struct DMGradient_vertStore { - float sco[2]; - float weight_orig; - enum { - VGRAD_STORE_NOP = 0, - VGRAD_STORE_DW_EXIST = (1 << 0) - } flag; -} DMGradient_vertStore; - -typedef struct DMGradient_userData { - struct ARegion *ar; - Scene *scene; - Mesh *me; - Brush *brush; - const float *sco_start; /* [2] */ - const float *sco_end; /* [2] */ - float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */ - int def_nr; - bool is_init; - DMGradient_vertStore *vert_cache; - /* only for init */ - BLI_bitmap *vert_visit; - - /* options */ - short use_select; - short type; - float weightpaint; -} DMGradient_userData; - -static void gradientVert_update(DMGradient_userData *grad_data, int index) -{ - Mesh *me = grad_data->me; - DMGradient_vertStore *vs = &grad_data->vert_cache[index]; - float alpha; - - if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) { - alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end); - } - else { - BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL); - alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div; - } - /* no need to clamp 'alpha' yet */ - - /* adjust weight */ - alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f); - - if (alpha != 0.0f) { - MDeformVert *dv = &me->dvert[index]; - MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr); - // dw->weight = alpha; // testing - int tool = grad_data->brush->vertexpaint_tool; - float testw; - - /* init if we just added */ - testw = wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha); - CLAMP(testw, 0.0f, 1.0f); - dw->weight = testw; - } - else { - MDeformVert *dv = &me->dvert[index]; - if (vs->flag & VGRAD_STORE_DW_EXIST) { - /* normally we NULL check, but in this case we know it exists */ - MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); - dw->weight = vs->weight_orig; - } - else { - /* wasn't originally existing, remove */ - MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); - if (dw) { - defvert_remove_group(dv, dw); - } - } - } -} - -static void gradientVertUpdate__mapFunc( - void *userData, int index, const float UNUSED(co[3]), - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) -{ - DMGradient_userData *grad_data = userData; - Mesh *me = grad_data->me; - if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) { - DMGradient_vertStore *vs = &grad_data->vert_cache[index]; - if (vs->sco[0] != FLT_MAX) { - gradientVert_update(grad_data, index); - } - } -} - -static void gradientVertInit__mapFunc( - void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) -{ - DMGradient_userData *grad_data = userData; - Mesh *me = grad_data->me; - - if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) { - /* run first pass only, - * the screen coords of the verts need to be cached because - * updating the mesh may move them about (entering feedback loop) */ - - if (BLI_BITMAP_TEST(grad_data->vert_visit, index) == 0) { - DMGradient_vertStore *vs = &grad_data->vert_cache[index]; - if (ED_view3d_project_float_object(grad_data->ar, - co, vs->sco, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) - { - /* ok */ - MDeformVert *dv = &me->dvert[index]; - MDeformWeight *dw; - dw = defvert_find_index(dv, grad_data->def_nr); - if (dw) { - vs->weight_orig = dw->weight; - vs->flag = VGRAD_STORE_DW_EXIST; - } - else { - vs->weight_orig = 0.0f; - vs->flag = VGRAD_STORE_NOP; - } - - BLI_BITMAP_ENABLE(grad_data->vert_visit, index); - - gradientVert_update(grad_data, index); - } - else { - /* no go */ - copy_v2_fl(vs->sco, FLT_MAX); - } - } - } -} - -static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - int ret = WM_gesture_straightline_modal(C, op, event); - - if (ret & OPERATOR_RUNNING_MODAL) { - if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */ - /* generally crap! redo! */ - WM_gesture_straightline_cancel(C, op); - ret &= ~OPERATOR_RUNNING_MODAL; - ret |= OPERATOR_FINISHED; - } - } - - if (ret & OPERATOR_CANCELLED) { - ToolSettings *ts = CTX_data_tool_settings(C); - VPaint *wp = ts->wpaint; - Object *ob = CTX_data_active_object(C); - Mesh *me = ob->data; - if (wp->wpaint_prev) { - BKE_defvert_array_free_elems(me->dvert, me->totvert); - BKE_defvert_array_copy(me->dvert, wp->wpaint_prev, me->totvert); - free_wpaint_prev(wp); - } - - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - } - else if (ret & OPERATOR_FINISHED) { - ToolSettings *ts = CTX_data_tool_settings(C); - VPaint *wp = ts->wpaint; - free_wpaint_prev(wp); - } - - return ret; -} - -static int paint_weight_gradient_exec(bContext *C, wmOperator *op) -{ - wmGesture *gesture = op->customdata; - DMGradient_vertStore *vert_cache; - struct ARegion *ar = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - Mesh *me = ob->data; - int x_start = RNA_int_get(op->ptr, "xstart"); - int y_start = RNA_int_get(op->ptr, "ystart"); - int x_end = RNA_int_get(op->ptr, "xend"); - int y_end = RNA_int_get(op->ptr, "yend"); - float sco_start[2] = {x_start, y_start}; - float sco_end[2] = {x_end, y_end}; - const bool is_interactive = (gesture != NULL); - DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); - - DMGradient_userData data = {NULL}; - - if (is_interactive) { - if (gesture->userdata == NULL) { - VPaint *wp = scene->toolsettings->wpaint; - - gesture->userdata = MEM_mallocN(sizeof(DMGradient_vertStore) * me->totvert, __func__); - data.is_init = true; - - copy_wpaint_prev(wp, me->dvert, me->totvert); - - /* on init only, convert face -> vert sel */ - if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { - BKE_mesh_flush_select_from_polys(me); - } - } - - vert_cache = gesture->userdata; - } - else { - if (wpaint_ensure_data(C, op, 0, NULL) == false) { - return OPERATOR_CANCELLED; - } - - data.is_init = true; - vert_cache = MEM_mallocN(sizeof(DMGradient_vertStore) * me->totvert, __func__); - } - - data.ar = ar; - data.scene = scene; - data.me = ob->data; - data.sco_start = sco_start; - data.sco_end = sco_end; - data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end); - data.def_nr = ob->actdef - 1; - data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)); - data.vert_cache = vert_cache; - data.vert_visit = NULL; - data.type = RNA_enum_get(op->ptr, "type"); - - { - ToolSettings *ts = CTX_data_tool_settings(C); - VPaint *wp = ts->wpaint; - struct Brush *brush = BKE_paint_brush(&wp->paint); - - curvemapping_initialize(brush->curve); - - data.brush = brush; - data.weightpaint = BKE_brush_weight_get(scene, brush); - } - - ED_view3d_init_mats_rv3d(ob, ar->regiondata); - - if (data.is_init) { - data.vert_visit = BLI_BITMAP_NEW(me->totvert, __func__); - - dm->foreachMappedVert(dm, gradientVertInit__mapFunc, &data, DM_FOREACH_NOP); - - MEM_freeN(data.vert_visit); - data.vert_visit = NULL; - } - else { - dm->foreachMappedVert(dm, gradientVertUpdate__mapFunc, &data, DM_FOREACH_NOP); - } - - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - if (is_interactive == false) { - MEM_freeN(vert_cache); - } - - return OPERATOR_FINISHED; -} - -static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - int ret; - - if (wpaint_ensure_data(C, op, 0, NULL) == false) { - return OPERATOR_CANCELLED; - } - - ret = WM_gesture_straightline_invoke(C, op, event); - if (ret & OPERATOR_RUNNING_MODAL) { - struct ARegion *ar = CTX_wm_region(C); - if (ar->regiontype == RGN_TYPE_WINDOW) { - /* TODO, hardcoded, extend WM_gesture_straightline_ */ - if (event->type == LEFTMOUSE && event->val == KM_PRESS) { - wmGesture *gesture = op->customdata; - gesture->mode = 1; - } - } - } - return ret; -} - -void PAINT_OT_weight_gradient(wmOperatorType *ot) -{ - /* defined in DNA_space_types.h */ - static EnumPropertyItem gradient_types[] = { - {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""}, - {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""}, - {0, NULL, 0, NULL, NULL} - }; - - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Weight Gradient"; - ot->idname = "PAINT_OT_weight_gradient"; - ot->description = "Draw a line to apply a weight gradient to selected vertices"; - - /* api callbacks */ - ot->invoke = paint_weight_gradient_invoke; - ot->modal = paint_weight_gradient_modal; - ot->exec = paint_weight_gradient_exec; - ot->poll = weight_paint_poll; - ot->cancel = WM_gesture_straightline_cancel; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", ""); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); -} diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c new file mode 100644 index 00000000000..4acd4ddbd8d --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c @@ -0,0 +1,574 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/sculpt_paint/paint_vertex_color_ops.c + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_math_base.h" +#include "BLI_math_color.h" + +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_mesh.h" +#include "BKE_deform.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" + +#include "paint_intern.h" /* own include */ + + +static int vertex_weight_paint_mode_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + Mesh *me = BKE_mesh_from_object(ob); + return (ob && (ob->mode == OB_MODE_VERTEX_PAINT || ob->mode == OB_MODE_WEIGHT_PAINT)) && + (me && me->totpoly && me->dvert); +} + +/* -------------------------------------------------------------------- */ +/** \name Set Vertex Colors Operator + * \{ */ + +static bool vertex_color_set(Object *ob, uint paintcol) +{ + Mesh *me; + const MPoly *mp; + int i, j; + + if (((me = BKE_mesh_from_object(ob)) == NULL) || + (ED_mesh_color_ensure(me, NULL) == false)) + { + return false; + } + + const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + + mp = me->mpoly; + for (i = 0; i < me->totpoly; i++, mp++) { + MLoopCol *lcol = me->mloopcol + mp->loopstart; + + if (use_face_sel && !(mp->flag & ME_FACE_SEL)) + continue; + + j = 0; + do { + uint vidx = me->mloop[mp->loopstart + j].v; + if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) { + *(int *)lcol = paintcol; + } + lcol++; + j++; + } while (j < mp->totloop); + + } + + /* remove stale me->mcol, will be added later */ + BKE_mesh_tessface_clear(me); + + DAG_id_tag_update(&me->id, 0); + + return true; +} + +static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + Object *obact = CTX_data_active_object(C); + unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint); + + if (vertex_color_set(obact, paintcol)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Vertex Colors"; + ot->idname = "PAINT_OT_vertex_color_set"; + ot->description = "Fill the active vertex color layer with the current paint color"; + + /* api callbacks */ + ot->exec = vertex_color_set_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Color from Weight Operator + * \{ */ + +static bool vertex_paint_from_weight(Object *ob) +{ + Mesh *me; + const MPoly *mp; + int vgroup_active; + + if (((me = BKE_mesh_from_object(ob)) == NULL || + (ED_mesh_color_ensure(me, NULL)) == false)) + { + return false; + } + + /* TODO: respect selection. */ + mp = me->mpoly; + vgroup_active = ob->actdef - 1; + for (int i = 0; i < me->totpoly; i++, mp++) { + MLoopCol *lcol = &me->mloopcol[mp->loopstart]; + uint j = 0; + do { + uint vidx = me->mloop[mp->loopstart + j].v; + const float weight = defvert_find_weight(&me->dvert[vidx], vgroup_active); + const uchar grayscale = weight * 255; + lcol->r = grayscale; + lcol->b = grayscale; + lcol->g = grayscale; + lcol++; + j++; + } while (j < mp->totloop); + } + + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + + return true; +} + +static int vertex_paint_from_weight_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obact = CTX_data_active_object(C); + if (vertex_paint_from_weight(obact)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Color from Weight"; + ot->idname = "PAINT_OT_vertex_color_from_weight"; + ot->description = "Converts active weight into greyscale vertex colors"; + + /* api callback */ + ot->exec = vertex_paint_from_weight_exec; + ot->poll = vertex_weight_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* TODO: invert, alpha */ +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Smooth Vertex Colors Operator + * \{ */ + +static void vertex_color_smooth_looptag(Mesh *me, bool *mlooptag) +{ + const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const MPoly *mp; + int (*scol)[4]; + int i, j; + bool has_shared = false; + + /* if no mloopcol: do not do */ + /* if mtexpoly: only the involved faces, otherwise all */ + + if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) return; + + scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol"); + + for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) { + if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) { + const MLoop *ml = me->mloop + mp->loopstart; + MLoopCol *lcol = me->mloopcol + mp->loopstart; + for (j = 0; j < mp->totloop; j++, ml++, lcol++) { + scol[ml->v][0] += lcol->r; + scol[ml->v][1] += lcol->g; + scol[ml->v][2] += lcol->b; + scol[ml->v][3] += 1; + has_shared = 1; + } + } + } + + if (has_shared) { + for (i = 0; i < me->totvert; i++) { + if (scol[i][3] != 0) { + scol[i][0] = divide_round_i(scol[i][0], scol[i][3]); + scol[i][1] = divide_round_i(scol[i][1], scol[i][3]); + scol[i][2] = divide_round_i(scol[i][2], scol[i][3]); + } + } + + for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) { + if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) { + const MLoop *ml = me->mloop + mp->loopstart; + MLoopCol *lcol = me->mloopcol + mp->loopstart; + for (j = 0; j < mp->totloop; j++, ml++, lcol++) { + if (mlooptag[mp->loopstart + j]) { + lcol->r = scol[ml->v][0]; + lcol->g = scol[ml->v][1]; + lcol->b = scol[ml->v][2]; + } + } + } + } + } + + MEM_freeN(scol); +} + +static bool vertex_color_smooth(Object *ob) +{ + Mesh *me; + const MPoly *mp; + + int i, j; + + bool *mlooptag; + + if (((me = BKE_mesh_from_object(ob)) == NULL) || + (ED_mesh_color_ensure(me, NULL) == false)) + { + return false; + } + + const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + + mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag"); + + /* simply tag loops of selected faces */ + mp = me->mpoly; + for (i = 0; i < me->totpoly; i++, mp++) { + const MLoop *ml = me->mloop + mp->loopstart; + int ml_index = mp->loopstart; + + if (use_face_sel && !(mp->flag & ME_FACE_SEL)) + continue; + + for (j = 0; j < mp->totloop; j++, ml_index++, ml++) { + mlooptag[ml_index] = true; + } + } + + /* remove stale me->mcol, will be added later */ + BKE_mesh_tessface_clear(me); + + vertex_color_smooth_looptag(me, mlooptag); + + MEM_freeN(mlooptag); + + DAG_id_tag_update(&me->id, 0); + + return true; +} + + +static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obact = CTX_data_active_object(C); + if (vertex_color_smooth(obact)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_smooth(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Smooth Vertex Colors"; + ot->idname = "PAINT_OT_vertex_color_smooth"; + ot->description = "Smooth colors across vertices"; + + /* api callbacks */ + ot->exec = vertex_color_smooth_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Color Transformation Operators + * \{ */ + +struct VPaintTx_BrightContrastData { + /* pre-calculated */ + float gain; + float offset; +}; + +static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3]) +{ + const struct VPaintTx_BrightContrastData *data = user_data; + + for (int i = 0; i < 3; i++) { + r_col[i] = data->gain * col[i] + data->offset; + } +} + +static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + float gain, offset; + { + float brightness = RNA_float_get(op->ptr, "brightness"); + float contrast = RNA_float_get(op->ptr, "contrast"); + brightness /= 100.0f; + float delta = contrast / 200.0f; + gain = 1.0f - delta * 2.0f; + /* + * The algorithm is by Werner D. Streidt + * (http://visca.com/ffactory/archives/5-99/msg00021.html) + * Extracted of OpenCV demhist.c + */ + if (contrast > 0) { + gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON); + offset = gain * (brightness - delta); + } + else { + delta *= -1; + offset = gain * (brightness + delta); + } + } + + const struct VPaintTx_BrightContrastData user_data = { + .gain = gain, + .offset = offset, + }; + + if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Vertex Paint Bright/Contrast"; + ot->idname = "PAINT_OT_vertex_color_brightness_contrast"; + ot->description = "Adjust vertex color brightness/contrast"; + + /* api callbacks */ + ot->exec = vertex_color_brightness_contrast_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + const float min = -100, max = +100; + prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max); + prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max); + RNA_def_property_ui_range(prop, min, max, 1, 1); +} + +struct VPaintTx_HueSatData { + float hue; + float sat; + float val; +}; + +static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3]) +{ + const struct VPaintTx_HueSatData *data = user_data; + float hsv[3]; + rgb_to_hsv_v(col, hsv); + + hsv[0] += (data->hue - 0.5f); + if (hsv[0] > 1.0f) { + hsv[0] -= 1.0f; + } + else if (hsv[0] < 0.0f) { + hsv[0] += 1.0f; + } + hsv[1] *= data->sat; + hsv[2] *= data->val; + + hsv_to_rgb_v(hsv, r_col); +} + +static int vertex_color_hsv_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + const struct VPaintTx_HueSatData user_data = { + .hue = RNA_float_get(op->ptr, "h"), + .sat = RNA_float_get(op->ptr, "s"), + .val = RNA_float_get(op->ptr, "v"), + }; + + if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_hsv(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Hue Saturation Value"; + ot->idname = "PAINT_OT_vertex_color_hsv"; + ot->description = "Adjust vertex color HSV values"; + + /* api callbacks */ + ot->exec = vertex_color_hsv_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f); + RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f); + RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f); +} + +static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3]) +{ + for (int i = 0; i < 3; i++) { + r_col[i] = 1.0f - col[i]; + } +} + +static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obact = CTX_data_active_object(C); + + if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_invert(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Invert"; + ot->idname = "PAINT_OT_vertex_color_invert"; + ot->description = "Invert RGB values"; + + /* api callbacks */ + ot->exec = vertex_color_invert_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + +struct VPaintTx_LevelsData { + float gain; + float offset; +}; + +static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3]) +{ + const struct VPaintTx_LevelsData *data = user_data; + for (int i = 0; i < 3; i++) { + r_col[i] = data->gain * (col[i] + data->offset); + } +} + +static int vertex_color_levels_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + const struct VPaintTx_LevelsData user_data = { + .gain = RNA_float_get(op->ptr, "gain"), + .offset = RNA_float_get(op->ptr, "offset"), + }; + + if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_levels(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Levels"; + ot->idname = "PAINT_OT_vertex_color_levels"; + ot->description = "Adjust levels of vertex colors"; + + /* api callbacks */ + ot->exec = vertex_color_levels_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + RNA_def_float(ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f); + RNA_def_float(ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f); +} + +/** \} */
\ No newline at end of file diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c new file mode 100644 index 00000000000..a2ba8818c1f --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c @@ -0,0 +1,648 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/sculpt_paint/paint_vertex_color_utils.c + * \ingroup edsculpt + * + * Intended for use by `paint_vertex.c` & `paint_vertex_color_ops.c`. + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_math_base.h" +#include "BLI_math_color.h" + +#include "IMB_colormanagement.h" + +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_mesh.h" + +#include "ED_mesh.h" + +#include "paint_intern.h" /* own include */ + +#define EPS_SATURATION 0.0005f + +/** + * Apply callback to each vertex of the active vertex color layer. + */ +bool ED_vpaint_color_transform( + struct Object *ob, + VPaintTransform_Callback vpaint_tx_fn, + const void *user_data) +{ + Mesh *me; + const MPoly *mp; + + if (((me = BKE_mesh_from_object(ob)) == NULL) || + (ED_mesh_color_ensure(me, NULL) == false)) + { + return false; + } + + const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + mp = me->mpoly; + + for (int i = 0; i < me->totpoly; i++, mp++) { + MLoopCol *lcol = &me->mloopcol[mp->loopstart]; + + if (use_face_sel && !(mp->flag & ME_FACE_SEL)) { + continue; + } + + for (int j = 0; j < mp->totloop; j++, lcol++) { + float col[3]; + rgb_uchar_to_float(col, &lcol->r); + + vpaint_tx_fn(col, user_data, col); + + rgb_float_to_uchar(&lcol->r, col); + } + } + + /* remove stale me->mcol, will be added later */ + BKE_mesh_tessface_clear(me); + + DAG_id_tag_update(&me->id, 0); + + return true; +} + +/* -------------------------------------------------------------------- */ +/** \name Color Blending Modes + * \{ */ + +BLI_INLINE uint mcol_blend(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + + if (fac >= 255) { + return col2; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + /* Updated to use the rgb squared color model which blends nicer. */ + int r1 = cp1[0] * cp1[0]; + int g1 = cp1[1] * cp1[1]; + int b1 = cp1[2] * cp1[2]; + int a1 = cp1[3] * cp1[3]; + + int r2 = cp2[0] * cp2[0]; + int g2 = cp2[1] * cp2[1]; + int b2 = cp2[2] * cp2[2]; + int a2 = cp2[3] * cp2[3]; + + cp[0] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * r1 + fac * r2), 255))); + cp[1] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * g1 + fac * g2), 255))); + cp[2] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * b1 + fac * b2), 255))); + cp[3] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * a1 + fac * a2), 255))); + + return col; +} + +BLI_INLINE uint mcol_add(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + temp = cp1[0] + divide_round_i((fac * cp2[0]), 255); + cp[0] = (temp > 254) ? 255 : temp; + temp = cp1[1] + divide_round_i((fac * cp2[1]), 255); + cp[1] = (temp > 254) ? 255 : temp; + temp = cp1[2] + divide_round_i((fac * cp2[2]), 255); + cp[2] = (temp > 254) ? 255 : temp; + temp = cp1[3] + divide_round_i((fac * cp2[3]), 255); + cp[3] = (temp > 254) ? 255 : temp; + + return col; +} + +BLI_INLINE uint mcol_sub(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + temp = cp1[0] - divide_round_i((fac * cp2[0]), 255); + cp[0] = (temp < 0) ? 0 : temp; + temp = cp1[1] - divide_round_i((fac * cp2[1]), 255); + cp[1] = (temp < 0) ? 0 : temp; + temp = cp1[2] - divide_round_i((fac * cp2[2]), 255); + cp[2] = (temp < 0) ? 0 : temp; + temp = cp1[3] - divide_round_i((fac * cp2[3]), 255); + cp[3] = (temp < 0) ? 0 : temp; + + return col; +} + +BLI_INLINE uint mcol_mul(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + /* first mul, then blend the fac */ + cp[0] = divide_round_i(mfac * cp1[0] * 255 + fac * cp2[0] * cp1[0], 255 * 255); + cp[1] = divide_round_i(mfac * cp1[1] * 255 + fac * cp2[1] * cp1[1], 255 * 255); + cp[2] = divide_round_i(mfac * cp1[2] * 255 + fac * cp2[2] * cp1[2], 255 * 255); + cp[3] = divide_round_i(mfac * cp1[3] * 255 + fac * cp2[3] * cp1[3], 255 * 255); + + return col; +} + +BLI_INLINE uint mcol_lighten(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + else if (fac >= 255) { + return col2; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + /* See if are lighter, if so mix, else don't do anything. + * if the paint col is darker then the original, then ignore */ + if (IMB_colormanagement_get_luminance_byte(cp1) > IMB_colormanagement_get_luminance_byte(cp2)) { + return col1; + } + + cp[0] = divide_round_i(mfac * cp1[0] + fac * cp2[0], 255); + cp[1] = divide_round_i(mfac * cp1[1] + fac * cp2[1], 255); + cp[2] = divide_round_i(mfac * cp1[2] + fac * cp2[2], 255); + cp[3] = divide_round_i(mfac * cp1[3] + fac * cp2[3], 255); + + return col; +} + +BLI_INLINE uint mcol_darken(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + else if (fac >= 255) { + return col2; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + /* See if were darker, if so mix, else don't do anything. + * if the paint col is brighter then the original, then ignore */ + if (IMB_colormanagement_get_luminance_byte(cp1) < IMB_colormanagement_get_luminance_byte(cp2)) { + return col1; + } + + cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255); + cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255); + cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255); + cp[3] = divide_round_i((mfac * cp1[3] + fac * cp2[3]), 255); + return col; +} + +BLI_INLINE uint mcol_colordodge(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac,temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + temp = (cp2[0] == 255) ? 255 : min_ii((cp1[0] * 225) / (255 - cp2[0]), 255); + cp[0] = (mfac * cp1[0] + temp * fac) / 255; + temp = (cp2[1] == 255) ? 255 : min_ii((cp1[1] * 225) / (255 - cp2[1]), 255); + cp[1] = (mfac * cp1[1] + temp * fac) / 255; + temp = (cp2[2] == 255) ? 255 : min_ii((cp1[2] * 225 )/ (255 - cp2[2]), 255); + cp[2] = (mfac * cp1[2] + temp * fac) / 255; + temp = (cp2[3] == 255) ? 255 : min_ii((cp1[3] * 225) / (255 - cp2[3]), 255); + cp[3] = (mfac * cp1[3] + temp * fac) / 255; + return col; +} + +BLI_INLINE uint mcol_difference(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac, temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + temp = abs(cp1[0] - cp2[0]); + cp[0] = (mfac * cp1[0] + temp * fac) / 255; + temp = abs(cp1[1] - cp2[1]); + cp[1] = (mfac * cp1[1] + temp * fac) / 255; + temp = abs(cp1[2] - cp2[2]); + cp[2] = (mfac * cp1[2] + temp * fac) / 255; + temp = abs(cp1[3] - cp2[3]); + cp[3] = (mfac * cp1[3] + temp * fac) / 255; + return col; +} + +BLI_INLINE uint mcol_screen(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac, temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + temp = max_ii(255 - (((255 - cp1[0]) * (255 - cp2[0])) / 255), 0); + cp[0] = (mfac * cp1[0] + temp * fac) / 255; + temp = max_ii(255 - (((255 - cp1[1]) * (255 - cp2[1])) / 255), 0); + cp[1] = (mfac * cp1[1] + temp * fac) / 255; + temp = max_ii(255 - (((255 - cp1[2]) * (255 - cp2[2])) / 255), 0); + cp[2] = (mfac * cp1[2] + temp * fac) / 255; + temp = max_ii(255 - (((255 - cp1[3]) * (255 - cp2[3])) / 255), 0); + cp[3] = (mfac * cp1[3] + temp * fac) / 255; + return col; +} + +BLI_INLINE uint mcol_hardlight(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac, temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + int i = 0; + + for (i = 0; i < 4; i++) { + if (cp2[i] > 127) { + temp = 255 - ((255 - 2 * (cp2[i] - 127)) * (255 - cp1[i]) / 255); + } + else { + temp = (2 * cp2[i] * cp1[i]) >> 8; + } + cp[i] = min_ii((mfac * cp1[i] + temp * fac) / 255, 255); + } + return col; +} + +BLI_INLINE uint mcol_overlay(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac, temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + int i = 0; + + for (i = 0; i < 4; i++) { + if (cp1[i] > 127) { + temp = 255 - ((255 - 2 * (cp1[i] - 127)) * (255 - cp2[i]) / 255); + } + else { + temp = (2 * cp2[i] * cp1[i]) >> 8; + } + cp[i] = min_ii((mfac * cp1[i] + temp * fac) / 255, 255); + } + return col; +} + +BLI_INLINE uint mcol_softlight(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac, temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + int i = 0; + + for (i = 0; i < 4; i++) { + if (cp1[i] < 127) { + temp = ((2 * ((cp2[i] / 2) + 64)) * cp1[i]) / 255; + } + else { + temp = 255 - (2 * (255 - ((cp2[i] / 2) + 64)) * (255 - cp1[i]) / 255); + } + cp[i] = (temp * fac + cp1[i] * mfac) / 255; + } + return col; +} + +BLI_INLINE uint mcol_exclusion(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac, temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + int i = 0; + + for (i = 0; i < 4; i++) { + temp = 127 - ((2 * (cp1[i] - 127) * (cp2[i] - 127)) / 255); + cp[i] = (temp * fac + cp1[i] * mfac) / 255; + } + return col; +} + +BLI_INLINE uint mcol_luminosity(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(cp1[0] / 255.0f, cp1[1] / 255.0f, cp1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(cp2[0] / 255.0f, cp2[1] / 255.0f, cp2[2] / 255.0f, &h2, &s2, &v2); + + v1 = v2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + cp[0] = ((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255; + cp[1] = ((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255; + cp[2] = ((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255; + cp[3] = ((int)(cp2[3]) * fac + mfac * cp1[3]) / 255; + return col; +} + +BLI_INLINE uint mcol_saturation(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(cp1[0] / 255.0f, cp1[1] / 255.0f, cp1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(cp2[0] / 255.0f, cp2[1] / 255.0f, cp2[2] / 255.0f, &h2, &s2, &v2); + + if (s1 > EPS_SATURATION) { + s1 = s2; + } + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + cp[0] = ((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255; + cp[1] = ((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255; + cp[2] = ((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255; + return col; +} + +BLI_INLINE uint mcol_hue(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(cp1[0] / 255.0f, cp1[1] / 255.0f, cp1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(cp2[0] / 255.0f, cp2[1] / 255.0f, cp2[2] / 255.0f, &h2, &s2, &v2); + + h1 = h2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + cp[0] = ((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255; + cp[1] = ((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255; + cp[2] = ((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255; + cp[3] = ((int)(cp2[3]) * fac + mfac * cp1[3]) / 255; + return col; +} + +BLI_INLINE uint mcol_alpha_add(uint col1, int fac) +{ + uchar *cp1, *cp; + int temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + cp1 = (uchar *)&col1; + cp = (uchar *)&col; + + temp = cp1[3] + fac; + cp[3] = (temp > 254) ? 255 : temp; + + return col; +} + +BLI_INLINE uint mcol_alpha_sub(uint col1, int fac) +{ + uchar *cp1, *cp; + int temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + cp1 = (uchar *)&col1; + cp = (uchar *)&col; + + temp = cp1[3] - fac; + cp[3] = temp < 0 ? 0 : temp; + + return col; +} + +/* wpaint has 'ED_wpaint_blend_tool' */ +uint ED_vpaint_blend_tool( + const int tool, const uint col, + const uint paintcol, const int alpha_i) +{ + switch (tool) { + case PAINT_BLEND_MIX: + case PAINT_BLEND_BLUR: return mcol_blend(col, paintcol, alpha_i); + case PAINT_BLEND_AVERAGE: return mcol_blend(col, paintcol, alpha_i); + case PAINT_BLEND_SMEAR: return mcol_blend(col, paintcol, alpha_i); + case PAINT_BLEND_ADD: return mcol_add(col, paintcol, alpha_i); + case PAINT_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i); + case PAINT_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i); + case PAINT_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i); + case PAINT_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i); + case PAINT_BLEND_COLORDODGE: return mcol_colordodge(col, paintcol, alpha_i); + case PAINT_BLEND_DIFFERENCE: return mcol_difference(col, paintcol, alpha_i); + case PAINT_BLEND_SCREEN: return mcol_screen(col, paintcol, alpha_i); + case PAINT_BLEND_HARDLIGHT: return mcol_hardlight(col, paintcol, alpha_i); + case PAINT_BLEND_OVERLAY: return mcol_overlay(col, paintcol, alpha_i); + case PAINT_BLEND_SOFTLIGHT: return mcol_softlight(col, paintcol, alpha_i); + case PAINT_BLEND_EXCLUSION: return mcol_exclusion(col, paintcol, alpha_i); + case PAINT_BLEND_LUMINOCITY: return mcol_luminosity(col, paintcol, alpha_i); + case PAINT_BLEND_SATURATION: return mcol_saturation(col, paintcol, alpha_i); + case PAINT_BLEND_HUE: return mcol_hue(col, paintcol, alpha_i); + /* non-color */ + case PAINT_BLEND_ALPHA_SUB: return mcol_alpha_sub(col, alpha_i); + case PAINT_BLEND_ALPHA_ADD: return mcol_alpha_add(col, alpha_i); + default: + BLI_assert(0); + return 0; + } +} + +/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c new file mode 100644 index 00000000000..4e807ccb4ef --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -0,0 +1,861 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/sculpt_paint/paint_vertex_weight_ops.c + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_array_utils.h" +#include "BLI_bitmap.h" +#include "BLI_task.h" +#include "BLI_string_utils.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" +#include "IMB_colormanagement.h" + +//#include "DNA_armature_types.h" +#include "DNA_mesh_types.h" +#include "DNA_particle_types.h" +#include "DNA_brush_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_brush.h" +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_deform.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_modifier.h" +#include "BKE_object_deform.h" +#include "BKE_paint.h" +#include "BKE_report.h" +#include "BKE_colortools.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_armature.h" +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "paint_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name Store Previous Weights + * + * Use to avoid feedback loop w/ mirrored edits. + * \{ */ + +struct WPaintPrev { + /* previous vertex weights */ + struct MDeformVert *wpaint_prev; + /* allocation size of prev buffers */ + int tot; +}; + + +static void wpaint_prev_init(struct WPaintPrev *wpp) +{ + wpp->wpaint_prev = NULL; + wpp->tot = 0; +} + +static void wpaint_prev_create(struct WPaintPrev *wpp, MDeformVert *dverts, int dcount) +{ + wpaint_prev_init(wpp); + + if (dverts && dcount) { + wpp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev"); + wpp->tot = dcount; + BKE_defvert_array_copy(wpp->wpaint_prev, dverts, dcount); + } +} + +static void wpaint_prev_destroy(struct WPaintPrev *wpp) +{ + if (wpp->wpaint_prev) { + BKE_defvert_array_free(wpp->wpaint_prev, wpp->tot); + } + wpp->wpaint_prev = NULL; + wpp->tot = 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weight from Bones Operator + * \{ */ + +static int weight_from_bones_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + + return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob)); +} + +static int weight_from_bones_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Object *armob = modifiers_isDeformedByArmature(ob); + Mesh *me = ob->data; + int type = RNA_enum_get(op->ptr, "type"); + + create_vgroups_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X)); + + DAG_id_tag_update(&me->id, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + + return OPERATOR_FINISHED; +} + +void PAINT_OT_weight_from_bones(wmOperatorType *ot) +{ + static EnumPropertyItem type_items[] = { + {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"}, + {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"}, + {0, NULL, 0, NULL, NULL}}; + + /* identifiers */ + ot->name = "Weight from Bones"; + ot->idname = "PAINT_OT_weight_from_bones"; + ot->description = "Set the weights of the groups matching the attached armature's selected bones, " + "using the distance between the vertices and the bones"; + + /* api callbacks */ + ot->exec = weight_from_bones_exec; + ot->invoke = WM_menu_invoke; + ot->poll = weight_from_bones_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights"); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sample Weight Operator + * \{ */ + +/* sets wp->weight to the closest weight value to vertex */ +/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */ +static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewContext vc; + Mesh *me; + bool changed = false; + + view3d_set_viewcontext(C, &vc); + me = BKE_mesh_from_object(vc.obact); + + if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) { + const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + int v_idx_best = -1; + uint index; + + view3d_operator_needs_opengl(C); + ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d); + + if (use_vert_sel) { + if (ED_mesh_pick_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, true)) { + v_idx_best = index; + } + } + else { + if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + v_idx_best = index; + } + else if (ED_mesh_pick_face(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + /* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */ + BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations"); + } + } + + if (v_idx_best != -1) { /* should always be valid */ + ToolSettings *ts = vc.scene->toolsettings; + Brush *brush = BKE_paint_brush(&ts->wpaint->paint); + const int vgroup_active = vc.obact->actdef - 1; + float vgroup_weight = defvert_find_weight(&me->dvert[v_idx_best], vgroup_active); + + /* use combined weight in multipaint mode, since that's what is displayed to the user in the colors */ + if (ts->multipaint) { + int defbase_tot_sel; + const int defbase_tot = BLI_listbase_count(&vc.obact->defbase); + bool *defbase_sel = BKE_object_defgroup_selected_get(vc.obact, defbase_tot, &defbase_tot_sel); + + if (defbase_tot_sel > 1) { + if (me->editflag & ME_EDIT_MIRROR_X) { + BKE_object_defgroup_mirror_selection( + vc.obact, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel); + } + + vgroup_weight = BKE_defvert_multipaint_collective_weight( + &me->dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, ts->auto_normalize); + + /* if autonormalize is enabled, but weights are not normalized, the value can exceed 1 */ + CLAMP(vgroup_weight, 0.0f, 1.0f); + } + + MEM_freeN(defbase_sel); + } + + BKE_brush_weight_set(vc.scene, brush, vgroup_weight); + changed = true; + } + } + + if (changed) { + /* not really correct since the brush didnt change, but redraws the toolbar */ + WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); /* ts->wpaint->paint.brush */ + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_weight_sample(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Weight Paint Sample Weight"; + ot->idname = "PAINT_OT_weight_sample"; + ot->description = "Use the mouse to sample a weight in the 3D view"; + + /* api callbacks */ + ot->invoke = weight_sample_invoke; + ot->poll = weight_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weight Paint Sample Group Operator + * \{ */ + +/* samples cursor location, and gives menu with vertex groups to activate */ +static bool weight_paint_sample_enum_itemf__helper(const MDeformVert *dvert, const int defbase_tot, int *groups) +{ + /* this func fills in used vgroup's */ + bool found = false; + int i = dvert->totweight; + MDeformWeight *dw; + for (dw = dvert->dw; i > 0; dw++, i--) { + if (dw->def_nr < defbase_tot) { + groups[dw->def_nr] = true; + found = true; + } + } + return found; +} +static EnumPropertyItem *weight_paint_sample_enum_itemf( + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + if (C) { + wmWindow *win = CTX_wm_window(C); + if (win && win->eventstate) { + ViewContext vc; + Mesh *me; + + view3d_set_viewcontext(C, &vc); + me = BKE_mesh_from_object(vc.obact); + + if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) { + const int defbase_tot = BLI_listbase_count(&vc.obact->defbase); + const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups"); + bool found = false; + uint index; + + const int mval[2] = { + win->eventstate->x - vc.ar->winrct.xmin, + win->eventstate->y - vc.ar->winrct.ymin, + }; + + view3d_operator_needs_opengl(C); + ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d); + + if (use_vert_sel) { + if (ED_mesh_pick_vert(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, true)) { + MDeformVert *dvert = &me->dvert[index]; + found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups); + } + } + else { + if (ED_mesh_pick_face(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + const MPoly *mp = &me->mpoly[index]; + uint fidx = mp->totloop - 1; + + do { + MDeformVert *dvert = &me->dvert[me->mloop[mp->loopstart + fidx].v]; + found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups); + } while (fidx--); + } + } + + if (found == false) { + MEM_freeN(groups); + } + else { + EnumPropertyItem *item = NULL, item_tmp = {0}; + int totitem = 0; + int i = 0; + bDeformGroup *dg; + for (dg = vc.obact->defbase.first; dg && i < defbase_tot; i++, dg = dg->next) { + if (groups[i]) { + item_tmp.identifier = item_tmp.name = dg->name; + item_tmp.value = i; + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + MEM_freeN(groups); + return item; + } + } + } + } + + return DummyRNA_NULL_items; +} + +static int weight_sample_group_exec(bContext *C, wmOperator *op) +{ + int type = RNA_enum_get(op->ptr, "group"); + ViewContext vc; + view3d_set_viewcontext(C, &vc); + + BLI_assert(type + 1 >= 0); + vc.obact->actdef = type + 1; + + DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, vc.obact); + return OPERATOR_FINISHED; +} + +/* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active rather than its own operator */ +void PAINT_OT_weight_sample_group(wmOperatorType *ot) +{ + PropertyRNA *prop = NULL; + + /* identifiers */ + ot->name = "Weight Paint Sample Group"; + ot->idname = "PAINT_OT_weight_sample_group"; + ot->description = "Select one of the vertex groups available under current mouse position"; + + /* api callbacks */ + ot->exec = weight_sample_group_exec; + ot->invoke = WM_menu_invoke; + ot->poll = weight_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* keyingset to use (dynamic enum) */ + prop = RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); + RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weight Set Operator + * \{ */ + +/* fills in the selected faces with the current weight and vertex group */ +static bool weight_paint_set(Object *ob, float paintweight) +{ + Mesh *me = ob->data; + const MPoly *mp; + MDeformWeight *dw, *dw_prev; + int vgroup_active, vgroup_mirror = -1; + uint index; + const bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + + /* mutually exclusive, could be made into a */ + const short paint_selmode = ME_EDIT_PAINT_SEL_MODE(me); + + if (me->totpoly == 0 || me->dvert == NULL || !me->mpoly) { + return false; + } + + vgroup_active = ob->actdef - 1; + + /* if mirror painting, find the other group */ + if (me->editflag & ME_EDIT_MIRROR_X) { + vgroup_mirror = ED_wpaint_mirror_vgroup_ensure(ob, vgroup_active); + } + + struct WPaintPrev wpp; + wpaint_prev_create(&wpp, me->dvert, me->totvert); + + for (index = 0, mp = me->mpoly; index < me->totpoly; index++, mp++) { + uint fidx = mp->totloop - 1; + + if ((paint_selmode == SCE_SELECT_FACE) && !(mp->flag & ME_FACE_SEL)) { + continue; + } + + do { + uint vidx = me->mloop[mp->loopstart + fidx].v; + + if (!me->dvert[vidx].flag) { + if ((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) { + continue; + } + + dw = defvert_verify_index(&me->dvert[vidx], vgroup_active); + if (dw) { + dw_prev = defvert_verify_index(wpp.wpaint_prev + vidx, vgroup_active); + dw_prev->weight = dw->weight; /* set the undo weight */ + dw->weight = paintweight; + + if (me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */ + int j = mesh_get_x_mirror_vert(ob, NULL, vidx, topology); + if (j >= 0) { + /* copy, not paint again */ + if (vgroup_mirror != -1) { + dw = defvert_verify_index(me->dvert + j, vgroup_mirror); + dw_prev = defvert_verify_index(wpp.wpaint_prev + j, vgroup_mirror); + } + else { + dw = defvert_verify_index(me->dvert + j, vgroup_active); + dw_prev = defvert_verify_index(wpp.wpaint_prev + j, vgroup_active); + } + dw_prev->weight = dw->weight; /* set the undo weight */ + dw->weight = paintweight; + } + } + } + me->dvert[vidx].flag = 1; + } + + } while (fidx--); + } + + { + MDeformVert *dv = me->dvert; + for (index = me->totvert; index != 0; index--, dv++) { + dv->flag = 0; + } + } + + wpaint_prev_destroy(&wpp); + + DAG_id_tag_update(&me->id, 0); + + return true; +} + + +static int weight_paint_set_exec(bContext *C, wmOperator *op) +{ + struct Scene *scene = CTX_data_scene(C); + Object *obact = CTX_data_active_object(C); + ToolSettings *ts = CTX_data_tool_settings(C); + Brush *brush = BKE_paint_brush(&ts->wpaint->paint); + float vgroup_weight = BKE_brush_weight_get(scene, brush); + + if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, NULL) == false) { + return OPERATOR_CANCELLED; + } + + if (weight_paint_set(obact, vgroup_weight)) { + ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */ + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_weight_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Weight"; + ot->idname = "PAINT_OT_weight_set"; + ot->description = "Fill the active vertex group with the current paint weight"; + + /* api callbacks */ + ot->exec = weight_paint_set_exec; + ot->poll = mask_paint_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Interactive Weight Gradient Operator + * \{ */ + +/* *** VGroups Gradient *** */ +typedef struct DMGradient_vertStore { + float sco[2]; + float weight_orig; + enum { + VGRAD_STORE_NOP = 0, + VGRAD_STORE_DW_EXIST = (1 << 0) + } flag; +} DMGradient_vertStore; + +typedef struct DMGradient_vertStoreBase { + struct WPaintPrev wpp; + DMGradient_vertStore elem[0]; +} DMGradient_vertStoreBase; + +typedef struct DMGradient_userData { + struct ARegion *ar; + Scene *scene; + Mesh *me; + Brush *brush; + const float *sco_start; /* [2] */ + const float *sco_end; /* [2] */ + float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */ + int def_nr; + bool is_init; + DMGradient_vertStoreBase *vert_cache; + /* only for init */ + BLI_bitmap *vert_visit; + + /* options */ + short use_select; + short type; + float weightpaint; +} DMGradient_userData; + +static void gradientVert_update(DMGradient_userData *grad_data, int index) +{ + Mesh *me = grad_data->me; + DMGradient_vertStore *vs = &grad_data->vert_cache->elem[index]; + float alpha; + + if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) { + alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end); + } + else { + BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL); + alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div; + } + /* no need to clamp 'alpha' yet */ + + /* adjust weight */ + alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f); + + if (alpha != 0.0f) { + MDeformVert *dv = &me->dvert[index]; + MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr); + // dw->weight = alpha; // testing + int tool = grad_data->brush->vertexpaint_tool; + float testw; + + /* init if we just added */ + testw = ED_wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha); + CLAMP(testw, 0.0f, 1.0f); + dw->weight = testw; + } + else { + MDeformVert *dv = &me->dvert[index]; + if (vs->flag & VGRAD_STORE_DW_EXIST) { + /* normally we NULL check, but in this case we know it exists */ + MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); + dw->weight = vs->weight_orig; + } + else { + /* wasn't originally existing, remove */ + MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); + if (dw) { + defvert_remove_group(dv, dw); + } + } + } +} + +static void gradientVertUpdate__mapFunc( + void *userData, int index, const float UNUSED(co[3]), + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + DMGradient_userData *grad_data = userData; + Mesh *me = grad_data->me; + if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) { + DMGradient_vertStore *vs = &grad_data->vert_cache->elem[index]; + if (vs->sco[0] != FLT_MAX) { + gradientVert_update(grad_data, index); + } + } +} + +static void gradientVertInit__mapFunc( + void *userData, int index, const float co[3], + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + DMGradient_userData *grad_data = userData; + Mesh *me = grad_data->me; + + if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) { + /* run first pass only, + * the screen coords of the verts need to be cached because + * updating the mesh may move them about (entering feedback loop) */ + + if (BLI_BITMAP_TEST(grad_data->vert_visit, index) == 0) { + DMGradient_vertStore *vs = &grad_data->vert_cache->elem[index]; + if (ED_view3d_project_float_object(grad_data->ar, + co, vs->sco, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { + /* ok */ + MDeformVert *dv = &me->dvert[index]; + const MDeformWeight *dw; + dw = defvert_find_index(dv, grad_data->def_nr); + if (dw) { + vs->weight_orig = dw->weight; + vs->flag = VGRAD_STORE_DW_EXIST; + } + else { + vs->weight_orig = 0.0f; + vs->flag = VGRAD_STORE_NOP; + } + + BLI_BITMAP_ENABLE(grad_data->vert_visit, index); + + gradientVert_update(grad_data, index); + } + else { + /* no go */ + copy_v2_fl(vs->sco, FLT_MAX); + } + } + } +} + +static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + int ret = WM_gesture_straightline_modal(C, op, event); + wmGesture *gesture = op->customdata; + DMGradient_vertStoreBase *vert_cache = gesture->userdata; + bool do_gesture_free = false; + + if (ret & OPERATOR_RUNNING_MODAL) { + if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */ + /* generally crap! redo! */ + do_gesture_free = true; + ret &= ~OPERATOR_RUNNING_MODAL; + ret |= OPERATOR_FINISHED; + } + } + + if (ret & OPERATOR_CANCELLED) { + Object *ob = CTX_data_active_object(C); + Mesh *me = ob->data; + if (vert_cache->wpp.wpaint_prev) { + BKE_defvert_array_free_elems(me->dvert, me->totvert); + BKE_defvert_array_copy(me->dvert, vert_cache->wpp.wpaint_prev, me->totvert); + wpaint_prev_destroy(&vert_cache->wpp); + } + + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + } + else if (ret & OPERATOR_FINISHED) { + wpaint_prev_destroy(&vert_cache->wpp); + } + + if (do_gesture_free) { + WM_gesture_straightline_cancel(C, op); + } + + return ret; +} + +static int paint_weight_gradient_exec(bContext *C, wmOperator *op) +{ + wmGesture *gesture = op->customdata; + DMGradient_vertStoreBase *vert_cache; + struct ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Mesh *me = ob->data; + int x_start = RNA_int_get(op->ptr, "xstart"); + int y_start = RNA_int_get(op->ptr, "ystart"); + int x_end = RNA_int_get(op->ptr, "xend"); + int y_end = RNA_int_get(op->ptr, "yend"); + float sco_start[2] = {x_start, y_start}; + float sco_end[2] = {x_end, y_end}; + const bool is_interactive = (gesture != NULL); + DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); + + DMGradient_userData data = {NULL}; + + if (is_interactive) { + if (gesture->userdata == NULL) { + gesture->userdata = MEM_mallocN( + sizeof(DMGradient_vertStoreBase) + + (sizeof(DMGradient_vertStore) * me->totvert), + __func__); + data.is_init = true; + + wpaint_prev_create(&((DMGradient_vertStoreBase *)gesture->userdata)->wpp, me->dvert, me->totvert); + + /* on init only, convert face -> vert sel */ + if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { + BKE_mesh_flush_select_from_polys(me); + } + } + + vert_cache = gesture->userdata; + } + else { + if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) { + return OPERATOR_CANCELLED; + } + + data.is_init = true; + vert_cache = MEM_mallocN( + sizeof(DMGradient_vertStoreBase) + + (sizeof(DMGradient_vertStore) * me->totvert), + __func__); + } + + data.ar = ar; + data.scene = scene; + data.me = ob->data; + data.sco_start = sco_start; + data.sco_end = sco_end; + data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end); + data.def_nr = ob->actdef - 1; + data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)); + data.vert_cache = vert_cache; + data.vert_visit = NULL; + data.type = RNA_enum_get(op->ptr, "type"); + + { + ToolSettings *ts = CTX_data_tool_settings(C); + VPaint *wp = ts->wpaint; + struct Brush *brush = BKE_paint_brush(&wp->paint); + + curvemapping_initialize(brush->curve); + + data.brush = brush; + data.weightpaint = BKE_brush_weight_get(scene, brush); + } + + ED_view3d_init_mats_rv3d(ob, ar->regiondata); + + if (data.is_init) { + data.vert_visit = BLI_BITMAP_NEW(me->totvert, __func__); + + dm->foreachMappedVert(dm, gradientVertInit__mapFunc, &data, DM_FOREACH_NOP); + + MEM_freeN(data.vert_visit); + data.vert_visit = NULL; + } + else { + dm->foreachMappedVert(dm, gradientVertUpdate__mapFunc, &data, DM_FOREACH_NOP); + } + + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + if (is_interactive == false) { + MEM_freeN(vert_cache); + } + + return OPERATOR_FINISHED; +} + +static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int ret; + + if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) { + return OPERATOR_CANCELLED; + } + + ret = WM_gesture_straightline_invoke(C, op, event); + if (ret & OPERATOR_RUNNING_MODAL) { + struct ARegion *ar = CTX_wm_region(C); + if (ar->regiontype == RGN_TYPE_WINDOW) { + /* TODO, hardcoded, extend WM_gesture_straightline_ */ + if (event->type == LEFTMOUSE && event->val == KM_PRESS) { + wmGesture *gesture = op->customdata; + gesture->mode = 1; + } + } + } + return ret; +} + +void PAINT_OT_weight_gradient(wmOperatorType *ot) +{ + /* defined in DNA_space_types.h */ + static EnumPropertyItem gradient_types[] = { + {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""}, + {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""}, + {0, NULL, 0, NULL, NULL} + }; + + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Weight Gradient"; + ot->idname = "PAINT_OT_weight_gradient"; + ot->description = "Draw a line to apply a weight gradient to selected vertices"; + + /* api callbacks */ + ot->invoke = paint_weight_gradient_invoke; + ot->modal = paint_weight_gradient_modal; + ot->exec = paint_weight_gradient_exec; + ot->poll = weight_paint_poll; + ot->cancel = WM_gesture_straightline_cancel; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); +} + +/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c new file mode 100644 index 00000000000..c05b0ba89cf --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c @@ -0,0 +1,212 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/sculpt_paint/paint_vertex_weight_utils.c + * \ingroup edsculpt + * + * Intended for use by `paint_vertex.c` & `paint_vertex_weight_ops.c`. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_string_utils.h" + +#include "DNA_armature_types.h" +#include "DNA_mesh_types.h" +#include "DNA_scene_types.h" +#include "DNA_brush_types.h" +#include "DNA_object_types.h" + +#include "BKE_action.h" +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_object_deform.h" +#include "BKE_report.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "paint_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name Weight Paint Sanity Checks + * \{ */ + +/* ensure we have data on wpaint start, add if needed */ +bool ED_wpaint_ensure_data( + bContext *C, struct ReportList *reports, + enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Mesh *me = BKE_mesh_from_object(ob); + + if (vgroup_index) { + vgroup_index->active = -1; + vgroup_index->mirror = -1; + } + + if (scene->obedit) { + return false; + } + + if (me == NULL || me->totpoly == 0) { + return false; + } + + /* if nothing was added yet, we make dverts and a vertex deform group */ + if (!me->dvert) { + BKE_object_defgroup_data_create(&me->id); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + } + + /* this happens on a Bone select, when no vgroup existed yet */ + if (ob->actdef <= 0) { + Object *modob; + if ((modob = modifiers_isDeformedByArmature(ob))) { + Bone *actbone = ((bArmature *)modob->data)->act_bone; + if (actbone) { + bPoseChannel *pchan = BKE_pose_channel_find_name(modob->pose, actbone->name); + + if (pchan) { + bDeformGroup *dg = defgroup_find_name(ob, pchan->name); + if (dg == NULL) { + dg = BKE_object_defgroup_add_name(ob, pchan->name); /* sets actdef */ + } + else { + int actdef = 1 + BLI_findindex(&ob->defbase, dg); + BLI_assert(actdef >= 0); + ob->actdef = actdef; + } + } + } + } + } + if (BLI_listbase_is_empty(&ob->defbase)) { + BKE_object_defgroup_add(ob); + } + + /* ensure we don't try paint onto an invalid group */ + if (ob->actdef <= 0) { + BKE_report(reports, RPT_WARNING, "No active vertex group for painting, aborting"); + return false; + } + + if (vgroup_index) { + vgroup_index->active = ob->actdef - 1; + } + + if (flag & WPAINT_ENSURE_MIRROR) { + if (me->editflag & ME_EDIT_MIRROR_X) { + int mirror = ED_wpaint_mirror_vgroup_ensure(ob, ob->actdef - 1); + if (vgroup_index) { + vgroup_index->mirror = mirror; + } + } + } + + return true; +} +/** \} */ + +/* mirror_vgroup is set to -1 when invalid */ +int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) +{ + bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active); + + if (defgroup) { + int mirrdef; + char name_flip[MAXBONENAME]; + + BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip)); + mirrdef = defgroup_name_index(ob, name_flip); + if (mirrdef == -1) { + if (BKE_defgroup_new(ob, name_flip)) { + mirrdef = BLI_listbase_count(&ob->defbase) - 1; + } + } + + /* curdef should never be NULL unless this is + * a lamp and BKE_object_defgroup_add_name fails */ + return mirrdef; + } + + return -1; +} + +/* -------------------------------------------------------------------- */ +/** \name Weight Blending Modes + * \{ */ + +BLI_INLINE float wval_blend(const float weight, const float paintval, const float alpha) +{ + const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */ + return (paintval * talpha) + (weight * (1.0f - talpha)); +} +BLI_INLINE float wval_add(const float weight, const float paintval, const float alpha) +{ + return weight + (paintval * alpha); +} +BLI_INLINE float wval_sub(const float weight, const float paintval, const float alpha) +{ + return weight - (paintval * alpha); +} +BLI_INLINE float wval_mul(const float weight, const float paintval, const float alpha) +{ /* first mul, then blend the fac */ + return ((1.0f - alpha) + (alpha * paintval)) * weight; +} +BLI_INLINE float wval_lighten(const float weight, const float paintval, const float alpha) +{ + return (weight < paintval) ? wval_blend(weight, paintval, alpha) : weight; +} +BLI_INLINE float wval_darken(const float weight, const float paintval, const float alpha) +{ + return (weight > paintval) ? wval_blend(weight, paintval, alpha) : weight; +} + +/* vpaint has 'vpaint_blend_tool' */ +/* result is not clamped from [0-1] */ +float ED_wpaint_blend_tool( + const int tool, + /* dw->weight */ + const float weight, + const float paintval, const float alpha) +{ + switch (tool) { + case PAINT_BLEND_MIX: + case PAINT_BLEND_AVERAGE: + case PAINT_BLEND_SMEAR: + case PAINT_BLEND_BLUR: return wval_blend(weight, paintval, alpha); + case PAINT_BLEND_ADD: return wval_add(weight, paintval, alpha); + case PAINT_BLEND_SUB: return wval_sub(weight, paintval, alpha); + case PAINT_BLEND_MUL: return wval_mul(weight, paintval, alpha); + case PAINT_BLEND_LIGHTEN: return wval_lighten(weight, paintval, alpha); + case PAINT_BLEND_DARKEN: return wval_darken(weight, paintval, alpha); + default: + BLI_assert(0); + return 0.0f; + } +} + +/** \} */
\ No newline at end of file diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 44cc2720a32..bef682868c3 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -39,7 +39,6 @@ #include "BLI_blenlib.h" #include "BLI_dial.h" #include "BLI_task.h" -#include "BLI_threads.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -165,111 +164,12 @@ static bool sculpt_brush_needs_rake_rotation(const Brush *brush) return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f); } -/* Factor of brush to have rake point following behind - * (could be configurable but this is reasonable default). */ -#define SCULPT_RAKE_BRUSH_FACTOR 0.25f - -struct SculptRakeData { - float follow_dist; - float follow_co[3]; -}; - typedef enum StrokeFlags { CLIP_X = 1, CLIP_Y = 2, CLIP_Z = 4 } StrokeFlags; -/* Cache stroke properties. Used because - * RNA property lookup isn't particularly fast. - * - * For descriptions of these settings, check the operator properties. - */ -typedef struct StrokeCache { - /* Invariants */ - float initial_radius; - float scale[3]; - int flag; - float clip_tolerance[3]; - float initial_mouse[2]; - - /* Variants */ - float radius; - float radius_squared; - float true_location[3]; - float location[3]; - - bool pen_flip; - bool invert; - float pressure; - float mouse[2]; - float bstrength; - float normal_weight; /* from brush (with optional override) */ - - /* The rest is temporary storage that isn't saved as a property */ - - bool first_time; /* Beginning of stroke may do some things special */ - - /* from ED_view3d_ob_project_mat_get() */ - float projection_mat[4][4]; - - /* Clean this up! */ - ViewContext *vc; - Brush *brush; - - float special_rotation; - float grab_delta[3], grab_delta_symmetry[3]; - float old_grab_location[3], orig_grab_location[3]; - - /* screen-space rotation defined by mouse motion */ - float rake_rotation[4], rake_rotation_symmetry[4]; - bool is_rake_rotation_valid; - struct SculptRakeData rake_data; - - int symmetry; /* Symmetry index between 0 and 7 bit combo 0 is Brush only; - * 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ - int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/ - float true_view_normal[3]; - float view_normal[3]; - - /* sculpt_normal gets calculated by calc_sculpt_normal(), then the - * sculpt_normal_symm gets updated quickly with the usual symmetry - * transforms */ - float sculpt_normal[3]; - float sculpt_normal_symm[3]; - - /* Used for area texture mode, local_mat gets calculated by - * calc_brush_local_mat() and used in tex_strength(). */ - float brush_local_mat[4][4]; - - float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */ - int tile_pass; - - float last_center[3]; - int radial_symmetry_pass; - float symm_rot_mat[4][4]; - float symm_rot_mat_inv[4][4]; - bool original; - float anchored_location[3]; - - float vertex_rotation; /* amount to rotate the vertices when using rotate brush */ - Dial *dial; - - char saved_active_brush_name[MAX_ID_NAME]; - char saved_mask_brush_tool; - int saved_smooth_size; /* smooth tool copies the size of the current tool */ - bool alt_smooth; - - float plane_trim_squared; - - bool supports_gravity; - float true_gravity_direction[3]; - float gravity_direction[3]; - - rcti previous_r; /* previous redraw rectangle */ - rcti current_r; /* current redraw rectangle */ -} StrokeCache; - /************** Access to original unmodified vertex data *************/ typedef struct { @@ -476,41 +376,6 @@ static bool sculpt_stroke_is_dynamic_topology( /*** paint mesh ***/ -/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */ -typedef struct SculptThreadedTaskData { - Sculpt *sd; - Object *ob; - Brush *brush; - PBVHNode **nodes; - int totnode; - - /* Data specific to some callbacks. */ - /* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out - * what it is, and memory overhead is ridiculous anyway... */ - float flippedbstrength; - float angle; - float strength; - bool smooth_mask; - bool has_bm_orco; - - SculptProjectVector *spvc; - float *offset; - float *grab_delta; - float *cono; - float *area_no; - float *area_no_sp; - float *area_co; - float (*mat)[4]; - float (*vertCos)[3]; - - /* 0=towards view, 1=flipped */ - float (*area_cos)[3]; - float (*area_nos)[3]; - int *count; - - ThreadMutex mutex; -} SculptThreadedTaskData; - static void paint_mesh_restore_co_task_cb(void *userdata, const int n) { SculptThreadedTaskData *data = userdata; @@ -600,7 +465,7 @@ static void sculpt_extend_redraw_rect_previous(Object *ob, rcti *rect) } /* Get a screen-space rectangle of the modified area */ -static bool sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d, +bool sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d, Object *ob, rcti *rect) { PBVH *pbvh = ob->sculpt->pbvh; @@ -650,17 +515,7 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar, /************************ Brush Testing *******************/ -typedef struct SculptBrushTest { - float radius_squared; - float location[3]; - float dist; - int mirror_symmetry_pass; - - /* View3d clipping - only set rv3d for clipping */ - RegionView3D *clip_rv3d; -} SculptBrushTest; - -static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) +void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) { RegionView3D *rv3d = ss->cache->vc->rv3d; @@ -689,7 +544,7 @@ BLI_INLINE bool sculpt_brush_test_clipping(const SculptBrushTest *test, const fl return ED_view3d_clipping_test(rv3d, symm_co, true); } -static bool sculpt_brush_test(SculptBrushTest *test, const float co[3]) +bool sculpt_brush_test(SculptBrushTest *test, const float co[3]) { float distsq = len_squared_v3v3(co, test->location); @@ -705,7 +560,7 @@ static bool sculpt_brush_test(SculptBrushTest *test, const float co[3]) } } -static bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) +bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) { float distsq = len_squared_v3v3(co, test->location); @@ -721,7 +576,7 @@ static bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) } } -static bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3]) +bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3]) { if (sculpt_brush_test_clipping(test, co)) { return 0; @@ -729,7 +584,7 @@ static bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3 return len_squared_v3v3(co, test->location) <= test->radius_squared; } -static bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4]) +bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4]) { float side = M_SQRT1_2; float local_co[3]; @@ -897,17 +752,19 @@ static void calc_area_normal_and_center_task_cb(void *userdata, const int n) PBVHVertexIter vd; SculptBrushTest test; - SculptUndoNode *unode; + SculptUndoNode *unode = NULL; float private_co[2][3] = {{0.0f}}; float private_no[2][3] = {{0.0f}}; int private_count[2] = {0}; - bool use_original; + bool use_original = false; - unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS); + if (ss->cache->original) { + unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS); + use_original = (unode->co || unode->bm_entry); + } sculpt_brush_test_init(ss, &test); - use_original = (ss->cache->original && (unode->co || unode->bm_entry)); /* when the mesh is edited we can't rely on original coords * (original mesh may not even have verts in brush radius) */ @@ -1029,8 +886,9 @@ static void calc_area_center( int count[2] = {0}; + /* Intentionally set 'sd' to NULL since we share logic with vertex paint. */ SculptThreadedTaskData data = { - .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode, + .sd = NULL, .ob = ob, .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = NULL, .count = count, }; BLI_mutex_init(&data.mutex); @@ -1053,42 +911,53 @@ static void calc_area_center( } } - static void calc_area_normal( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]) { const Brush *brush = BKE_paint_brush(&sd->paint); + bool use_threading = (sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT; + sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, use_threading, r_area_no); +} + +/* expose 'calc_area_normal' externally. */ +void sculpt_pbvh_calc_area_normal( + const Brush *brush, Object *ob, + PBVHNode **nodes, int totnode, + bool use_threading, + float r_area_no[3]) +{ SculptSession *ss = ob->sculpt; const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush); - int n; /* 0=towards view, 1=flipped */ float area_nos[2][3] = {{0.0f}}; int count[2] = {0}; + /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */ SculptThreadedTaskData data = { - .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode, + .sd = NULL, .ob = ob, .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, .area_cos = NULL, .area_nos = area_nos, .count = count, }; BLI_mutex_init(&data.mutex); BLI_task_parallel_range( 0, totnode, &data, calc_area_normal_and_center_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + use_threading); BLI_mutex_end(&data.mutex); /* for area normal */ - for (n = 0; n < ARRAY_SIZE(area_nos); n++) { - if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) { + for (int i = 0; i < ARRAY_SIZE(area_nos); i++) { + if (normalize_v3_v3(r_area_no, area_nos[i]) != 0.0f) { break; } } } + /* this calculates flatten center and area normal together, * amortizing the memory bandwidth and loop overhead to calculate both at the same time */ static void calc_area_normal_and_center( @@ -1107,8 +976,9 @@ static void calc_area_normal_and_center( int count[2] = {0}; + /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */ SculptThreadedTaskData data = { - .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode, + .sd = NULL, .ob = ob, .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = area_nos, .count = count, }; BLI_mutex_init(&data.mutex); @@ -1237,13 +1107,13 @@ static float brush_strength( } /* Return a multiplier for brush strength on a particular vertex. */ -static float tex_strength(SculptSession *ss, Brush *br, - const float brush_point[3], - const float len, - const short vno[3], - const float fno[3], - const float mask, - const int thread_id) +float tex_strength(SculptSession *ss, Brush *br, + const float brush_point[3], + const float len, + const short vno[3], + const float fno[3], + const float mask, + const int thread_id) { StrokeCache *cache = ss->cache; const Scene *scene = cache->vc->scene; @@ -1316,15 +1186,8 @@ static float tex_strength(SculptSession *ss, Brush *br, return avg; } -typedef struct { - Sculpt *sd; - SculptSession *ss; - float radius_squared; - bool original; -} SculptSearchSphereData; - /* Test AABB against sphere */ -static bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v) +bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v) { SculptSearchSphereData *data = data_v; float *center = data->ss->cache->location, nearest[3]; @@ -1632,6 +1495,22 @@ typedef struct SculptDoBrushSmoothGridDataChunk { size_t tmpgrid_size; } SculptDoBrushSmoothGridDataChunk; +typedef struct { + SculptSession *ss; + const float *ray_start, *ray_normal; + bool hit; + float dist; + bool original; + PBVHNode* node; +} SculptRaycastData; + +typedef struct { + const float *ray_start, *ray_normal; + bool hit; + float dist; + float detail; +} SculptDetailRaycastData; + static void do_smooth_brush_mesh_task_cb_ex( void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) { @@ -3688,12 +3567,10 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob) /* Flip all the editdata across the axis/axes specified by symm. Used to * calculate multiple modifications to the mesh when symmetry is enabled. */ -static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm, - const char axis, const float angle, - const float UNUSED(feather)) +void sculpt_cache_calc_brushdata_symm( + StrokeCache *cache, const char symm, + const char axis, const float angle) { - (void)sd; /* unused */ - flip_v3_v3(cache->location, cache->true_location, symm); flip_v3_v3(cache->grab_delta_symmetry, cache->grab_delta, symm); flip_v3_v3(cache->view_normal, cache->true_view_normal, symm); @@ -3791,7 +3668,7 @@ static void do_tiled(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups, BrushActionFunc action, const char symm, const int axis, - const float feather) + const float UNUSED(feather)) { SculptSession *ss = ob->sculpt; int i; @@ -3799,7 +3676,7 @@ static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPain for (i = 1; i < sd->radial_symm[axis - 'X']; ++i) { const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X']; ss->cache->radial_symmetry_pass = i; - calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather); + sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle); do_tiled(sd, ob, brush, ups, action); } } @@ -3817,8 +3694,9 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob) multires_stitch_grids(ob); } -static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob, - BrushActionFunc action, UnifiedPaintSettings *ups) +static void do_symmetrical_brush_actions( + Sculpt *sd, Object *ob, + BrushActionFunc action, UnifiedPaintSettings *ups) { Brush *brush = BKE_paint_brush(&sd->paint); SculptSession *ss = ob->sculpt; @@ -3837,7 +3715,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob, cache->mirror_symmetry_pass = i; cache->radial_symmetry_pass = 0; - calc_brushdata_symm(sd, cache, i, 0, 0, feather); + sculpt_cache_calc_brushdata_symm(cache, i, 0, 0); do_tiled(sd, ob, brush, ups, action); do_radial_symmetry(sd, ob, brush, ups, action, i, 'X', feather); @@ -3948,7 +3826,7 @@ static const char *sculpt_tool_name(Sculpt *sd) * Operator for applying a stroke (various attributes including mouse path) * using the current brush. */ -static void sculpt_cache_free(StrokeCache *cache) +void sculpt_cache_free(StrokeCache *cache) { if (cache->dial) MEM_freeN(cache->dial); @@ -4398,21 +4276,6 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob) } } -typedef struct { - SculptSession *ss; - const float *ray_start, *ray_normal; - bool hit; - float dist; - bool original; -} SculptRaycastData; - -typedef struct { - const float *ray_start, *ray_normal; - bool hit; - float dist; - float detail; -} SculptDetailRaycastData; - static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin) { if (BKE_pbvh_node_get_tmin(node) < *tmin) { @@ -4437,6 +4300,9 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin) { srd->hit = 1; *tmin = srd->dist; + + //for vwpaint testing + srd->node = node; } } } @@ -4521,12 +4387,17 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) srd.dist = dist; BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, - ray_start, ray_normal, srd.original); + ray_start, ray_normal, srd.original); copy_v3_v3(out, ray_normal); mul_v3_fl(out, srd.dist); add_v3_v3(out, ray_start); + //used in vwpaint + if (cache && srd.hit){ + copy_v3_v3(cache->true_location, out); + } + return srd.hit; } @@ -4656,8 +4527,11 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2]) { /* Don't start the stroke until mouse goes over the mesh. - * note: mouse will only be null when re-executing the saved stroke. */ - if (!mouse || over_mesh(C, op, mouse[0], mouse[1])) { + * note: mouse will only be null when re-executing the saved stroke. + * We have exception for 'exec' strokes since they may not set 'mouse', only 'location', see: T52195. */ + if (((op->flag & OP_IS_INVOKE) == 0) || + (mouse == NULL) || over_mesh(C, op, mouse[0], mouse[1])) + { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -5527,7 +5401,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; float size; - float bb_min[3], bb_max[3]; + float bb_min[3], bb_max[3], center[3], dim[3]; int i, totnodes; PBVHNode **nodes; @@ -5539,11 +5413,12 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) for (i = 0; i < totnodes; i++) { BKE_pbvh_node_mark_topology_update(nodes[i]); } - /* get the bounding box, store the size to bb_max and center (zero) to bb_min */ + /* get the bounding box, it's center and size */ BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max); - sub_v3_v3(bb_max, bb_min); - zero_v3(bb_min); - size = max_fff(bb_max[0], bb_max[1], bb_max[2]); + add_v3_v3v3(center, bb_min, bb_max); + mul_v3_fl(center, 0.5f); + sub_v3_v3v3(dim, bb_max, bb_min); + size = max_fff(dim[0], dim[1], dim[2]); /* update topology size */ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail); @@ -5553,7 +5428,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) while (BKE_pbvh_bmesh_update_topology( ss->pbvh, PBVH_Collapse | PBVH_Subdivide, - bb_min, NULL, size)) + center, NULL, size)) { for (i = 0; i < totnodes; i++) BKE_pbvh_node_mark_topology_update(nodes[i]); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 108fe3532e3..27d8fbaa340 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -38,12 +38,15 @@ #include "DNA_key_types.h" #include "BLI_bitmap.h" +#include "BLI_threads.h" + #include "BKE_pbvh.h" struct bContext; struct KeyBlock; struct Object; struct SculptUndoNode; +struct SculptOrigVertData; int sculpt_mode_poll(struct bContext *C); int sculpt_mode_poll_view3d(struct bContext *C); @@ -52,12 +55,12 @@ int sculpt_poll(struct bContext *C); int sculpt_poll_view3d(struct bContext *C); /* Stroke */ -bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]); +bool sculpt_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]); /* Dynamic topology */ void sculpt_pbvh_clear(Object *ob); void sculpt_dyntopo_node_layers_add(struct SculptSession *ss); -void sculpt_update_after_dynamic_topology_toggle(bContext *C); +void sculpt_update_after_dynamic_topology_toggle(struct bContext *C); void sculpt_dynamic_topology_enable(struct bContext *C); void sculpt_dynamic_topology_disable(struct bContext *C, struct SculptUndoNode *unode); @@ -115,6 +118,203 @@ typedef struct SculptUndoNode { char shapeName[sizeof(((KeyBlock *)0))->name]; } SculptUndoNode; +/* Factor of brush to have rake point following behind +* (could be configurable but this is reasonable default). */ +#define SCULPT_RAKE_BRUSH_FACTOR 0.25f + +struct SculptRakeData { + float follow_dist; + float follow_co[3]; +}; + +/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */ +typedef struct SculptThreadedTaskData { + struct bContext *C; + struct Sculpt *sd; + struct Object *ob; + struct Brush *brush; + struct PBVHNode **nodes; + int totnode; + + struct VPaint *vp; + struct VPaintData *vpd; + struct WPaintData *wpd; + struct WeightPaintInfo *wpi; + unsigned int *lcol; + struct Mesh *me; + /* For passing generic params. */ + void *custom_data; + + + /* Data specific to some callbacks. */ + /* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out + * what it is, and memory overhead is ridiculous anyway... */ + float flippedbstrength; + float angle; + float strength; + bool smooth_mask; + bool has_bm_orco; + + struct SculptProjectVector *spvc; + float *offset; + float *grab_delta; + float *cono; + float *area_no; + float *area_no_sp; + float *area_co; + float(*mat)[4]; + float(*vertCos)[3]; + + /* 0=towards view, 1=flipped */ + float(*area_cos)[3]; + float(*area_nos)[3]; + int *count; + + ThreadMutex mutex; + +} SculptThreadedTaskData; + +/*************** Brush testing declarations ****************/ +typedef struct SculptBrushTest { + float radius_squared; + float location[3]; + float dist; + int mirror_symmetry_pass; + + /* View3d clipping - only set rv3d for clipping */ + struct RegionView3D *clip_rv3d; +} SculptBrushTest; + +typedef struct { + struct Sculpt *sd; + struct SculptSession *ss; + float radius_squared; + bool original; +} SculptSearchSphereData; + +void sculpt_brush_test_init(struct SculptSession *ss, SculptBrushTest *test); +bool sculpt_brush_test(SculptBrushTest *test, const float co[3]); +bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]); +bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3]); +bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4]); +bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v); +float tex_strength( + struct SculptSession *ss, struct Brush *br, + const float point[3], + const float len, + const short vno[3], + const float fno[3], + const float mask, + const int thread_id); + +/* just for vertex paint. */ +void sculpt_pbvh_calc_area_normal( + const struct Brush *brush, Object *ob, + PBVHNode **nodes, int totnode, + bool use_threading, + float r_area_no[3]); + +/* Cache stroke properties. Used because +* RNA property lookup isn't particularly fast. +* +* For descriptions of these settings, check the operator properties. +*/ + +typedef struct StrokeCache { + /* Invariants */ + float initial_radius; + float scale[3]; + int flag; + float clip_tolerance[3]; + float initial_mouse[2]; + + /* Variants */ + float radius; + float radius_squared; + float true_location[3]; + float true_last_location[3]; + float location[3]; + float last_location[3]; + bool is_last_valid; + + bool pen_flip; + bool invert; + float pressure; + float mouse[2]; + float bstrength; + float normal_weight; /* from brush (with optional override) */ + + /* The rest is temporary storage that isn't saved as a property */ + + bool first_time; /* Beginning of stroke may do some things special */ + + /* from ED_view3d_ob_project_mat_get() */ + float projection_mat[4][4]; + + /* Clean this up! */ + struct ViewContext *vc; + struct Brush *brush; + + float special_rotation; + float grab_delta[3], grab_delta_symmetry[3]; + float old_grab_location[3], orig_grab_location[3]; + + /* screen-space rotation defined by mouse motion */ + float rake_rotation[4], rake_rotation_symmetry[4]; + bool is_rake_rotation_valid; + struct SculptRakeData rake_data; + + /* Symmetry index between 0 and 7 bit combo 0 is Brush only; + * 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ + int symmetry; + int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/ + float true_view_normal[3]; + float view_normal[3]; + + /* sculpt_normal gets calculated by calc_sculpt_normal(), then the + * sculpt_normal_symm gets updated quickly with the usual symmetry + * transforms */ + float sculpt_normal[3]; + float sculpt_normal_symm[3]; + + /* Used for area texture mode, local_mat gets calculated by + * calc_brush_local_mat() and used in tex_strength(). */ + float brush_local_mat[4][4]; + + float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */ + int tile_pass; + + float last_center[3]; + int radial_symmetry_pass; + float symm_rot_mat[4][4]; + float symm_rot_mat_inv[4][4]; + bool original; + float anchored_location[3]; + + float vertex_rotation; /* amount to rotate the vertices when using rotate brush */ + struct Dial *dial; + + char saved_active_brush_name[MAX_ID_NAME]; + char saved_mask_brush_tool; + int saved_smooth_size; /* smooth tool copies the size of the current tool */ + bool alt_smooth; + + float plane_trim_squared; + + bool supports_gravity; + float true_gravity_direction[3]; + float gravity_direction[3]; + + rcti previous_r; /* previous redraw rectangle */ + rcti current_r; /* current redraw rectangle */ + +} StrokeCache; + +void sculpt_cache_calc_brushdata_symm( + StrokeCache *cache, const char symm, + const char axis, const float angle); +void sculpt_cache_free(StrokeCache *cache); + SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type); SculptUndoNode *sculpt_undo_get_node(PBVHNode *node); void sculpt_undo_push_begin(const char *name); @@ -124,6 +324,8 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]); void sculpt_update_object_bounding_box(struct Object *ob); +bool sculpt_get_redraw_rect(struct ARegion *ar, struct RegionView3D *rv3d, Object *ob, rcti *rect); + #define SCULPT_THREADED_LIMIT 4 #endif diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index f8db35e2311..a9920389980 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -1522,7 +1522,7 @@ static int actkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op)) /* set the new current frame value, based on the average time */ if (ked.i1) { Scene *scene = ac.scene; - CFRA = iroundf(ked.f1 / ked.i1); + CFRA = round_fl_to_int(ked.f1 / ked.i1); SUBFRA = 0.f; } diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 553be0ad290..17edbc6cc1d 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -262,6 +262,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s { /* loop over data selecting */ switch (ale->type) { +#if 0 /* XXXX: Keyframes are not currently shown here */ case ANIMTYPE_GPDATABLOCK: { bGPdata *gpd = ale->data; @@ -271,6 +272,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s } break; } +#endif case ANIMTYPE_GPLAYER: ED_gplayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode); break; diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 83655a2ba9e..5cde224b7dc 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -624,13 +624,17 @@ static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, I { SpaceAction *sact = (SpaceAction *)slink; - if (!ELEM(GS(old_id->name), ID_GR)) { - return; + if ((ID *)sact->action == old_id) { + sact->action = (bAction *)new_id; } if ((ID *)sact->ads.filter_grp == old_id) { sact->ads.filter_grp = (Group *)new_id; } + if ((ID *)sact->ads.source == old_id) { + sact->ads.source = new_id; + } + } /* only called once, from space/spacetypes.c */ diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 695d04d3850..a71b2baa96f 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -365,9 +365,11 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track) { +#define MAX_STATIC_PATH 64 int count = sc->path_length; int i, a, b, curindex = -1; - float path[102][2]; + float path_static[(MAX_STATIC_PATH + 1) * 2][2]; + float (*path)[2]; int tiny = sc->flag & SC_SHOW_TINY_MARKER, framenr, start_frame; MovieTrackingMarker *marker; @@ -380,6 +382,13 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin if (marker->framenr != framenr || marker->flag & MARKER_DISABLED) return; + if (count < MAX_STATIC_PATH) { + path = path_static; + } + else { + path = MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path"); + } + a = count; i = framenr - 1; while (i >= framenr - count) { @@ -470,6 +479,11 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin glVertex2f(path[i][0], path[i][1]); } glEnd(); + + if (path != path_static) { + MEM_freeN(path); + } +#undef MAX_STATIC_PATH } static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker, diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 9430ee626ba..970eae0ad14 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -941,7 +941,7 @@ static int frame_from_event(bContext *C, const wmEvent *event) UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy); - framenr = iroundf(viewx); + framenr = round_fl_to_int(viewx); } return framenr; diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 237082f948b..58930fa2cf2 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -821,6 +821,7 @@ static void clip_keymap(struct wmKeyConfig *keyconf) #endif } +/* DO NOT make this static, this hides the symbol and breaks API generation script. */ const char *clip_context_dir[] = {"edit_movieclip", "edit_mask", NULL}; static int clip_context(const bContext *C, const char *member, bContextDataResult *result) diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c index 368cbeaf955..0dd0ee8c7d4 100644 --- a/source/blender/editors/space_clip/tracking_ops_track.c +++ b/source/blender/editors/space_clip/tracking_ops_track.c @@ -165,7 +165,7 @@ static int track_markers_initjob(bContext *C, track_init_markers(sc, clip, framenr, &frames_limit); - tmj->sfra = ED_space_clip_get_clip_frame_number(sc); + tmj->sfra = framenr; tmj->clip = clip; tmj->backwards = backwards; @@ -176,6 +176,7 @@ static int track_markers_initjob(bContext *C, else { tmj->efra = EFRA; } + tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra); } else { if (backwards) { @@ -196,8 +197,6 @@ static int track_markers_initjob(bContext *C, } } - tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra); - if (settings->speed != TRACKING_SPEED_FASTEST) { tmj->delay = 1.0f / scene->r.frs_sec * 1000.0f; @@ -212,7 +211,7 @@ static int track_markers_initjob(bContext *C, } } - tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards, 1); + tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards, true); clip->tracking_context = tmj->context; @@ -310,6 +309,7 @@ static void track_markers_endjob(void *tmv) static void track_markers_freejob(void *tmv) { TrackMarkersJob *tmj = (TrackMarkersJob *)tmv; + tmj->clip->tracking_context = NULL; BKE_autotrack_context_free(tmj->context); MEM_freeN(tmj); } diff --git a/source/blender/editors/space_console/console_intern.h b/source/blender/editors/space_console/console_intern.h index 5b016b77e9f..f523cf0d476 100644 --- a/source/blender/editors/space_console/console_intern.h +++ b/source/blender/editors/space_console/console_intern.h @@ -70,6 +70,6 @@ void CONSOLE_OT_select_set(struct wmOperatorType *ot); void CONSOLE_OT_select_word(struct wmOperatorType *ot); enum { LINE_BEGIN, LINE_END, PREV_CHAR, NEXT_CHAR, PREV_WORD, NEXT_WORD }; -enum { DEL_ALL, DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_NEXT_WORD, DEL_PREV_WORD, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL }; +enum { DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_NEXT_WORD, DEL_PREV_WORD, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL }; #endif /* __CONSOLE_INTERN_H__ */ diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 6c33091ff01..48f3dd4fde6 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -277,9 +277,10 @@ typedef struct FileListFilter { /* FileListFilter.flags */ enum { - FLF_HIDE_DOT = 1 << 0, - FLF_HIDE_PARENT = 1 << 1, - FLF_HIDE_LIB_DIR = 1 << 2, + FLF_DO_FILTER = 1 << 0, + FLF_HIDE_DOT = 1 << 1, + FLF_HIDE_PARENT = 1 << 2, + FLF_HIDE_LIB_DIR = 1 << 3, }; typedef struct FileList { @@ -594,24 +595,27 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root) { bool is_filtered = !is_hidden_file(file->relpath, filter); - if (is_filtered && filter->filter && !FILENAME_IS_CURRPAR(file->relpath)) { - if (file->typeflag & FILE_TYPE_DIR) { - if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - is_filtered = false; + if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { + /* We only check for types if some type are enabled in filtering. */ + if (filter->filter) { + if (file->typeflag & FILE_TYPE_DIR) { + if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + is_filtered = false; + } + } + else { + if (!(filter->filter & FILE_TYPE_FOLDER)) { + is_filtered = false; + } } } else { - if (!(filter->filter & FILE_TYPE_FOLDER)) { + if (!(file->typeflag & filter->filter)) { is_filtered = false; } } } - else { - if (!(file->typeflag & filter->filter)) { - is_filtered = false; - } - } if (is_filtered && (filter->filter_search[0] != '\0')) { if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { is_filtered = false; @@ -631,28 +635,31 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis if (BLO_library_path_explode(path, dir, &group, &name)) { is_filtered = !is_hidden_file(file->relpath, filter); - if (is_filtered && filter->filter && !FILENAME_IS_CURRPAR(file->relpath)) { - if (file->typeflag & FILE_TYPE_DIR) { - if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - is_filtered = false; + if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { + /* We only check for types if some type are enabled in filtering. */ + if (filter->filter || filter->filter_id) { + if (file->typeflag & FILE_TYPE_DIR) { + if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + is_filtered = false; + } } - } - else { - if (!(filter->filter & FILE_TYPE_FOLDER)) { - is_filtered = false; + else { + if (!(filter->filter & FILE_TYPE_FOLDER)) { + is_filtered = false; + } } } - } - if (is_filtered && group) { - if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { - is_filtered = false; - } - else { - unsigned int filter_id = groupname_to_filter_id(group); - if (!(filter_id & filter->filter_id)) { + if (is_filtered && group) { + if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { is_filtered = false; } + else { + unsigned int filter_id = groupname_to_filter_id(group); + if (!(filter_id & filter->filter_id)) { + is_filtered = false; + } + } } } if (is_filtered && (filter->filter_search[0] != '\0')) { @@ -729,12 +736,17 @@ void filelist_filter(FileList *filelist) MEM_freeN(filtered_tmp); } -void filelist_setfilter_options(FileList *filelist, const bool hide_dot, const bool hide_parent, +void filelist_setfilter_options(FileList *filelist, const bool do_filter, + const bool hide_dot, const bool hide_parent, const unsigned int filter, const unsigned int filter_id, const char *filter_glob, const char *filter_search) { bool update = false; + if (((filelist->filter_data.flags & FLF_DO_FILTER) != 0) != (do_filter != 0)) { + filelist->filter_data.flags ^= FLF_DO_FILTER; + update = true; + } if (((filelist->filter_data.flags & FLF_HIDE_DOT) != 0) != (hide_dot != 0)) { filelist->filter_data.flags ^= FLF_HIDE_DOT; update = true; @@ -1104,7 +1116,10 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source); IMB_thumb_path_unlock(preview->path); - preview->flags = 0; /* Used to tell free func to not free anything! */ + /* Used to tell free func to not free anything. + * Note that we do not care about cas result here, + * we only want value attribution itself to be atomic (and memory barier).*/ + atomic_cas_uint32(&preview->flags, preview->flags, 0); BLI_thread_queue_push(cache->previews_done, preview); // printf("%s: End (%d)...\n", __func__, threadid); @@ -1979,8 +1994,7 @@ int ED_path_extension_type(const char *path) else if (BLI_testextensie(path, ".abc")) { return FILE_TYPE_ALEMBIC; } - else if (BLI_testextensie_array(path, imb_ext_image) || - (G.have_quicktime && BLI_testextensie_array(path, imb_ext_image_qt))) + else if (BLI_testextensie_array(path, imb_ext_image)) { return FILE_TYPE_IMAGE; } diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index f4304681780..4e9c1e0dd1d 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -68,7 +68,8 @@ int folderlist_clear_next(struct SpaceFile *sfile); void filelist_setsorting(struct FileList *filelist, const short sort); void filelist_sort(struct FileList *filelist); -void filelist_setfilter_options(struct FileList *filelist, const bool hide_dot, const bool hide_parent, +void filelist_setfilter_options(struct FileList *filelist, const bool do_filter, + const bool hide_dot, const bool hide_parent, const unsigned int filter, const unsigned int filter_id, const char *filter_glob, const char *filter_search); void filelist_filter(struct FileList *filelist); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 374db92297d..287b98fa589 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -223,9 +223,10 @@ static void file_refresh(const bContext *C, ScrArea *sa) filelist_setdir(sfile->files, params->dir); filelist_setrecursion(sfile->files, params->recursion_level); filelist_setsorting(sfile->files, params->sort); - filelist_setfilter_options(sfile->files, (params->flag & FILE_HIDE_DOT) != 0, + filelist_setfilter_options(sfile->files, (params->flag & FILE_FILTER) != 0, + (params->flag & FILE_HIDE_DOT) != 0, false, /* TODO hide_parent, should be controllable? */ - (params->flag & FILE_FILTER) ? params->filter : 0, + params->filter, params->filter_id, params->filter_glob, params->filter_search); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index f38d36853d7..861a38da2c7 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -195,8 +195,8 @@ static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) /* set the range directly */ get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL, false, false); scene->r.flag |= SCER_PRV_RANGE; - scene->r.psfra = iroundf(min); - scene->r.pefra = iroundf(max); + scene->r.psfra = round_fl_to_int(min); + scene->r.pefra = round_fl_to_int(max); /* set notifier that things have changed */ // XXX err... there's nothing for frame ranges yet, but this should do fine too @@ -2036,7 +2036,7 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op)) } else { /* Animation Mode - Affects current frame (int) */ - CFRA = iroundf(ked.f1 / ked.i1); + CFRA = round_fl_to_int(ked.f1 / ked.i1); SUBFRA = 0.f; sipo->cursorVal = ked.f2 / (float)ked.i1; } diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 75f0da83e77..5c670a216d8 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -94,7 +94,7 @@ static void graphview_cursor_apply(bContext *C, wmOperator *op) * NOTE: sync this part of the code with ANIM_OT_change_frame */ /* 1) frame is rounded to the nearest int, since frames are ints */ - CFRA = iroundf(frame); + CFRA = round_fl_to_int(frame); if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) { /* Clip to preview range diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index e810f4db7dd..8cb23c9e021 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -88,7 +88,7 @@ static void draw_render_info(const bContext *C, float zoomy) { RenderResult *rr; - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); RenderData *rd = RE_engine_get_render_data(re); Scene *stats_scene = ED_render_job_get_scene(C); if (stats_scene == NULL) { diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index a0d67626940..55fcf9213d6 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1169,6 +1169,7 @@ static int image_sequence_get_len(ListBase *frames, int *ofs) } return frame_curr - (*ofs); } + *ofs = 0; return 0; } @@ -3525,7 +3526,7 @@ static int frame_from_event(bContext *C, const wmEvent *event) UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy); - framenr = iroundf(viewx); + framenr = round_fl_to_int(viewx); } return framenr; @@ -3631,7 +3632,7 @@ static int render_border_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); RenderData *rd; rctf border; diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 1f298373a80..f7f7c82171d 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -365,8 +365,8 @@ static int nlaedit_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) /* set the range directly */ get_nlastrip_extents(&ac, &min, &max, true); scene->r.flag |= SCER_PRV_RANGE; - scene->r.psfra = iroundf(min); - scene->r.pefra = iroundf(max); + scene->r.psfra = round_fl_to_int(min); + scene->r.pefra = round_fl_to_int(max); /* set notifier that things have changed */ // XXX err... there's nothing for frame ranges yet, but this should do fine too diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index f58b4050834..7ef34669ee2 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -638,7 +638,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED( * highlight also if node itself is selected, since we don't display the node body separately! */ for (sock = node->inputs.first; sock; sock = sock->next) { - node_socket_circle_draw(C, ntree, node, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT)); + node_socket_draw(C, ntree, node, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT)); } UI_block_end(C, node->block); @@ -2204,16 +2204,17 @@ static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNo if (node->custom1 == 0) { const float backdropWidth = backdrop->x; const float backdropHeight = backdrop->y; - const float cx = x + snode->zoom * backdropWidth * node->custom3; + const float cx = x + snode->zoom * backdropWidth * node->custom3; const float cy = y + snode->zoom * backdropHeight * node->custom4; + const float cross_size = 12 * U.pixelsize; glColor3f(1.0, 1.0, 1.0); glBegin(GL_LINES); - glVertex2f(cx - 25, cy - 25); - glVertex2f(cx + 25, cy + 25); - glVertex2f(cx + 25, cy - 25); - glVertex2f(cx - 25, cy + 25); + glVertex2f(cx - cross_size, cy - cross_size); + glVertex2f(cx + cross_size, cy + cross_size); + glVertex2f(cx + cross_size, cy - cross_size); + glVertex2f(cx - cross_size, cy + cross_size); glEnd(); } } diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 6e25c87d274..d7119302611 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -617,34 +617,22 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node) glDisable(GL_LINE_SMOOTH); } -/* this might have some more generic use */ -static void node_circle_draw(float x, float y, float size, const float col[4], int highlight) +static void node_socket_shape_draw( + float x, float y, float size, const float col[4], bool highlight, + const float coords[][2], int coords_len) { - /* 16 values of sin function */ - static const float si[16] = { - 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f, - 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f, - -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f, - -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f - }; - /* 16 values of cos function */ - static const float co[16] = { - 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f, - -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f, - -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f, - 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f, - }; int a; - + glColor4fv(col); - + glEnable(GL_BLEND); glBegin(GL_POLYGON); - for (a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); + for (a = 0; a < coords_len; a++) { + glVertex2f(x + size * coords[a][0], y + size * coords[a][1]); + } glEnd(); glDisable(GL_BLEND); - + if (highlight) { UI_ThemeColor(TH_TEXT_HI); glLineWidth(1.5f); @@ -655,14 +643,16 @@ static void node_circle_draw(float x, float y, float size, const float col[4], i glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); glBegin(GL_LINE_LOOP); - for (a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); + for (a = 0; a < coords_len; a++) { + glVertex2f(x + size * coords[a][0], y + size * coords[a][1]); + } glEnd(); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); } -void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, int highlight) + +void node_socket_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, bool highlight) { PointerRNA ptr, node_ptr; float color[4]; @@ -670,7 +660,60 @@ void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, bNode *node, b RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color); - node_circle_draw(sock->locx, sock->locy, size, color, highlight); + + /* 16 values of {sin, cos} function */ + const float shape_circle[16][2] = { + {0.00000000f, 1.00000000f}, + {0.39435585f, 0.91895781f}, + {0.72479278f, 0.68896691f}, + {0.93775213f, 0.34730525f}, + {0.99871650f, -0.05064916f}, + {0.89780453f, -0.44039415f}, + {0.65137248f, -0.75875812f}, + {0.29936312f, -0.95413925f}, + {-0.10116832f, -0.99486932f}, + {-0.48530196f, -0.87434661f}, + {-0.79077573f, -0.61210598f}, + {-0.96807711f, -0.25065253f}, + {-0.98846832f, 0.15142777f}, + {-0.84864425f, 0.52896401f}, + {-0.57126821f, 0.82076344f}, + {-0.20129852f, 0.97952994f } + }; + + const float shape_diamond[4][2] = { + {0.0f, 1.2f}, + {1.2f, 0.0f}, + {0.0f, -1.2f}, + {-1.2f, 0.0f}, + }; + + const float shape_square[4][2] = { + {-0.9f, 0.9f}, + {0.9f, 0.9f}, + {0.9f, -0.9f}, + {-0.9f, -0.9f}, + }; + + const float (*shape)[2]; + int shape_len; + switch (sock->draw_shape) { + default: + case SOCK_DRAW_SHAPE_CIRCLE: + shape = shape_circle; + shape_len = ARRAY_SIZE(shape_circle); + break; + case SOCK_DRAW_SHAPE_DIAMOND: + shape = shape_diamond; + shape_len = ARRAY_SIZE(shape_diamond); + break; + case SOCK_DRAW_SHAPE_SQUARE: + shape = shape_square; + shape_len = ARRAY_SIZE(shape_square); + break; + } + + node_socket_shape_draw(sock->locx, sock->locy, size, color, highlight, shape, shape_len); } /* ************** Socket callbacks *********** */ @@ -935,7 +978,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN if (nodeSocketIsHidden(sock)) continue; - node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); + node_socket_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); } /* socket outputs */ @@ -943,7 +986,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN if (nodeSocketIsHidden(sock)) continue; - node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); + node_socket_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); } /* preview */ @@ -1048,7 +1091,7 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b // BLI_snprintf(showname, sizeof(showname), "[%s]", showname); /* XXX - don't print into self! */ uiDefBut(node->block, UI_BTYPE_LABEL, 0, showname, - iroundf(rct->xmin + NODE_MARGIN_X), iroundf(centy - NODE_DY * 0.5f), + round_fl_to_int(rct->xmin + NODE_MARGIN_X), round_fl_to_int(centy - NODE_DY * 0.5f), (short)(BLI_rctf_size_x(rct) - 18.0f - 12.0f), (short)NODE_DY, NULL, 0, 0, 0, 0, ""); } @@ -1066,13 +1109,15 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b /* sockets */ for (sock = node->inputs.first; sock; sock = sock->next) { - if (!nodeSocketIsHidden(sock)) - node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); + if (!nodeSocketIsHidden(sock)) { + node_socket_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); + } } for (sock = node->outputs.first; sock; sock = sock->next) { - if (!nodeSocketIsHidden(sock)) - node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); + if (!nodeSocketIsHidden(sock)) { + node_socket_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); + } } UI_block_end(C, node->block); diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 5f8f839025f..e91fd1ee575 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -1321,7 +1321,7 @@ static int node_read_fullsamplelayers_exec(bContext *C, wmOperator *UNUSED(op)) Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); Scene *curscene = CTX_data_scene(C); - Render *re = RE_NewRender(curscene->id.name); + Render *re = RE_NewSceneRender(curscene); WM_cursor_wait(1); RE_MergeFullSample(re, bmain, curscene, snode->nodetree); diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index 914f8ffbe10..9d750bfe348 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -37,6 +37,7 @@ #include "DNA_anim_types.h" #include "BLI_listbase.h" +#include "BLI_linklist.h" #include "BLI_math.h" #include "BLT_translation.h" @@ -186,6 +187,7 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode) bNode *node, *nextnode; bNodeTree *ngroup, *wgroup; ListBase anim_basepaths = {NULL, NULL}; + LinkNode *nodes_delayed_free = NULL; ngroup = (bNodeTree *)gnode->id; @@ -208,8 +210,8 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode) * This also removes remaining links to and from interface nodes. */ if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { - nodeFreeNode(wgroup, node); - continue; + /* We must delay removal since sockets will reference this node. see: T52092 */ + BLI_linklist_prepend(&nodes_delayed_free, node); } /* keep track of this node's RNA "base" path (the part of the path identifying the node) @@ -336,6 +338,11 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode) } } + while (nodes_delayed_free) { + node = BLI_linklist_pop(&nodes_delayed_free); + nodeFreeNode(ntree, node); + } + /* delete the group instance */ nodeFreeNode(ntree, gnode); diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 6b8fa0b88fe..352f9e51012 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -67,8 +67,9 @@ void snode_group_offset(struct SpaceNode *snode, float *x, float *y); /* transfo /* node_draw.c */ int node_get_colorid(struct bNode *node); -void node_socket_circle_draw(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node, - struct bNodeSocket *sock, float size, int highlight); +void node_socket_draw( + const struct bContext *C, struct bNodeTree *ntree, struct bNode *node, + struct bNodeSocket *sock, float size, bool highlight); int node_get_resize_cursor(int directions); void node_draw_shadow(struct SpaceNode *snode, struct bNode *node, float radius, float alpha); void node_draw_default(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 5f592431558..3b03399a5e7 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -567,7 +567,13 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) ntree->is_updating = true; for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { bNodeLink *link = linkdata->data; - + + /* See note below, but basically TEST flag means that the link + * was connected to output (or to a node which affects the + * output). + */ + do_tag_update |= (link->flag & NODE_LINK_TEST) != 0; + if (apply_links && link->tosock && link->fromsock) { /* before actually adding the link, * let nodes perform special link insertion handling @@ -593,11 +599,6 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) } } else { - /* See note below, but basically TEST flag means that the link - * was connected to output (or to a node which affects the - * output). - */ - do_tag_update |= (link->flag & NODE_LINK_TEST) != 0; nodeRemLink(ntree, link); } } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 121fe812016..af6fdf2ab86 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1273,7 +1273,10 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto } } else { - switch (GS(tselem->id->name)) { + /* TODO(sergey): Casting to short here just to handle ID_NLA which is + * NOT inside of IDType enum. + */ + switch ((short)GS(tselem->id->name)) { case ID_SCE: tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break; case ID_ME: @@ -1343,6 +1346,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break; case ID_GD: tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break; + default: + break; } } } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 265a19b9e7e..f4089667b04 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -1092,7 +1092,7 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op)) te = outliner_find_id(so, &so->tree, &obact->id); - if (obact->type == OB_ARMATURE) { + if (te != NULL && obact->type == OB_ARMATURE) { /* traverse down the bone hierarchy in case of armature */ TreeElement *te_obact = te; diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 09a49f201d4..4b0b0e2e0f0 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -882,6 +882,8 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor } break; } + default: + break; } } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 70a6e6d83cb..97961501c6d 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -40,6 +40,7 @@ #include "DNA_scene_types.h" #include "DNA_mask_types.h" +#include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_userdef_types.h" @@ -1116,18 +1117,16 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; bool draw_metadata = false; - if (G.is_rendering == false && (scene->r.seq_flag & R_SEQ_GL_PREV) == 0) { + if (G.is_rendering == false && (scene->r.seq_prev_type) == OB_RENDER) { /* stop all running jobs, except screen one. currently previews frustrate Render * needed to make so sequencer's rendering doesn't conflict with compositor */ WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_COMPOSITE); - if ((scene->r.seq_flag & R_SEQ_GL_PREV) == 0) { - /* in case of final rendering used for preview, kill all previews, - * otherwise threading conflict will happen in rendering module - */ - WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_RENDER_PREVIEW); - } + /* in case of final rendering used for preview, kill all previews, + * otherwise threading conflict will happen in rendering module + */ + WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_RENDER_PREVIEW); } if ((!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) && !draw_backdrop) { diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index e63569ac386..b22a158e151 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -727,7 +727,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) if (!skip_dup) { /* Duplicate AFTER the first change */ - seqn = BKE_sequence_dupli_recursive(scene, NULL, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); + seqn = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); } if (seqn) { @@ -820,7 +820,7 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) if (!skip_dup) { /* Duplicate AFTER the first change */ - seqn = BKE_sequence_dupli_recursive(scene, NULL, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); + seqn = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); } if (seqn) { @@ -2162,7 +2162,7 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) if (ed == NULL) return OPERATOR_CANCELLED; - BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT); + BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT, 0); if (nseqbase.first) { Sequence *seq = nseqbase.first; @@ -3200,7 +3200,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME); + BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME, 0); /* To make sure the copied strips have unique names between each other add * them temporarily to the end of the original seqbase. (bug 25932) @@ -3267,7 +3267,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) ED_sequencer_deselect_all(scene); ofs = scene->r.cfra - seqbase_clipboard_frame; - BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME); + BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME, 0); /* transform pasted strips before adding */ if (ofs) { diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index a2a80297041..f1d0f23f8af 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -435,6 +435,7 @@ static void sequencer_dropboxes(void) /* ************* end drop *********** */ +/* DO NOT make this static, this hides the symbol and breaks API generation script. */ const char *sequencer_context_dir[] = {"edit_mask", NULL}; static int sequencer_context(const bContext *C, const char *member, bContextDataResult *result) diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c index 0d19c503798..1ef3322711c 100644 --- a/source/blender/editors/space_text/text_format_pov.c +++ b/source/blender/editors/space_text/text_format_pov.c @@ -49,36 +49,38 @@ static int txtfmt_pov_find_keyword(const char *string) { int i, len; /* Language Directives */ - if (STR_LITERAL_STARTSWITH(string, "append", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "debug", len)) i = len; + if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "persistent", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "version", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "warning", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "declare", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "default", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "include", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "append", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "elseif", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "debug", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "end", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "error", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fclose", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fopen", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "ifndef", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "ifdef", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "include", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "patch", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "local", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "macro", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "range", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "read", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "render", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "switch", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "undef", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "version", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "warning", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "write", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "end", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; else i = 0; /* If next source char is an identifier (eg. 'i' in "definate") no match */ @@ -92,221 +94,275 @@ static int txtfmt_pov_find_reserved_keywords(const char *string) * list is from... * http://www.povray.org/documentation/view/3.7.0/212/ */ + + /* Float Functions */ + if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_intersections", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dimension_size", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bitwise_and", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bitwise_or", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bitwise_xor", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "file_exists", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "precompute", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dimensions", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clipped_by", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "shadowless", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "turb_depth", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "reciprocal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "quaternion", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "phong_size", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tesselate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "save_file", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "load_file", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_trace", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "transform", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "translate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "direction", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "roughness", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "metallic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gts_load", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gts_save", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "location", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "altitude", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "function", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "evaluate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inverse", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "collect", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "target", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "albedo", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rotate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "matrix", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "look_at", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "jitter", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "angle", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "right", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "scale", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "child", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "crand", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "blink", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "defined", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "degrees", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inside", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "radians", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vlength", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "select", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "floor", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "strcmp", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "strlen", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tessel", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sturm", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "abs", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "acosh", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "prod", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "with", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "acos", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "asc", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "asinh", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "asin", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "atan2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "atand", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "atanh", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "atan", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ceil", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "warp", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cosh", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "log", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "min", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mod", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pow", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rand", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "seed", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "form", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sinh", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sqrt", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tanh", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vdot", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sin", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sqr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sum", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pwr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tan", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "val", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cos", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "div", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "exp", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "int", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sky", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "up", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ln", len)) i = len; + /* Color Identifiers */ + else if (STR_LITERAL_STARTSWITH(string, "transmit", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "filter", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "srgbft", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "srgbf", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "srgbt", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rgbft", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gamma", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "green", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "blue", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gray", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "srgb", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sRGB", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "SRGB", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rgbf", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rgbt", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rgb", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "red", len)) i = len; + /* Color Spaces */ + else if (STR_LITERAL_STARTSWITH(string, "pov", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hsl", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hsv", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "xyl", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "xyv", len)) i = len; + /* Vector Functions */ + else if (STR_LITERAL_STARTSWITH(string, "vaxis_rotate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vturbulence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "min_extent", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vnormalize", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_extent", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vrotate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vcross", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "trace", len)) i = len; + /* String Functions */ + else if (STR_LITERAL_STARTSWITH(string, "file_time", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "datetime", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "concat", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "strlwr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "strupr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "substr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vstr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "chr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "str", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "definate") no match */ + return (i == 0 || text_check_identifier(string[i])) ? -1 : i; +} + + +static int txtfmt_pov_find_reserved_builtins(const char *string) +{ + int i, len; + + /* POV-Ray Built-in Variables + * list is from... + * http://www.povray.org/documentation/view/3.7.0/212/ + */ /* Language Keywords */ - if (STR_LITERAL_STARTSWITH(string, "aa_level", len)) i = len; + if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "area_illumination", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "all_intersections", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cutaway_textures", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "smooth_triangle", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lommel_seeliger", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "falloff_angle", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "aa_threshold", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hypercomplex", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "major_radius", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_distance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_iteration", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "colour_space", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "color_space", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "iridescence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "subsurface", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "scattering", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "absorption", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "accuracy", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "adc_bailout", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "albedo", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "all_intersections", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "translucency", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "all", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "alpha", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "altitude", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "always_sample", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ambient_light", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ambient", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "angle", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "aperture", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "water_level", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "reflection", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_extent", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "oren_nayar", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "refraction", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hierarchy", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "radiosity", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tolerance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "interior", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "toroidal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "emission", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "material", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "internal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "photons", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "arc_angle", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "area_light", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "area_illumination", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "minnaert", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "texture", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "array", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "assumed_gamma", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "autostop", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "black_hole", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "blur_samples", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "brightness", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "brilliance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "caustics", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "charset", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "collect", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "component", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "composite", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "confidence", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "contained_by", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "coords", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "count", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "crand", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "cube", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cutaway_textures", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "diffuse", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "direction", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "dispersion", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "dist_exp", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "distance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "eccentricity", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "emission", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "error_bound", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "evaluate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "expand_thresholds", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "exponent", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "exterior", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "extinction", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "face_indices", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "falloff_angle", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "falloff", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "file_gamma", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "flatness", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "planet", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "screw", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "keep", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "flip", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "focal_point", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fog_alt", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fog_offset", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fog_type", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "form", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fresnel", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "function", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "gamma", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "gather", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "global_settings", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "gray_threshold", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "hf_gray_16", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "hierarchy", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "hypercomplex", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "importance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "inside_vector", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "internal", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "intervals", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ior", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "irid_wavelength", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "irid", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "load_file", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "location", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "move", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "roll", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "look_at", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "looks_like", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "low_error_factor", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "major_radius", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_distance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_extent", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_gradient", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_intersections", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_iteration", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_sample", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_trace_level", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_trace", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "maximum_reuse", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "metallic", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "method", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "metric", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "minimum_reuse", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "nearest_count", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "normal_indices", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "normal_vectors", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "now", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "number_of_waves", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "offset", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "open", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "orientation", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pass_through", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "pattern", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "phong_size", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "phong", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "point_at", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pot", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "precision", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "precompute", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pretrace_end", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pretrace_start", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "prod", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pwr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "quaternion", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "radiosity", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "radius", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ratio", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "reciprocal", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "recursion_limit", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "reflection", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "refraction", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "width", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "repeat", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "right", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "roughness", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "samples", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "save_file", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "scattering", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bend", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "size", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sky", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "alpha", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "slice", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "smooth", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "solid", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "spacing", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "specular", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "split_union", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "spotlight", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "strength", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sturm", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sum", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "target", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "texture_list", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "thickness", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "threshold", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tightness", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tolerance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "toroidal", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ttf", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "turb_depth", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "all", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "now", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pot", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "type", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "u_steps", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "up", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "use_alpha", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "uv_indices", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "uv_vectors", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "v_steps", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "variance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vertex_vectors", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "water_level", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "width", len)) i = len; - - else i = 0; - - /* If next source char is an identifier (eg. 'i' in "definate") no match */ - return (i == 0 || text_check_identifier(string[i])) ? -1 : i; -} - - -static int txtfmt_pov_find_reserved_builtins(const char *string) -{ - int i, len; - - /* POV-Ray Built-in Variables - * list is from... - * http://www.povray.org/documentation/view/3.7.0/212/ - */ - if (STR_LITERAL_STARTSWITH(string, "clock_delta", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "clock", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "clock_on", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "final_clock", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "final_frame", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "frame_number", len)) i = len; + /* Animation Options */ + else if (STR_LITERAL_STARTSWITH(string, "global_settings", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "input_file_name", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "initial_clock", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "initial_frame", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "frame_number", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "image_height", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "image_width", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "input_file_name", len)) i = len; - /* Color Identifiers */ - else if (STR_LITERAL_STARTSWITH(string, "blue", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "filter", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "gray", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "green", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "red", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rgbft", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rgbf", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rgbt", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rgb", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "srgb", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sRGB", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "SRGB", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "srgbft", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "srgbf", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "srgbt", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "transmit", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "final_clock", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "final_frame", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clock_delta", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clock_on", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clock", len)) i = len; + /* Spline Identifiers */ + else if (STR_LITERAL_STARTSWITH(string, "extended_x_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "general_x_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "quadratic_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "basic_x_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "natural_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "linear_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bezier_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "akima_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cubic_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sor_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tcb_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "linear_sweep", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "conic_sweep", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "b_spline", len)) i = len; /* Patterns */ - else if (STR_LITERAL_STARTSWITH(string, "agate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "aoi", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pigment_pattern", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "image_pattern", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "density_file", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cylindrical", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "proportion", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "triangular", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "image_map", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "proximity", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "spherical", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bump_map", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "wrinkles", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "average", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "voronoi", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "masonry", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "binary", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "boxed", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "bozo", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "brick", len)) i = len; @@ -315,14 +371,11 @@ static int txtfmt_pov_find_reserved_builtins(const char *string) else if (STR_LITERAL_STARTSWITH(string, "checker", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "crackle", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cylindrical", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "density_file", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "dents", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "facets", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "gradient", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "granite", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "hexagon", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "image_pattern", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "julia", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "leopard", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "magnet", len)) i = len; @@ -330,13 +383,11 @@ static int txtfmt_pov_find_reserved_builtins(const char *string) else if (STR_LITERAL_STARTSWITH(string, "marble", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "onion", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "pavement", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pigment_pattern", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "planar", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "quilted", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "radial", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "ripples", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "slope", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "spherical", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "spiral1", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "spiral2", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "spotted", len)) i = len; @@ -344,97 +395,68 @@ static int txtfmt_pov_find_reserved_builtins(const char *string) else if (STR_LITERAL_STARTSWITH(string, "tile2", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "tiling", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "tiles", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "triangular", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "waves", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "wood", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "wrinkles", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "agate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "aoi", len)) i = len; /* Objects */ - else if (STR_LITERAL_STARTSWITH(string, "background", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "superellipsoid", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "bicubic_patch", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "blob", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "box", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "camera", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cone", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "julia_fractal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "height_field", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cubic_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sphere_sweep", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "light_group", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "light_source", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "intersection", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "isosurface", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "background", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sky_sphere", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "cylinder", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "difference", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "brilliance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "parametric", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "interunion", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "intermerge", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "polynomial", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "displace", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "specular", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ambient", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "diffuse", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "polygon", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "quadric", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "quartic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rainbow", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sphere", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "prism", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "galley", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "phong", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cone", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "blob", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "box", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "disc", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fog", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "height_field", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "intersection", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "isosurface", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "julia_fractal", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "lathe", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "light_group", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "light_source", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "merge", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "mesh2", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "mesh", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "object", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "ovus", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "lemon", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "parametric", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "plane", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "poly", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "polygon", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "polynomial", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "prism", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "quadric", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "quartic", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rainbow", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sky_sphere", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "smooth_triangle", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cubic_spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sphere_sweep", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sphere", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "superellipsoid", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "irid", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "sor", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "text", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "torus", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "triangle", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "union", len)) i = len; - /* Filetypes */ - else if (STR_LITERAL_STARTSWITH(string, "df3", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "exr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "gif", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "hdr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "iff", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "jpeg", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pgm", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "png", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ppm", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sys", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tga", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tiff", len)) i = len; - /* Spline Identifiers */ - else if (STR_LITERAL_STARTSWITH(string, "b_spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "bezier_spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "conic_sweep", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cubic_spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "linear_spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "linear_sweep", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "natural_spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "quadratic_spline", len)) i = len; - /* Encodings */ - else if (STR_LITERAL_STARTSWITH(string, "ascii", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "utf8", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "uint8", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "uint16be", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "uint16le", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sint8", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sint16be", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sint16le", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sint32be", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sint32le", len)) i = len; - /* Camera Types */ - else if (STR_LITERAL_STARTSWITH(string, "fisheye", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "mesh_camera", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "omnimax", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "orthographic", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "panoramic", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "perspective", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ultra_wide_angle", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "colour", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "color", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "media", len)) i = len; /* Built-in Vectors */ else if (STR_LITERAL_STARTSWITH(string, "t", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "u", len)) i = len; @@ -442,7 +464,6 @@ static int txtfmt_pov_find_reserved_builtins(const char *string) else if (STR_LITERAL_STARTSWITH(string, "x", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "y", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "z", len)) i = len; - else i = 0; /* If next source char is an identifier (eg. 'i' in "definate") no match */ @@ -465,156 +486,201 @@ static int txtfmt_pov_find_specialvar(const char *string) { int i, len; /* Modifiers */ - if (STR_LITERAL_STARTSWITH(string, "interior_texture", len)) i = len; + if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "projected_through", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "double_illuminate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "expand_thresholds", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "media_interaction", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "media_attenuation", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "projected_through", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "low_error_factor", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "recursion_limit", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "interior_texture", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_trace_level", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gray_threshold", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pretrace_start", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "normal_indices", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "normal_vectors", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vertex_vectors", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "noise_generator", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "irid_wavelength", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "number_of_waves", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ambient_light", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inside_vector", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "face_indices", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "texture_list", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_gradient", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uv_indices", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uv_vectors", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fade_distance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "global_lights", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no_bump_scale", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pretrace_end", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no_radiosity", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no_reflection", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "assumed_gamma", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "scallop_wave", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "triangle_wave", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "nearest_count", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "maximum_reuse", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "minimum_reuse", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "always_sample", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "translucency", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "eccentricity", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "contained_by", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inside_point", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "adc_bailout", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "density_map", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "split_union", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mm_per_unit", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "agate_turb", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "bounded_by", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "brick_size", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "bump_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "bump_size", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "circular", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "clipped_by", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hf_gray_16", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dispersion", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "extinction", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "thickness", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "color_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "color", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "colour_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "colour", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "control0", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "control1", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "cubic_wave", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "density_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "density", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fade_color", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fade_colour", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fade_distance", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fade_power", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "frequency", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "global_lights", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "hollow", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "image_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "adaptive", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "interior", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "interpolate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "inverse", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "jitter", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "lambda", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "map_type", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "material_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "material", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "matrix", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "media", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "mm_per_unit", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "mortar", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "no_bump_scale", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "no_image", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "no_radiosity", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "no_reflection", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "no_shadow", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fade_color", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "normal_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "normal", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "octaves", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "omega", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "once", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "orient", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "parallel", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "phase", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "photons", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "pigment_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pigment", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "finish", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "poly_wave", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "quick_color", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "quick_colour", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ramp_wave", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rotate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "scale", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "scallop_wave", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "shadowless", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sine_wave", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "slope_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "subsurface", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "material_map", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pass_through", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "interpolate", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "texture_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "texture", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "transform", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "translate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "triangle_wave", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "turbulence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "error_bound", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "brightness", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "use_color", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "use_alpha", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "use_colour", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "use_index", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "uv_mapping", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "warp", len)) i = len; - - /* Vector Functions */ - else if (STR_LITERAL_STARTSWITH(string, "max_extent", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "min_extent", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "trace", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vaxis_rotate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vcross", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vnormalize", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vrotate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vturbulence", len)) i = len; - /* String Functions */ - else if (STR_LITERAL_STARTSWITH(string, "chr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "concat", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "datetime", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "str", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "strlwr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "strupr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "substr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vstr", len)) i = len; - /* Float Functions */ - else if (STR_LITERAL_STARTSWITH(string, "abs", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "acosh", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "acos", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "asc", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "asinh", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "asin", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "atan2", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "atand", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "atanh", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "atan", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "bitwise_and", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "bitwise_or", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "bitwise_xor", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ceil", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cosh", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cos", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "defined", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "degrees", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "dimension_size", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "dimensions", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "div", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "exp", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "file_exists", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "floor", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "inside", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "int", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ln", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "log", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "min", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "mod", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pow", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "radians", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rand", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "seed", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "select", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sinh", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sin", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sqrt", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sqr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "strcmp", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "strlen", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tanh", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tan", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "val", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vdot", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vlength", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "importance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_sample", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "intervals", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sine_wave", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "slope_map", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "poly_wave", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no_shadow", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ramp_wave", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "precision", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "original", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "accuracy", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "map_type", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no_image", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "distance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "autostop", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "caustics", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "octaves", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "aa_level", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "frequency", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fog_offset", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "modulation", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "outbound", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no_cache", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pigment", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "charset", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inbound", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "outside", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inner", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "turbulence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "threshold", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "accuracy", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "polarity", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bump_size", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "circular", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "control0", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "control1", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "maximal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "minimal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fog_type", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fog_alt", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "samples", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "origin", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "amount", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "adaptive", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "exponent", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "strength", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "density", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fresnel", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "albinos", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "finish", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "method", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "omega", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fixed", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "spacing", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "u_steps", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "v_steps", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "offset", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hollow", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gather", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lambda", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mortar", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "count", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "once", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "orient", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "normal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "phase", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ratio", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "open", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ior", len)) i = len; + /* Light Types and options*/ + else if (STR_LITERAL_STARTSWITH(string, "area_light", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "looks_like", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fade_power", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tightness", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "spotlight", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "parallel", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "point_at", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "falloff", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "radius", len)) i = len; + /* Camera Types and options*/ + else if (STR_LITERAL_STARTSWITH(string, "omni_directional_stereo", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lambert_cylindrical", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "miller_cylindrical", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lambert_azimuthal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ultra_wide_angle", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_direction", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_location ", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "van_der_grinten", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "aitoff_hammer", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "smyth_craster", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "orthographic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_right", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "blur_samples", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "plate_carree", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_type", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "perspective", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mesh_camera", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "focal_point", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "balthasart", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "confidence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "parallaxe", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hobo_dyer", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_up", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "panoramic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "eckert_vi", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "eckert_iv", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mollweide", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "aperture", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "behrmann", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "variance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "stereo", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "icosa", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tetra", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "octa", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mercator", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "omnimax", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fisheye", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "edwards", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "peters", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gall", len)) i = len; else i = 0; /* If next source char is an identifier (eg. 'i' in "definate") no match */ @@ -625,15 +691,43 @@ static int txtfmt_pov_find_bool(const char *string) { int i, len; /*Built-in Constants*/ - if (STR_LITERAL_STARTSWITH(string, "false", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "no", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "off", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "true", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "yes", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "on", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pi", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tau", len)) i = len; - else i = 0; + if (STR_LITERAL_STARTSWITH(string, "unofficial", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "false", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "off", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "true", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "yes", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "on", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pi", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tau", len)) i = len; + /* Encodings */ + else if (STR_LITERAL_STARTSWITH(string, "sint16be", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sint16le", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sint32be", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sint32le", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uint16be", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uint16le", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bt2020", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bt709", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sint8", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uint8", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ascii", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "utf8", len)) i = len; + /* Filetypes */ + else if (STR_LITERAL_STARTSWITH(string, "tiff", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "df3", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "exr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gif", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hdr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "iff", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "jpeg", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pgm", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "png", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ppm", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sys", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tga", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ttf", len)) i = len; + else i = 0; /* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */ return (i == 0 || text_check_identifier(string[i])) ? -1 : i; @@ -645,7 +739,7 @@ static char txtfmt_pov_format_identifier(const char *str) if ((txtfmt_pov_find_specialvar(str)) != -1) fmt = FMT_TYPE_SPECIAL; else if ((txtfmt_pov_find_keyword(str)) != -1) fmt = FMT_TYPE_KEYWORD; else if ((txtfmt_pov_find_reserved_keywords(str)) != -1) fmt = FMT_TYPE_RESERVED; - else if ((txtfmt_pov_find_reserved_builtins(str)) != -1) fmt = FMT_TYPE_RESERVED; + else if ((txtfmt_pov_find_reserved_builtins(str)) != -1) fmt = FMT_TYPE_DIRECTIVE; else fmt = FMT_TYPE_DEFAULT; return fmt; } @@ -770,7 +864,7 @@ static void txtfmt_pov_format_line(SpaceText *st, TextLine *line, const bool do_ if ((i = txtfmt_pov_find_specialvar(str)) != -1) prev = FMT_TYPE_SPECIAL; else if ((i = txtfmt_pov_find_keyword(str)) != -1) prev = FMT_TYPE_KEYWORD; else if ((i = txtfmt_pov_find_reserved_keywords(str)) != -1) prev = FMT_TYPE_RESERVED; - else if ((i = txtfmt_pov_find_reserved_builtins(str)) != -1) prev = FMT_TYPE_RESERVED; + else if ((i = txtfmt_pov_find_reserved_builtins(str)) != -1) prev = FMT_TYPE_DIRECTIVE; if (i > 0) { text_format_fill_ascii(&str, &fmt, prev, i); diff --git a/source/blender/editors/space_text/text_format_pov_ini.c b/source/blender/editors/space_text/text_format_pov_ini.c index 719f4e3c036..453dd1d748c 100644 --- a/source/blender/editors/space_text/text_format_pov_ini.c +++ b/source/blender/editors/space_text/text_format_pov_ini.c @@ -49,36 +49,36 @@ static int txtfmt_ini_find_keyword(const char *string) { int i, len; /* Language Directives */ - if (STR_LITERAL_STARTSWITH(string, "append", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "debug", len)) i = len; + if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "declare", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "default", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "version", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "warning", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "include", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fclose", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ifndef", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "append", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "elseif", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "end", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "debug", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "error", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fclose", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fopen", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "ifdef", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ifndef", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "include", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "local", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "macro", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "range", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "read", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "render", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "switch", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "undef", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "version", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "warning", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "write", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "read", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "end", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "I", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "S", len)) i = len; @@ -104,29 +104,54 @@ static int txtfmt_ini_find_reserved(const char *string) * list is from... * http://www.povray.org/documentation/view/3.7.0/212/ */ - if (STR_LITERAL_STARTSWITH(string, "Antialias_Threshold", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Bounding_Method", len)) i = len; + if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Create_Continue_Trace_Log", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSoundEnabled", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSoundEnabled", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "HideWhenMainMinimized", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Antialias_Confidence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSound", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSound", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSound", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "UseExtensions", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ReadWriteSourceDir", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "NormalPositionLeft", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "NormalPositionTop", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "NormalPositionRight", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "NormalPositionBottom", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Pre_Scene_Command", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Pre_Frame_Command", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Post_Scene_Command", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Post_Frame_Command", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "User_Abort_Command", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Fatal_Error_Command", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "NormalPositionX", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "NormalPositionY", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Pre_Scene_Return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Pre_Frame_Return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Post_Scene_Return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Post_Frame_Return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "User_Abort_Return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Fatal_Error_Return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Antialias_Threshold", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Antialias_Gamma", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Antialias_Depth", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "clock_delta", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "clock_on", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "clock", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "final_clock", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "final_frame", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "frame_number", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "initial_clock", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "initial_frame", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "image_height", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "image_width", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "input_file_name", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Subset_Start_Frame", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Subset_End_Frame", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "UseToolbar", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "UseTooltips", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Frame_Step", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Cyclic_Animation", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Field_Render", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Odd_Field", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Height", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Width", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "final_clock", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "final_frame", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "frame_number", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "initial_clock", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "initial_frame", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "image_height", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "image_width", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Start_Column", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Start_Row", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "End_Column", len)) i = len; @@ -134,7 +159,7 @@ static int txtfmt_ini_find_reserved(const char *string) else if (STR_LITERAL_STARTSWITH(string, "Test_Abort_Count", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Test_Abort", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Continue_Trace", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Create_Continue_Trace_Log", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Bounding_Method", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Create_Ini", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Display_Gamma", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Display", len)) i = len; @@ -151,19 +176,6 @@ static int txtfmt_ini_find_reserved(const char *string) else if (STR_LITERAL_STARTSWITH(string, "Bits_Per_Color", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Compression", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Dither_Method", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Dither", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Pre_Scene_Command", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Pre_Frame_Command", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Post_Scene_Command", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Post_Frame_Command", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "User_Abort_Command", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Fatal_Error_Command", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Pre_Scene_Return", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Pre_Frame_Return", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Post_Scene_Return", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Post_Frame_Return", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "User_Abort_Return", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Fatal_Error_Return", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Include_Header", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Library_Path", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Debug_Console", len)) i = len; @@ -187,7 +199,9 @@ static int txtfmt_ini_find_reserved(const char *string) else if (STR_LITERAL_STARTSWITH(string, "Remove_Bounds", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Split_Unions", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Antialias", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Glare_Desaturation", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Sampling_Method", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Stochastic_Seed", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Jitter_Amount", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Jitter", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Antialias_Depth", len)) i = len; @@ -221,25 +235,14 @@ static int txtfmt_ini_find_reserved(const char *string) else if (STR_LITERAL_STARTSWITH(string, "Band3Width", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Band4Width", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "ShowCmd", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "NormalPositionLeft", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "NormalPositionTop", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "NormalPositionRight", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "NormalPositionBottom", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "UseToolbar", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "UseTooltips", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "NormalPositionX", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "NormalPositionY", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Flags", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Transparency", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Use8BitMode", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "MakeActive", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "KeepAboveMain", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "HideWhenMainMinimized", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "AutoClose", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "PreserveBitmap", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "FontSize", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "FontWeight", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Font", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "KeepMessages", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "AlertSound", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Completion", len)) i = len; @@ -250,14 +253,6 @@ static int txtfmt_ini_find_reserved(const char *string) else if (STR_LITERAL_STARTSWITH(string, "PreventSleep", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "NoShelloutWait", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "SystemNoActive", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSoundEnabled", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSoundEnabled", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSound", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSound", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSound", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "UseExtensions", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ReadWriteSourceDir", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "NoShellOuts", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "VideoSource", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "SceneFile", len)) i = len; @@ -269,6 +264,14 @@ static int txtfmt_ini_find_reserved(const char *string) else if (STR_LITERAL_STARTSWITH(string, "RenderwinClose", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Append_File", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Warning Level", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clock_delta", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clock_on", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clock", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Height", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Width", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Dither", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Flags", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Font", len)) i = len; /* Filetypes */ else if (STR_LITERAL_STARTSWITH(string, "df3", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "exr", len)) i = len; diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 15eb154c757..f29d2b30ffe 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -329,6 +329,8 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) case ID_CF: cachefile_to_keylist(&ads, (CacheFile *)id, &keys, NULL); break; + default: + break; } /* build linked-list for searching */ diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 73fd77db477..5f01092f5b0 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -8457,8 +8457,8 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec else { Mesh *me = ob->data; if ((me->editflag & ME_EDIT_PAINT_VERT_SEL) && - /* currently vertex select only supports weight paint */ - (ob->mode & OB_MODE_WEIGHT_PAINT)) + /* currently vertex select supports weight paint and vertex paint*/ + ((ob->mode & OB_MODE_WEIGHT_PAINT) || (ob->mode & OB_MODE_VERTEX_PAINT))) { bbs_mesh_solid_verts(scene, ob); } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index b8228c63209..996506a9cf7 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1412,33 +1412,31 @@ static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_i } } } - if ((ID *)v3d->ob_centre == old_id) { - v3d->ob_centre = (Object *)new_id; - if (new_id == NULL) { /* Otherwise, bonename may remain valid... We could be smart and check this, too? */ - v3d->ob_centre_bone[0] = '\0'; - } - } - if ((ID *)v3d->defmaterial == old_id) { - v3d->defmaterial = (Material *)new_id; - } -#if 0 /* XXX Deprecated? */ - if ((ID *)v3d->gpd == old_id) { - v3d->gpd = (bGPData *)new_id; - } -#endif + /* Values in local-view aren't used, see: T52663 */ + if (is_local == false) { + /* Skip 'v3d->defmaterial', it's not library data. */ - if (ELEM(GS(old_id->name), ID_IM, ID_MC)) { - for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { - if ((ID *)bgpic->ima == old_id) { - bgpic->ima = (Image *)new_id; - id_us_min(old_id); - id_us_plus(new_id); + if ((ID *)v3d->ob_centre == old_id) { + v3d->ob_centre = (Object *)new_id; + /* Otherwise, bonename may remain valid... We could be smart and check this, too? */ + if (new_id == NULL) { + v3d->ob_centre_bone[0] = '\0'; } - if ((ID *)bgpic->clip == old_id) { - bgpic->clip = (MovieClip *)new_id; - id_us_min(old_id); - id_us_plus(new_id); + } + + if (ELEM(GS(old_id->name), ID_IM, ID_MC)) { + for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { + if ((ID *)bgpic->ima == old_id) { + bgpic->ima = (Image *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + if ((ID *)bgpic->clip == old_id) { + bgpic->clip = (MovieClip *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } } } } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 250e6559b8f..56508ea989a 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -2471,6 +2471,7 @@ static void view3d_draw_depth_loop(Scene *scene, ARegion *ar, View3D *v3d) void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride) { + struct bThemeState theme_state; RegionView3D *rv3d = ar->regiondata; short zbuf = v3d->zbuf; short flag = v3d->flag; @@ -2483,6 +2484,10 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */ U.obcenter_dia = 0; + /* Tools may request depth outside of regular drawing code. */ + UI_Theme_Store(&theme_state); + UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); + /* Setup view matrix. */ ED_view3d_draw_setup_view(NULL, scene, ar, v3d, rv3d->viewmat, rv3d->winmat, NULL); @@ -2510,6 +2515,8 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover U.glalphaclip = glalphaclip; v3d->flag = flag; U.obcenter_dia = obcenter_dia; + + UI_Theme_Restore(&theme_state); } void ED_view3d_draw_select_loop( @@ -2592,7 +2599,7 @@ static void gpu_render_lamp_update(Scene *scene, View3D *v3d, if (layers && GPU_lamp_has_shadow_buffer(lamp) && /* keep last, may do string lookup */ - GPU_lamp_override_visible(lamp, srl, NULL)) + GPU_lamp_visible(lamp, srl, NULL)) { shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow"); shadow->lamp = lamp; diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 4e3f279e12e..97fcca11962 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -726,10 +726,15 @@ static enum eViewOpsOrbit viewops_orbit_mode(void) /** * Calculate the values for #ViewOpsData + * + * \param use_ensure_persp: When enabled run #view3d_ensure_persp this may switch out of + * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled. + * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common + * so we don't want it to trigger auto-perspective). */ static void viewops_data_create_ex( bContext *C, wmOperator *op, const wmEvent *event, - bool switch_from_camera, enum eViewOpsOrbit orbit_mode) + bool use_ensure_persp, enum eViewOpsOrbit orbit_mode) { ViewOpsData *vod = op->customdata; RegionView3D *rv3d = vod->rv3d; @@ -750,8 +755,7 @@ static void viewops_data_create_ex( vod->use_dyn_ofs = false; } - if (switch_from_camera) { - /* switch from camera view when: */ + if (use_ensure_persp) { if (view3d_ensure_persp(vod->v3d, vod->ar)) { /* If we're switching from camera view to the perspective one, * need to tag viewport update, so camera vuew and borders @@ -853,10 +857,10 @@ static void viewops_data_create_ex( rv3d->rflag |= RV3D_NAVIGATING; } -static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event, bool switch_from_camera) +static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event, bool use_ensure_persp) { enum eViewOpsOrbit orbit_mode = viewops_orbit_mode(); - viewops_data_create_ex(C, op, event, switch_from_camera, orbit_mode); + viewops_data_create_ex(C, op, event, use_ensure_persp, orbit_mode); } static void viewops_data_free(bContext *C, wmOperator *op) @@ -1673,7 +1677,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) viewops_data_alloc(C, op); viewops_data_create_ex( C, op, event, - viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false), false); + false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); @@ -1742,7 +1746,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev viewops_data_alloc(C, op); viewops_data_create_ex( C, op, event, - viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false), false); + false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); vod = op->customdata; @@ -4753,13 +4757,20 @@ void ED_view3d_cursor3d_update(bContext *C, const int mval[2]) ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = ar->regiondata; - float co_curr[2], co_prev[2]; + if (U.uiflag & USER_LOCK_CURSOR_ADJUST) { - if ((ED_view3d_project_float_global(ar, fp_prev, co_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) && - (ED_view3d_project_float_global(ar, fp_curr, co_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK)) - { - rv3d->ofs_lock[0] += (co_curr[0] - co_prev[0]) / (ar->winx * 0.5f); - rv3d->ofs_lock[1] += (co_curr[1] - co_prev[1]) / (ar->winy * 0.5f); + float co_curr[2], co_prev[2]; + + if ((ED_view3d_project_float_global(ar, fp_prev, co_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) && + (ED_view3d_project_float_global(ar, fp_curr, co_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK)) + { + rv3d->ofs_lock[0] += (co_curr[0] - co_prev[0]) / (ar->winx * 0.5f); + rv3d->ofs_lock[1] += (co_curr[1] - co_prev[1]) / (ar->winy * 0.5f); + } + } + else { + /* Cursor may be outside of the view, prevent it getting 'lost', see: T40353 & T45301 */ + zero_v2(rv3d->ofs_lock); } } diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index bf1bdf68619..70caee66b29 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -350,7 +350,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) PointerRNA meshptr; RNA_pointer_create(ob->data, &RNA_Mesh, ob->data, &meshptr); - if (ob->mode & (OB_MODE_TEXTURE_PAINT | OB_MODE_VERTEX_PAINT)) { + if (ob->mode & (OB_MODE_TEXTURE_PAINT)) { uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); } else { diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index aefe30bbe32..714db0db0ff 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -48,7 +48,6 @@ #include "ED_screen.h" #include "ED_view3d.h" -#include "ED_transform.h" #include "ED_transform_snap_object_context.h" #include "ED_space_api.h" diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 5c13fd37dda..16b626a5be4 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -54,6 +54,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "UI_resources.h" + #include "GPU_select.h" #include "WM_api.h" @@ -812,19 +814,108 @@ bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb) return view3d_boundbox_clip_m4(bb, rv3d->persmatob); } -float ED_view3d_depth_read_cached(const ViewContext *vc, int x, int y) +/* -------------------------------------------------------------------- */ + +/** \name Depth Utilities + * \{ */ + +float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2]) { ViewDepths *vd = vc->rv3d->depths; - x -= vc->ar->winrct.xmin; - y -= vc->ar->winrct.ymin; + int x = mval[0]; + int y = mval[1]; - if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) + if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) { return vd->depths[y * vd->w + x]; - else - return 1; + } + else { + BLI_assert(1.0 <= vd->depth_range[1]); + return 1.0f; + } +} + +bool ED_view3d_depth_read_cached_normal( + const ViewContext *vc, const bglMats *mats, const int mval[2], + float r_normal[3]) +{ + /* Note: we could support passing in a radius. + * For now just read 9 pixels. */ + + /* pixels surrounding */ + bool depths_valid[9] = {false}; + float coords[9][3] = {{0}}; + + ARegion *ar = vc->ar; + const ViewDepths *depths = vc->rv3d->depths; + + for (int x = 0, i = 0; x < 2; x++) { + for (int y = 0; y < 2; y++) { + const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)}; + + const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs); + if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { + if (ED_view3d_depth_unproject(ar, mats, mval_ofs, depth, coords[i])) { + depths_valid[i] = true; + } + } + i++; + } + } + + const int edges[2][6][2] = { + /* x edges */ + {{0, 1}, {1, 2}, + {3, 4}, {4, 5}, + {6, 7}, {7, 8}}, + /* y edges */ + {{0, 3}, {3, 6}, + {1, 4}, {4, 7}, + {2, 5}, {5, 8}}, + }; + + float cross[2][3] = {{0.0f}}; + + for (int i = 0; i < 6; i++) { + for (int axis = 0; axis < 2; axis++) { + if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) { + float delta[3]; + sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]); + add_v3_v3(cross[axis], delta); + } + } + } + + cross_v3_v3v3(r_normal, cross[0], cross[1]); + + if (normalize_v3(r_normal) != 0.0f) { + return true; + } + else { + return false; + } } +bool ED_view3d_depth_unproject( + const ARegion *ar, const bglMats *mats, + const int mval[2], const double depth, + float r_location_world[3]) +{ + double p[3]; + if (gluUnProject( + (double)ar->winrct.xmin + mval[0] + 0.5, + (double)ar->winrct.ymin + mval[1] + 0.5, + depth, mats->modelview, mats->projection, (const GLint *)mats->viewport, + &p[0], &p[1], &p[2])) + { + copy_v3fl_v3db(r_location_world, p); + return true; + } + return false; +} + +/** \} */ + void ED_view3d_depth_tag_update(RegionView3D *rv3d) { if (rv3d->depths) @@ -1117,6 +1208,7 @@ int view3d_opengl_select( ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, eV3DSelectMode select_mode) { + struct bThemeState theme_state; Scene *scene = vc->scene; View3D *v3d = vc->v3d; ARegion *ar = vc->ar; @@ -1161,6 +1253,10 @@ int view3d_opengl_select( } } + /* Tools may request depth outside of regular drawing code. */ + UI_Theme_Store(&theme_state); + UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); + /* Re-use cache (rect must be smaller then the cached) * other context is assumed to be unchanged */ if (GPU_select_is_cached()) { @@ -1213,6 +1309,8 @@ int view3d_opengl_select( finally: if (hits < 0) printf("Too many objects in select buffer\n"); /* XXX make error message */ + UI_Theme_Restore(&theme_state); + return hits; } diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 542dc410bc3..5248a260617 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -49,7 +49,6 @@ #include "ED_screen.h" #include "ED_space_api.h" -#include "ED_transform.h" #include "ED_transform_snap_object_context.h" #include "PIL_time.h" /* smoothview */ @@ -674,16 +673,6 @@ static int walkEnd(bContext *C, WalkInfo *walk) return OPERATOR_CANCELLED; } -static bool wm_event_is_last_mousemove(const wmEvent *event) -{ - while ((event = event->next)) { - if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { - return false; - } - } - return true; -} - static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent *event) { if (event->type == TIMER && event->customdata == walk->timer) { @@ -736,7 +725,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent } else #endif - if (wm_event_is_last_mousemove(event)) { + if (WM_event_is_last_mousemove(event)) { wmWindow *win = CTX_wm_window(C); #ifdef __APPLE__ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index ca6e2267218..c2f04005e83 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -51,7 +51,7 @@ #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_ghash.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_memarena.h" #include "BKE_nla.h" @@ -2878,7 +2878,9 @@ static void initBend(TransInfo *t) t->flag |= T_NO_CONSTRAINT; //copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view)); - calculateCenterCursor(t, t->center); + if ((t->flag & T_OVERRIDE_CENTER) == 0) { + calculateCenterCursor(t, t->center); + } calculateCenterGlobal(t, t->center, t->center_global); t->val = 0.0f; @@ -8360,8 +8362,15 @@ static void initTimeSlide(TransInfo *t) TransData *td = t->data; for (i = 0; i < t->total; i++, td++) { - if (min > *(td->val)) min = *(td->val); - if (max < *(td->val)) max = *(td->val); + AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; + float val = *(td->val); + + /* strip/action time to global (mapped) time */ + if (adt) + val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP); + + if (min > val) min = val; + if (max < val) max = val; } if (min == max) { @@ -8436,25 +8445,38 @@ static void applyTimeSlideValue(TransInfo *t, float sval) */ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; float cval = t->values[0]; - - /* apply NLA-mapping to necessary values */ - if (adt) - cval = BKE_nla_tweakedit_remap(adt, cval, NLATIME_CONVERT_UNMAP); - + /* only apply to data if in range */ if ((sval > minx) && (sval < maxx)) { float cvalc = CLAMPIS(cval, minx, maxx); + float ival = td->ival; float timefac; - + + /* NLA mapping magic here works as follows: + * - "ival" goes from strip time to global time + * - calculation is performed into td->val in global time + * (since sval and min/max are all in global time) + * - "td->val" then gets put back into strip time + */ + if (adt) { + /* strip to global */ + ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP); + } + /* left half? */ - if (td->ival < sval) { - timefac = (sval - td->ival) / (sval - minx); + if (ival < sval) { + timefac = (sval - ival) / (sval - minx); *(td->val) = cvalc - timefac * (cvalc - minx); } else { - timefac = (td->ival - sval) / (maxx - sval); + timefac = (ival - sval) / (maxx - sval); *(td->val) = cvalc + timefac * (maxx - cvalc); } + + if (adt) { + /* global to strip */ + *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP); + } } } } @@ -8513,9 +8535,11 @@ static void initTimeScale(TransInfo *t) /* recalculate center2d to use CFRA and mouse Y, since that's * what is used in time scale */ - t->center[0] = t->scene->r.cfra; - projectFloatView(t, t->center, center); - center[1] = t->mouse.imval[1]; + if ((t->flag & T_OVERRIDE_CENTER) == 0) { + t->center[0] = t->scene->r.cfra; + projectFloatView(t, t->center, center); + center[1] = t->mouse.imval[1]; + } /* force a reinit with the center2d used here */ initMouseInput(t, &t->mouse, center, t->mouse.imval, false); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index d60eb2f0778..06a60456cdb 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -533,6 +533,9 @@ typedef struct TransInfo { /* alternative transformation. used to add offset to tracking markers */ #define T_ALT_TRANSFORM (1 << 24) + /** #TransInfo.center has been set, don't change it. */ +#define T_OVERRIDE_CENTER (1 << 25) + /* TransInfo->modifiers */ #define MOD_CONSTRAINT_SELECT 0x01 #define MOD_PRECISION 0x02 diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index d7b670b6476..5621eede543 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -831,6 +831,13 @@ static void drawObjectConstraint(TransInfo *t) } } + if (t->options & CTX_GPENCIL_STROKES) { + /* only draw a constraint line for one point, otherwise we can't see anything */ + if ((options & DRAWLIGHT) == 0) { + break; + } + } + if (t->flag & T_OBJECT) { copy_v3_v3(co, td->ob->obmat[3]); axismtx = td->axismtx; diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 4429d19613a..9d63afeb85c 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -807,7 +807,6 @@ static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen) /* change the chain-length of auto-ik */ void transform_autoik_update(TransInfo *t, short mode) { - const short old_len = t->settings->autoik_chainlen; short *chainlen = &t->settings->autoik_chainlen; bPoseChannel *pchan; @@ -818,12 +817,13 @@ void transform_autoik_update(TransInfo *t, short mode) } else if (mode == -1) { /* mode==-1 is from WHEELMOUSEUP... decreases len */ - if (*chainlen > 0) (*chainlen)--; - } - - /* IK length did not change, skip any updates. */ - if (old_len == *chainlen) { - return; + if (*chainlen > 0) { + (*chainlen)--; + } + else { + /* IK length did not change, skip updates. */ + return; + } } /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */ @@ -2801,7 +2801,7 @@ void flushTransSeq(TransInfo *t) tdsq = (TransDataSeq *)td->extra; seq = tdsq->seq; old_start = seq->start; - new_frame = iroundf(td2d->loc[0]); + new_frame = round_fl_to_int(td2d->loc[0]); switch (tdsq->sel_flag) { case SELECT: @@ -2813,7 +2813,7 @@ void flushTransSeq(TransInfo *t) seq->start = new_frame - tdsq->start_offset; #endif if (seq->depth == 0) { - seq->machine = iroundf(td2d->loc[1]); + seq->machine = round_fl_to_int(td2d->loc[1]); CLAMP(seq->machine, 1, MAXSEQ); } break; @@ -3761,7 +3761,7 @@ void flushTransIntFrameActionData(TransInfo *t) /* flush data! */ for (i = 0; i < t->total; i++, tfd++) { - *(tfd->sdata) = iroundf(tfd->val); + *(tfd->sdata) = round_fl_to_int(tfd->val); } } @@ -4789,7 +4789,7 @@ void flushTransGraphData(TransInfo *t) /* if int-values only, truncate to integers */ if (td->flag & TD_INTVALUES) - td2d->loc2d[1] = floorf(td2d->loc[1] + 0.5f); + td2d->loc2d[1] = floorf(td2d->loc[1] * inv_unit_scale - tdg->offset + 0.5f); else td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset; @@ -5606,9 +5606,7 @@ static void set_trans_object_base_flags(TransInfo *t) } /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ -#ifdef WITH_LEGACY_DEPSGRAPH DAG_scene_flush_update(G.main, t->scene, -1, 0); -#endif /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ @@ -5687,9 +5685,7 @@ static int count_proportional_objects(TransInfo *t) /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ DAG_scene_relations_update(G.main, t->scene); -#ifdef WITH_LEGACY_DEPSGRAPH DAG_scene_flush_update(G.main, t->scene, -1, 0); -#endif /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ @@ -5976,27 +5972,23 @@ static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) { SpaceClip *sc = t->sa->spacedata.first; MovieClip *clip = ED_space_clip_get_clip(sc); - MovieTrackingPlaneTrack *plane_track; ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); - int framenr = ED_space_clip_get_clip_frame_number(sc); - - for (plane_track = plane_tracks_base->first; + const int framenr = ED_space_clip_get_clip_frame_number(sc); + /* Update coordinates of modified plane tracks. */ + for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) { bool do_update = false; - if (plane_track->flag & PLANE_TRACK_HIDDEN) { continue; } - do_update |= PLANE_TRACK_VIEW_SELECTED(plane_track) != 0; if (do_update == false) { if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) { int i; for (i = 0; i < plane_track->point_tracksnr; i++) { MovieTrackingTrack *track = plane_track->point_tracks[i]; - if (TRACK_VIEW_SELECTED(sc, track)) { do_update = true; break; @@ -6004,15 +5996,14 @@ static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) } } } - if (do_update) { BKE_tracking_track_plane_from_existing_motion(plane_track, framenr); } } - - if (t->scene->nodetree) { - /* tracks can be used for stabilization nodes, - * flush update for such nodes */ + if (t->scene->nodetree != NULL) { + /* Tracks can be used for stabilization nodes, + * flush update for such nodes. + */ nodeUpdateID(t->scene->nodetree, &clip->id); WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL); } @@ -7840,7 +7831,7 @@ static void createTransGPencil(bContext *C, TransInfo *t) float mtx[3][3], smtx[3][3]; const Scene *scene = CTX_data_scene(C); - const int cfra = CFRA; + const int cfra_scene = CFRA; const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0; @@ -7865,7 +7856,7 @@ static void createTransGPencil(bContext *C, TransInfo *t) if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf = gpl->actframe; bGPDstroke *gps; - + for (gps = gpf->strokes.first; gps; gps = gps->next) { /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) { @@ -7921,6 +7912,7 @@ static void createTransGPencil(bContext *C, TransInfo *t) for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene; bGPDframe *gpf = gpl->actframe; bGPDstroke *gps; float diff_mat[4][4]; @@ -7937,7 +7929,6 @@ static void createTransGPencil(bContext *C, TransInfo *t) * - This is useful when animating as it saves that "uh-oh" moment when you realize you've * spent too much time editing the wrong frame... */ - // XXX: should this be allowed when framelock is enabled? if (gpf->framenum != cfra) { gpf = BKE_gpencil_frame_addcopy(gpl, cfra); /* in some weird situations (framelock enabled) return NULL */ diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index c23da19f830..179b68dd270 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1331,7 +1331,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->current_orientation = V3D_MANIP_GLOBAL; } } - + if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && RNA_property_is_set(op->ptr, prop))) { @@ -1435,6 +1435,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve #endif setTransformViewAspect(t, t->aspect); + + if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_get_array(op->ptr, prop, t->center); + mul_v3_v3(t->center, t->aspect); + t->flag |= T_OVERRIDE_CENTER; + } + setTransformViewMatrices(t); initNumInput(&t->num); } @@ -1835,7 +1842,9 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[ void calculateCenter(TransInfo *t) { - calculateCenter_FromAround(t, t->around, t->center); + if ((t->flag & T_OVERRIDE_CENTER) == 0) { + calculateCenter_FromAround(t, t->around, t->center); + } calculateCenterGlobal(t, t->center, t->center_global); /* avoid calculating again */ @@ -1849,7 +1858,7 @@ void calculateCenter(TransInfo *t) calculateCenter2D(t); /* for panning from cameraview */ - if (t->flag & T_OBJECT) { + if ((t->flag & T_OBJECT) && (t->flag & T_OVERRIDE_CENTER) == 0) { if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) { if (t->flag & T_CAMERA) { diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index ec066ba91a4..9a362ee609f 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -107,15 +107,16 @@ #define TW_AXIS_DOT_MIN 0.02f #define TW_AXIS_DOT_MAX 0.1f +struct TransformBounds { + float center[3]; /* Center for transform widget. */ + float min[3], max[3]; /* Boundbox of selection for transform widget. */ +}; + /* transform widget center calc helper for below */ -static void calc_tw_center(Scene *scene, const float co[3]) +static void calc_tw_center(struct TransformBounds *tbounds, const float co[3]) { - float *twcent = scene->twcent; - float *min = scene->twmin; - float *max = scene->twmax; - - minmax_v3v3_v3(min, max, co); - add_v3_v3(twcent, co); + minmax_v3v3_v3(tbounds->min, tbounds->max, co); + add_v3_v3(tbounds->center, co); } static void protectflag_to_drawflags(short protectflag, short *drawflags) @@ -260,7 +261,7 @@ bool gimbal_axis(Object *ob, float gmat[3][3]) /* centroid, boundbox, of selection */ /* returns total items selected */ -static int calc_manipulator_stats(const bContext *C) +static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbounds) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); @@ -280,9 +281,9 @@ static int calc_manipulator_stats(const bContext *C) rv3d->twdrawflag = 0xFFFF; /* transform widget centroid/center */ - INIT_MINMAX(scene->twmin, scene->twmax); - zero_v3(scene->twcent); - + INIT_MINMAX(tbounds->min, tbounds->max); + zero_v3(tbounds->center); + if (is_gp_edit) { float diff_mat[4][4]; float fpt[3]; @@ -311,12 +312,12 @@ static int calc_manipulator_stats(const bContext *C) for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { if (gpl->parent == NULL) { - calc_tw_center(scene, &pt->x); + calc_tw_center(tbounds, &pt->x); totsel++; } else { mul_v3_m4v3(fpt, diff_mat, &pt->x); - calc_tw_center(scene, fpt); + calc_tw_center(tbounds, fpt); totsel++; } } @@ -329,7 +330,7 @@ static int calc_manipulator_stats(const bContext *C) /* selection center */ if (totsel) { - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); /* centroid! */ + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); } } else if (obedit) { @@ -344,7 +345,7 @@ static int calc_manipulator_stats(const bContext *C) /* USE LAST SELECTE WITH ACTIVE */ if ((v3d->around == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) { BM_editselection_center(&ese, vec); - calc_tw_center(scene, vec); + calc_tw_center(tbounds, vec); totsel = 1; } else { @@ -357,7 +358,7 @@ static int calc_manipulator_stats(const bContext *C) if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { totsel++; - calc_tw_center(scene, eve->co); + calc_tw_center(tbounds, eve->co); } } } @@ -370,13 +371,13 @@ static int calc_manipulator_stats(const bContext *C) if ((v3d->around == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) { /* doesn't check selection or visibility intentionally */ if (ebo->flag & BONE_TIPSEL) { - calc_tw_center(scene, ebo->tail); + calc_tw_center(tbounds, ebo->tail); totsel++; } if ((ebo->flag & BONE_ROOTSEL) || ((ebo->flag & BONE_TIPSEL) == false)) /* ensure we get at least one point */ { - calc_tw_center(scene, ebo->head); + calc_tw_center(tbounds, ebo->head); totsel++; } protectflag_to_drawflags_ebone(rv3d, ebo); @@ -385,7 +386,7 @@ static int calc_manipulator_stats(const bContext *C) for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { if (EBONE_VISIBLE(arm, ebo)) { if (ebo->flag & BONE_TIPSEL) { - calc_tw_center(scene, ebo->tail); + calc_tw_center(tbounds, ebo->tail); totsel++; } if ((ebo->flag & BONE_ROOTSEL) && @@ -395,7 +396,7 @@ static int calc_manipulator_stats(const bContext *C) (ebo->parent->flag & BONE_TIPSEL) && EBONE_VISIBLE(arm, ebo->parent)) == 0) { - calc_tw_center(scene, ebo->head); + calc_tw_center(tbounds, ebo->head); totsel++; } if (ebo->flag & BONE_SELECTED) { @@ -410,7 +411,7 @@ static int calc_manipulator_stats(const bContext *C) float center[3]; if (v3d->around == V3D_AROUND_ACTIVE && ED_curve_active_center(cu, center)) { - calc_tw_center(scene, center); + calc_tw_center(tbounds, center); totsel++; } else { @@ -431,21 +432,25 @@ static int calc_manipulator_stats(const bContext *C) */ if (cu->drawflag & CU_HIDE_HANDLES) { if (bezt->f2 & SELECT) { - calc_tw_center(scene, bezt->vec[1]); + calc_tw_center(tbounds, bezt->vec[1]); totsel++; } } else if (bezt->f2 & SELECT) { - calc_tw_center(scene, bezt->vec[1]); + calc_tw_center(tbounds, bezt->vec[1]); totsel++; } else { if (bezt->f1 & SELECT) { - calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); + calc_tw_center( + tbounds, + bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); totsel++; } if (bezt->f3 & SELECT) { - calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); + calc_tw_center( + tbounds, + bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); totsel++; } } @@ -457,7 +462,7 @@ static int calc_manipulator_stats(const bContext *C) a = nu->pntsu * nu->pntsv; while (a--) { if (bp->f1 & SELECT) { - calc_tw_center(scene, bp->vec); + calc_tw_center(tbounds, bp->vec); totsel++; } bp++; @@ -472,13 +477,13 @@ static int calc_manipulator_stats(const bContext *C) MetaElem *ml; if ((v3d->around == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) { - calc_tw_center(scene, &ml->x); + calc_tw_center(tbounds, &ml->x); totsel++; } else { for (ml = mb->editelems->first; ml; ml = ml->next) { if (ml->flag & SELECT) { - calc_tw_center(scene, &ml->x); + calc_tw_center(tbounds, &ml->x); totsel++; } } @@ -489,7 +494,7 @@ static int calc_manipulator_stats(const bContext *C) BPoint *bp; if ((v3d->around == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) { - calc_tw_center(scene, bp->vec); + calc_tw_center(tbounds, bp->vec); totsel++; } else { @@ -497,7 +502,7 @@ static int calc_manipulator_stats(const bContext *C) a = lt->pntsu * lt->pntsv * lt->pntsw; while (a--) { if (bp->f1 & SELECT) { - calc_tw_center(scene, bp->vec); + calc_tw_center(tbounds, bp->vec); totsel++; } bp++; @@ -507,10 +512,10 @@ static int calc_manipulator_stats(const bContext *C) /* selection center */ if (totsel) { - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid! - mul_m4_v3(obedit->obmat, scene->twcent); - mul_m4_v3(obedit->obmat, scene->twmin); - mul_m4_v3(obedit->obmat, scene->twmax); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_m4_v3(obedit->obmat, tbounds->center); + mul_m4_v3(obedit->obmat, tbounds->min); + mul_m4_v3(obedit->obmat, tbounds->max); } } else if (ob && (ob->mode & OB_MODE_POSE)) { @@ -524,7 +529,7 @@ static int calc_manipulator_stats(const bContext *C) /* doesn't check selection or visibility intentionally */ Bone *bone = pchan->bone; if (bone) { - calc_tw_center(scene, pchan->pose_head); + calc_tw_center(tbounds, pchan->pose_head); protectflag_to_drawflags_pchan(rv3d, pchan); totsel = 1; ok = true; @@ -538,7 +543,7 @@ static int calc_manipulator_stats(const bContext *C) for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { Bone *bone = pchan->bone; if (bone && (bone->flag & BONE_TRANSFORM)) { - calc_tw_center(scene, pchan->pose_head); + calc_tw_center(tbounds, pchan->pose_head); protectflag_to_drawflags_pchan(rv3d, pchan); } } @@ -547,10 +552,10 @@ static int calc_manipulator_stats(const bContext *C) } if (ok) { - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid! - mul_m4_v3(ob->obmat, scene->twcent); - mul_m4_v3(ob->obmat, scene->twmin); - mul_m4_v3(ob->obmat, scene->twmax); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_m4_v3(ob->obmat, tbounds->center); + mul_m4_v3(ob->obmat, tbounds->min); + mul_m4_v3(ob->obmat, tbounds->max); } } else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { @@ -569,7 +574,7 @@ static int calc_manipulator_stats(const bContext *C) for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) { if (ek->flag & PEK_SELECT) { - calc_tw_center(scene, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co); + calc_tw_center(tbounds, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co); totsel++; } } @@ -577,7 +582,7 @@ static int calc_manipulator_stats(const bContext *C) /* selection center */ if (totsel) - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid! + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); } } else { @@ -590,7 +595,7 @@ static int calc_manipulator_stats(const bContext *C) if (TESTBASELIB(v3d, base)) { if (ob == NULL) ob = base->object; - calc_tw_center(scene, base->object->obmat[3]); + calc_tw_center(tbounds, base->object->obmat[3]); protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); totsel++; } @@ -598,7 +603,7 @@ static int calc_manipulator_stats(const bContext *C) /* selection center */ if (totsel) { - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid! + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); } } @@ -1643,9 +1648,10 @@ void BIF_draw_manipulator(const bContext *C) if ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) == 0) return; { + struct TransformBounds tbounds; v3d->twflag &= ~V3D_DRAW_MANIPULATOR; - totsel = calc_manipulator_stats(C); + totsel = calc_manipulator_stats(C, &tbounds); if (totsel == 0) return; v3d->twflag |= V3D_DRAW_MANIPULATOR; @@ -1665,13 +1671,13 @@ void BIF_draw_manipulator(const bContext *C) copy_v3_v3(rv3d->twmat[3], ob->obmat[3]); } else { - mid_v3_v3v3(rv3d->twmat[3], scene->twmin, scene->twmax); + mid_v3_v3v3(rv3d->twmat[3], tbounds.min, tbounds.max); } break; } case V3D_AROUND_LOCAL_ORIGINS: case V3D_AROUND_CENTER_MEAN: - copy_v3_v3(rv3d->twmat[3], scene->twcent); + copy_v3_v3(rv3d->twmat[3], tbounds.center); break; case V3D_AROUND_CURSOR: copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d)); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 2a97384cf7d..1aa800f9fb1 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -565,6 +565,14 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) RNA_def_boolean(ot->srna, "correct_uv", 0, "Correct UVs", "Correct UV coordinates when transforming"); } + if (flags & P_CENTER) { + /* For manipulators that define their own center. */ + prop = RNA_def_property(ot->srna, "center_override", PROP_FLOAT, PROP_XYZ); + RNA_def_property_array(prop, 3); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + RNA_def_property_ui_text(prop, "Center Override", "Force using this center value (when set)"); + } + if ((flags & P_NO_DEFAULTS) == 0) { // Add confirm method all the time. At the end because it's not really that important and should be hidden only in log, not in keymap edit /*prop =*/ RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "Always confirm operation when releasing button"); @@ -612,7 +620,8 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot) RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT); + Transform_Properties( + ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT | P_CENTER); } static int skin_resize_poll(bContext *C) @@ -663,7 +672,7 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot) /* Maybe we could use float_vector_xyz here too? */ RNA_def_float_rotation(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_rotate(struct wmOperatorType *ot) @@ -683,7 +692,8 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot) RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); - Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT); + Transform_Properties( + ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_tilt(struct wmOperatorType *ot) @@ -726,7 +736,7 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot) RNA_def_float_rotation(ot->srna, "value", 1, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_shear(struct wmOperatorType *ot) @@ -767,7 +777,7 @@ static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot) RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Distance", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_CENTER); } static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot) @@ -810,7 +820,7 @@ static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot) RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_mirror(struct wmOperatorType *ot) @@ -828,7 +838,7 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot) ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; - Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT); + Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot) @@ -991,7 +1001,8 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot) RNA_def_float_vector(ot->srna, "value", 4, NULL, -FLT_MAX, FLT_MAX, "Values", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_GPENCIL_EDIT); + Transform_Properties( + ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER); } void transform_operatortypes(void) diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 318d2718969..4a7c2decf95 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1017,7 +1017,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here char node_border; - if (snapNodesTransform(t, t->mval, t->tsnap.modeSelect, loc, &dist_px, &node_border)) { + if (snapNodesTransform(t, t->mval, loc, &dist_px, &node_border)) { copy_v2_v2(t->tsnap.snapPoint, loc); t->tsnap.snapNodeBorder = node_border; @@ -1413,22 +1413,11 @@ static bool snapNodes( } bool snapNodesTransform( - TransInfo *t, const int mval[2], SnapSelect snap_select, + TransInfo *t, const int mval[2], float r_loc[2], float *r_dist_px, char *r_node_border) { return snapNodes( - t->settings, t->sa->spacedata.first, t->ar, mval, snap_select, - r_loc, r_dist_px, r_node_border); -} - -bool snapNodesContext( - bContext *C, const int mval[2], SnapSelect snap_select, - float r_loc[2], float *r_dist_px, char *r_node_border) -{ - Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - return snapNodes( - scene->toolsettings, CTX_wm_space_node(C), ar, mval, snap_select, + t->settings, t->sa->spacedata.first, t->ar, mval, t->tsnap.modeSelect, r_loc, r_dist_px, r_node_border); } @@ -1478,7 +1467,7 @@ void snapSequenceBounds(TransInfo *t, const int mval[2]) /* convert to frame range */ UI_view2d_region_to_view(&t->ar->v2d, mval[0], mval[1], &xmouse, &ymouse); - mframe = iroundf(xmouse); + mframe = round_fl_to_int(xmouse); /* now find the closest sequence */ frame = BKE_sequencer_find_next_prev_edit(t->scene, mframe, SEQ_SIDE_BOTH, true, false, true); diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 85833f54da6..1fdf7c67cff 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -139,43 +139,55 @@ struct SnapObjectContext { * \{ */ -#define ITER_SNAP_OBJECTS(use_obedit, ob, obmat, sctx, snap_select, obedit, CODE) \ - Base *base_act = sctx->scene->basact;\ - /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA\ - * which makes the loop skip it, even the derived mesh will never change\ - *\ - * To solve that problem, we do it first as an exception.\ - * */\ - if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) {\ - use_obedit = false;\ - ob = base_act->object;\ - obmat = ob->obmat;\ - CODE\ - }\ - for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) {\ - if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) &&\ - (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&\ - !((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL))) ||\ - (snap_select == SNAP_NOT_ACTIVE && base == base_act)))\ - {\ - Object *obj = base->object;\ - if (ob->transflag & OB_DUPLI) {\ - DupliObject *dupli_ob;\ - ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, obj);\ - for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {\ - use_obedit = obedit && dupli_ob->ob->data == obedit->data;;\ - ob = use_obedit ? obedit : dupli_ob->ob;\ - obmat = dupli_ob->mat;\ - CODE\ - }\ - free_object_duplilist(lb);\ - }\ - use_obedit = obedit && ob->data == obedit->data;\ - ob = use_obedit ? obedit : obj;\ - obmat = ob->obmat;\ - CODE\ - }\ - }\ +typedef void(*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data); + +/** + * Walks through all objects in the scene to create the list of objets to snap. + * + * \param sctx: Snap context to store data. + * \param snap_select : from enum SnapSelect. + * \param obedit : Object Edited to use its coordinates of BMesh(if any) to do the snapping. + */ +static void iter_snap_objects( + SnapObjectContext *sctx, + const SnapSelect snap_select, + Object *obedit, + IterSnapObjsCallback sob_callback, + void *data) +{ + Base *base_act = sctx->scene->basact; + /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA + * which makes the loop skip it, even the derived mesh will never change + * + * To solve that problem, we do it first as an exception. + * */ + if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) { + sob_callback(sctx, false, base_act->object, base_act->object->obmat, data); + } + + for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) { + if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) && + (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && + !((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL))) || + (snap_select == SNAP_NOT_ACTIVE && base == base_act))) + { + bool use_obedit; + Object *obj = base->object; + if (obj->transflag & OB_DUPLI) { + DupliObject *dupli_ob; + ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, obj); + for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { + use_obedit = obedit && dupli_ob->ob->data == obedit->data; + sob_callback(sctx, use_obedit, use_obedit ? obedit : dupli_ob->ob, dupli_ob->mat, data); + } + free_object_duplilist(lb); + } + + use_obedit = obedit && obj->data == obedit->data; + sob_callback(sctx, use_obedit, use_obedit ? obedit : obj, obj->obmat, data); + } + } +} /** @@ -353,7 +365,7 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH static bool raycastDerivedMesh( SnapObjectContext *sctx, - const float ray_orig[3], const float ray_start[3], const float ray_dir[3], const float depth_range[2], + const float ray_start[3], const float ray_dir[3], Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index, /* read/write args */ float *ray_depth, @@ -393,7 +405,7 @@ static bool raycastDerivedMesh( if (bb) { /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ if (!isect_ray_aabb_v3_simple( - ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, NULL)) + ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, NULL)) { return retval; } @@ -424,21 +436,18 @@ static bool raycastDerivedMesh( free_bvhtree_from_mesh(treedata); } else { - if (!treedata->vert_allocated) { + if (treedata->vert == NULL) { treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated); } - if (!treedata->loop_allocated) { + if (treedata->loop == NULL) { treedata->loop = DM_get_loop_array(dm, &treedata->loop_allocated); } - if (!treedata->looptri_allocated) { - if (!sod->poly_allocated) { + if (treedata->looptri == NULL) { + if (sod->mpoly == NULL) { sod->mpoly = DM_get_poly_array(dm, &sod->poly_allocated); } - treedata->looptri = DM_get_looptri_array( - dm, treedata->vert, - sod->mpoly, dm->getNumPolys(dm), - treedata->loop, dm->getNumLoops(dm), - &treedata->looptri_allocated); + treedata->looptri = dm->getLoopTriArray(dm); + treedata->looptri_allocated = false; } } } @@ -462,8 +471,7 @@ static bool raycastDerivedMesh( if (len_diff == 0.0f) { /* do_ray_start_correction */ /* We *need* a reasonably valid len_diff in this case. * Get the distance to bvhtree root */ - if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) - { + if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) { return retval; } } @@ -471,18 +479,11 @@ static bool raycastDerivedMesh( * because even in the Orthografic view, in some cases, * the ray can start inside the object (see T50486) */ if (len_diff > 400.0f) { - float ray_org_local[3]; - - copy_v3_v3(ray_org_local, ray_orig); - mul_m4_v3(imat, ray_org_local); - /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with * very far away ray_start values (as returned in case of ortho view3d), see T38358. */ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl( - ray_start_local, ray_org_local, ray_normal_local, - len_diff + depth_range[0] * local_scale); + madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff); local_depth -= len_diff; } else { @@ -512,8 +513,8 @@ static bool raycastDerivedMesh( BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; if (BLI_bvhtree_ray_cast( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - &hit, treedata->raycast_callback, treedata) != -1) + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) { hit.dist += len_diff; hit.dist /= local_scale; @@ -544,7 +545,7 @@ static bool raycastDerivedMesh( static bool raycastEditMesh( SnapObjectContext *sctx, - const float ray_orig[3], const float ray_start[3], const float ray_dir[3], const float depth_range[2], + const float ray_start[3], const float ray_dir[3], Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index, /* read/write args */ float *ray_depth, @@ -558,8 +559,7 @@ static bool raycastEditMesh( } SnapObjectData_EditMesh *sod = NULL; - - BVHTreeFromEditMesh *treedata; + BVHTreeFromEditMesh *treedata = NULL; void **sod_p; if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { @@ -627,26 +627,18 @@ static bool raycastEditMesh( if (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp) { /* do_ray_start_correction */ /* We *need* a reasonably valid len_diff in this case. * Get the distance to bvhtree root */ - if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) - { + if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) { return retval; } /* You need to make sure that ray_start is really far away, * because even in the Orthografic view, in some cases, * the ray can start inside the object (see T50486) */ if (len_diff > 400.0f) { - float ray_org_local[3]; - - copy_v3_v3(ray_org_local, ray_orig); - mul_m4_v3(imat, ray_org_local); - /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with * very far away ray_start values (as returned in case of ortho view3d), see T38358. */ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl( - ray_start_local, ray_org_local, ray_normal_local, - len_diff + depth_range[0] * local_scale); + madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff); local_depth -= len_diff; } else len_diff = 0.0f; @@ -713,7 +705,7 @@ static bool raycastEditMesh( */ static bool raycastObj( SnapObjectContext *sctx, - const float ray_orig[3], const float ray_start[3], const float ray_dir[3], const float depth_range[2], + const float ray_start[3], const float ray_dir[3], Object *ob, float obmat[4][4], const unsigned int ob_index, bool use_obedit, /* read/write args */ @@ -732,7 +724,7 @@ static bool raycastObj( em = BKE_editmesh_from_object(ob); retval = raycastEditMesh( sctx, - ray_orig, ray_start, ray_dir, depth_range, + ray_start, ray_dir, ob, em, obmat, ob_index, ray_depth, r_loc, r_no, r_index, r_hit_list); } @@ -749,11 +741,9 @@ static bool raycastObj( } retval = raycastDerivedMesh( sctx, - ray_orig, ray_start, ray_dir, depth_range, + ray_start, ray_dir, ob, dm, obmat, ob_index, ray_depth, r_loc, r_no, r_index, r_hit_list); - - dm->release(dm); } } @@ -768,6 +758,35 @@ static bool raycastObj( } +struct RaycastObjUserData { + const float *ray_start; + const float *ray_dir; + unsigned int ob_index; + /* read/write args */ + float *ray_depth; + /* return args */ + float *r_loc; + float *r_no; + int *r_index; + Object **r_ob; + float (*r_obmat)[4]; + ListBase *r_hit_list; + bool ret; +}; + +static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data) +{ + struct RaycastObjUserData *dt = data; + dt->ret |= raycastObj( + sctx, + dt->ray_start, dt->ray_dir, + ob, obmat, dt->ob_index++, is_obedit, + dt->ray_depth, + dt->r_loc, dt->r_no, dt->r_index, + dt->r_ob, dt->r_obmat, + dt->r_hit_list); +} + /** * Main RayCast Function * ====================== @@ -799,7 +818,7 @@ static bool raycastObj( */ static bool raycastObjects( SnapObjectContext *sctx, - const float ray_orig[3], const float ray_start[3], const float ray_dir[3], const float depth_range[2], + const float ray_start[3], const float ray_dir[3], const SnapSelect snap_select, const bool use_object_edit_cage, /* read/write args */ float *ray_depth, @@ -808,24 +827,25 @@ static bool raycastObjects( Object **r_ob, float r_obmat[4][4], ListBase *r_hit_list) { - bool retval = false; - bool use_obedit; - - unsigned int ob_index = 0; - - Object *ob, *obedit; - float (*obmat)[4]; + Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; + + struct RaycastObjUserData data = { + .ray_start = ray_start, + .ray_dir = ray_dir, + .ob_index = 0, + .ray_depth = ray_depth, + .r_loc = r_loc, + .r_no = r_no, + .r_index = r_index, + .r_ob = r_ob, + .r_obmat = r_obmat, + .r_hit_list = r_hit_list, + .ret = false, + }; - obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; - ITER_SNAP_OBJECTS(use_obedit, ob, obmat, sctx, snap_select, obedit, - retval |= raycastObj( - sctx, - ray_orig, ray_start, ray_dir, depth_range, - ob, obmat, ob_index++, use_obedit, - ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); - ) + iter_snap_objects(sctx, snap_select, obedit, raycast_obj_cb, &data); - return retval; + return data.ret; } @@ -1045,36 +1065,20 @@ static float dist_squared_to_projected_aabb( main_axis += 3; } - /* if rtmin < rtmax, ray intersect `AABB` */ - if (rtmin <= rtmax) { #define IGNORE_BEHIND_RAY #ifdef IGNORE_BEHIND_RAY - /* `if rtmax < depth_min`, the hit is behind us */ - if (rtmax < data->ray_min_dist) { - /* Test if the entire AABB is behind us */ - float depth = depth_get( - local_bvmax, data->ray_origin_local, data->ray_direction_local); - if (depth < (data->ray_min_dist)) { - return FLT_MAX; - } - } -#endif - const float proj = rtmin * data->ray_direction_local[main_axis]; - r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj); - return 0.0f; - } -#ifdef IGNORE_BEHIND_RAY - /* `if rtmin < depth_min`, the hit is behing us */ - else if (rtmin < data->ray_min_dist) { - /* Test if the entire AABB is behind us */ - float depth = depth_get( - local_bvmax, data->ray_origin_local, data->ray_direction_local); - if (depth < (data->ray_min_dist)) { - return FLT_MAX; - } + float depth_max = depth_get(local_bvmax, data->ray_origin_local, data->ray_direction_local); + if (depth_max < data->ray_min_dist) { + return FLT_MAX; } #endif #undef IGNORE_BEHIND_RAY + + /* if rtmin <= rtmax, ray intersect `AABB` */ + if (rtmin <= rtmax) { + return 0; + } + if (data->sign[main_axis]) { va[main_axis] = local_bvmax[main_axis]; vb[main_axis] = local_bvmin[main_axis]; @@ -1684,10 +1688,10 @@ static bool snapDerivedMesh( free_bvhtree_from_mesh(treedata); } else { - if (!treedata->vert_allocated) { + if (treedata->vert == NULL) { treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated); } - if ((tree_index == 1) && !treedata->edge_allocated) { + if ((tree_index == 1) && (treedata->edge == NULL)) { treedata->edge = DM_get_edge_array(dm, &treedata->edge_allocated); } } @@ -1794,8 +1798,7 @@ static bool snapEditMesh( float local_scale = normalize_v3(ray_normal_local); SnapObjectData_EditMesh *sod = NULL; - - BVHTreeFromEditMesh *treedata; + BVHTreeFromEditMesh *treedata = NULL; void **sod_p; if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { @@ -1998,6 +2001,33 @@ static bool snapObject( } +struct SnapObjUserData { + SnapData *snapdata; + /* read/write args */ + float *ray_depth; + float *dist_px; + /* return args */ + float *r_loc; + float *r_no; + Object **r_ob; + float (*r_obmat)[4]; + bool ret; +}; + +static void sanp_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data) +{ + struct SnapObjUserData *dt = data; + dt->ret |= snapObject( + sctx, dt->snapdata, + ob, obmat, is_obedit, + /* read/write args */ + dt->ray_depth, dt->dist_px, + /* return args */ + dt->r_loc, dt->r_no, + dt->r_ob, dt->r_obmat); +} + + /** * Main Snapping Function * ====================== @@ -2035,21 +2065,22 @@ static bool snapObjectsRay( float r_loc[3], float r_no[3], Object **r_ob, float r_obmat[4][4]) { - bool retval = false; - bool use_obedit; - - Object *ob, *obedit; - float (*obmat)[4]; + Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; + + struct SnapObjUserData data = { + .snapdata = snapdata, + .ray_depth = ray_depth, + .dist_px = dist_px, + .r_loc = r_loc, + .r_no = r_no, + .r_ob = r_ob, + .r_obmat = r_obmat, + .ret = false, + }; - obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; - ITER_SNAP_OBJECTS(use_obedit, ob, obmat, sctx, snap_select, obedit, - retval |= snapObject( - sctx, snapdata, ob, obmat, use_obedit, - ray_depth, dist_px, - r_loc, r_no, r_ob, r_obmat); - ) + iter_snap_objects(sctx, snap_select, obedit, sanp_obj_cb, &data); - return retval; + return data.ret; } /** \} */ @@ -2149,11 +2180,9 @@ bool ED_transform_snap_object_project_ray_ex( float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { - const float depth_range[2] = {0.0f, FLT_MAX}; - return raycastObjects( sctx, - ray_start, ray_start, ray_normal, depth_range, + ray_start, ray_normal, params->snap_select, params->use_object_edit_cage, ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL); } @@ -2172,7 +2201,6 @@ bool ED_transform_snap_object_project_ray_all( float ray_depth, bool sort, ListBase *r_hit_list) { - const float depth_range[2] = {0.0f, FLT_MAX}; if (ray_depth == -1.0f) { ray_depth = BVH_RAYCAST_DIST_MAX; } @@ -2183,7 +2211,7 @@ bool ED_transform_snap_object_project_ray_all( bool retval = raycastObjects( sctx, - ray_start, ray_start, ray_normal, depth_range, + ray_start, ray_normal, params->snap_select, params->use_object_edit_cage, &ray_depth, NULL, NULL, NULL, NULL, NULL, r_hit_list); @@ -2366,7 +2394,7 @@ bool ED_transform_snap_object_project_view3d_ex( if (snap_to == SCE_SNAP_MODE_FACE) { return raycastObjects( sctx, - ray_origin, ray_start, ray_normal, depth_range, + ray_start, ray_normal, params->snap_select, params->use_object_edit_cage, ray_depth, r_loc, r_no, r_index, NULL, NULL, NULL); } diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 5125bb54dd4..9ae5145e53a 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -225,7 +225,7 @@ void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, I BM_data_layer_add(em->bm, &em->bm->pdata, CD_MTEXPOLY); BM_data_layer_add(em->bm, &em->bm->ldata, CD_MLOOPUV); /* make UVs all nice 0-1 */ - ED_mesh_uv_loop_reset_ex(obedit->data, CustomData_get_active_layer_index(&em->bm->pdata, CD_MTEXPOLY)); + ED_mesh_uv_loop_reset_ex(obedit->data, CustomData_get_active_layer(&em->bm->pdata, CD_MTEXPOLY)); update = true; } diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 1dbac1848b7..9c478c203e7 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -957,7 +957,7 @@ Render *BlenderStrokeRenderer::RenderScene(Render * /*re*/, bool render) } #endif - Render *freestyle_render = RE_NewRender(freestyle_scene->id.name); + Render *freestyle_render = RE_NewSceneRender(freestyle_scene); RE_RenderFreestyleStrokes(freestyle_render, freestyle_bmain, freestyle_scene, render && get_stroke_count() > 0); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 6db23686832..dbfcd4d1ea4 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -226,7 +226,7 @@ void GPU_material_free(struct ListBase *gpumaterial); void GPU_materials_free(void); -bool GPU_lamp_override_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma); +bool GPU_lamp_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma); void GPU_material_bind( GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 9f1fe3a5a67..e288c74fee6 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -76,13 +76,13 @@ typedef struct { static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type); -const GPUBufferTypeSettings gpu_buffer_type_settings[] = { +static const GPUBufferTypeSettings gpu_buffer_type_settings[] = { /* vertex */ {GL_ARRAY_BUFFER, 3}, /* normal */ {GL_ARRAY_BUFFER, 4}, /* we copy 3 shorts per normal but we add a fourth for alignment */ /* mcol */ - {GL_ARRAY_BUFFER, 3}, + {GL_ARRAY_BUFFER, 4}, /* uv */ {GL_ARRAY_BUFFER, 2}, /* uv for texpaint */ @@ -690,7 +690,7 @@ void GPU_color_setup(DerivedMesh *dm, int colType) glEnableClientState(GL_COLOR_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->colors->id); - glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0); GLStates |= GPU_BUFFER_COLOR_STATE; } diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 1583d16ca27..2d7fa760e49 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -682,10 +682,10 @@ int GPU_verify_image( if (do_color_management) { srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "floar_buf_col_cor"); gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf); - frect = srgb_frect + texwinsy * ibuf->x + texwinsx; + frect = srgb_frect + (4 * (texwinsy * ibuf->x + texwinsx)); } else { - frect = ibuf->rect_float + texwinsy * ibuf->x + texwinsx; + frect = ibuf->rect_float + (ibuf->channels * (texwinsy * ibuf->x + texwinsx)); } } else { diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 1f3ae7f708a..f39cad20b9b 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -312,9 +312,11 @@ void GPU_material_free(ListBase *gpumaterial) BLI_freelistN(gpumaterial); } -bool GPU_lamp_override_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma) +bool GPU_lamp_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma) { - if (srl && srl->light_override) + if (lamp->hide) + return false; + else if (srl && srl->light_override) return BKE_group_object_exists(srl->light_override, lamp->ob); else if (ma && ma->group) return BKE_group_object_exists(ma->group, lamp->ob); @@ -338,8 +340,8 @@ void GPU_material_bind( for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) { GPULamp *lamp = nlink->data; - if (!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) && - GPU_lamp_override_visible(lamp, srl, material->ma)) + if ((lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) && + GPU_lamp_visible(lamp, srl, material->ma)) { lamp->dynenergy = lamp->energy; copy_v3_v3(lamp->dyncol, lamp->col); diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index f14db57a26a..3dbecc58a7e 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -3116,15 +3116,17 @@ void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha) } void node_tex_image_box(vec3 texco, - vec3 nob, + vec3 N, sampler2D ima, float blend, out vec4 color, out float alpha) { + vec3 signed_N = N; + /* project from direction vector to barycentric coordinates in triangles */ - nob = vec3(abs(nob.x), abs(nob.y), abs(nob.z)); - nob /= (nob.x + nob.y + nob.z); + N = vec3(abs(N.x), abs(N.y), abs(N.z)); + N /= (N.x + N.y + N.z); /* basic idea is to think of this as a triangle, each corner representing * one of the 3 faces of the cube. in the corners we have single textures, @@ -3140,37 +3142,37 @@ void node_tex_image_box(vec3 texco, float limit = 0.5 * (1.0 + blend); /* first test for corners with single texture */ - if (nob.x > limit * (nob.x + nob.y) && nob.x > limit * (nob.x + nob.z)) { + if (N.x > limit * (N.x + N.y) && N.x > limit * (N.x + N.z)) { weight.x = 1.0; } - else if (nob.y > limit * (nob.x + nob.y) && nob.y > limit * (nob.y + nob.z)) { + else if (N.y > limit * (N.x + N.y) && N.y > limit * (N.y + N.z)) { weight.y = 1.0; } - else if (nob.z > limit * (nob.x + nob.z) && nob.z > limit * (nob.y + nob.z)) { + else if (N.z > limit * (N.x + N.z) && N.z > limit * (N.y + N.z)) { weight.z = 1.0; } else if (blend > 0.0) { /* in case of blending, test for mixes between two textures */ - if (nob.z < (1.0 - limit) * (nob.y + nob.x)) { - weight.x = nob.x / (nob.x + nob.y); + if (N.z < (1.0 - limit) * (N.y + N.x)) { + weight.x = N.x / (N.x + N.y); weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); weight.y = 1.0 - weight.x; } - else if (nob.x < (1.0 - limit) * (nob.y + nob.z)) { - weight.y = nob.y / (nob.y + nob.z); + else if (N.x < (1.0 - limit) * (N.y + N.z)) { + weight.y = N.y / (N.y + N.z); weight.y = clamp((weight.y - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); weight.z = 1.0 - weight.y; } - else if (nob.y < (1.0 - limit) * (nob.x + nob.z)) { - weight.x = nob.x / (nob.x + nob.z); + else if (N.y < (1.0 - limit) * (N.x + N.z)) { + weight.x = N.x / (N.x + N.z); weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); weight.z = 1.0 - weight.x; } else { /* last case, we have a mix between three */ - weight.x = ((2.0 - limit) * nob.x + (limit - 1.0)) / (2.0 * limit - 1.0); - weight.y = ((2.0 - limit) * nob.y + (limit - 1.0)) / (2.0 * limit - 1.0); - weight.z = ((2.0 - limit) * nob.z + (limit - 1.0)) / (2.0 * limit - 1.0); + weight.x = ((2.0 - limit) * N.x + (limit - 1.0)) / (2.0 * limit - 1.0); + weight.y = ((2.0 - limit) * N.y + (limit - 1.0)) / (2.0 * limit - 1.0); + weight.z = ((2.0 - limit) * N.z + (limit - 1.0)) / (2.0 * limit - 1.0); } } else { @@ -3179,13 +3181,25 @@ void node_tex_image_box(vec3 texco, } color = vec4(0); if (weight.x > 0.0) { - color += weight.x * texture2D(ima, texco.yz); + vec2 uv = texco.yz; + if(signed_N.x < 0.0) { + uv.x = 1.0 - uv.x; + } + color += weight.x * texture2D(ima, uv); } if (weight.y > 0.0) { - color += weight.y * texture2D(ima, texco.xz); + vec2 uv = texco.xz; + if(signed_N.y > 0.0) { + uv.x = 1.0 - uv.x; + } + color += weight.y * texture2D(ima, uv); } if (weight.z > 0.0) { - color += weight.z * texture2D(ima, texco.yx); + vec2 uv = texco.yx; + if(signed_N.z > 0.0) { + uv.x = 1.0 - uv.x; + } + color += weight.z * texture2D(ima, uv); } alpha = color.a; diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c index 6ea311b2c7b..f837789914e 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.c +++ b/source/blender/ikplugin/intern/iksolver_plugin.c @@ -217,9 +217,27 @@ static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[3][3]) // nr = copy_m4_m3(ikmat, ik_mat); if (pchan->parent) - mul_m4_series(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat); + mul_m4_m4m4(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat); else - mul_m4_m4m4(pchan->pose_mat, pchan->chan_mat, ikmat); + copy_m4_m4(pchan->pose_mat, pchan->chan_mat); + +#ifdef USE_NONUNIFORM_SCALE + /* apply IK mat, but as if the bones have uniform scale since the IK solver + * is not aware of non-uniform scale */ + float scale[3]; + mat4_to_size(scale, pchan->pose_mat); + normalize_v3_length(pchan->pose_mat[0], scale[1]); + normalize_v3_length(pchan->pose_mat[2], scale[1]); +#endif + + mul_m4_m4m4(pchan->pose_mat, pchan->pose_mat, ikmat); + +#ifdef USE_NONUNIFORM_SCALE + float ik_scale[3]; + mat3_to_size(ik_scale, ik_mat); + normalize_v3_length(pchan->pose_mat[0], scale[0] * ik_scale[0]); + normalize_v3_length(pchan->pose_mat[2], scale[2] * ik_scale[2]); +#endif /* calculate head */ copy_v3_v3(pchan->pose_head, pchan->pose_mat[3]); @@ -308,6 +326,10 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree) /* change length based on bone size */ length = bone->length * len_v3(R_bonemat[1]); + /* basis must be pure rotation */ + normalize_m3(R_bonemat); + normalize_m3(R_parmat); + /* compute rest basis and its inverse */ copy_m3_m3(rest_basis, bone->bone_mat); transpose_m3_m3(irest_basis, bone->bone_mat); @@ -317,11 +339,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree) mul_m3_m3m3(full_basis, iR_parmat, R_bonemat); mul_m3_m3m3(basis, irest_basis, full_basis); - /* basis must be pure rotation */ - normalize_m3(basis); - /* transform offset into local bone space */ - normalize_m3(iR_parmat); mul_m3_v3(iR_parmat, start); IK_SetTransform(seg, start, rest_basis, basis, length); @@ -545,18 +563,6 @@ void iksolver_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan tree->pchan[a]->flag |= POSE_CHAIN; } -#ifdef USE_NONUNIFORM_SCALE - float (*pchan_scale_data)[3] = MEM_mallocN(sizeof(float[3]) * tree->totchannel, __func__); - - for (a = 0; a < tree->totchannel; a++) { - mat4_to_size(pchan_scale_data[a], tree->pchan[a]->pose_mat); - - /* make uniform at y scale since this controls the length */ - normalize_v3_length(tree->pchan[a]->pose_mat[0], pchan_scale_data[a][1]); - normalize_v3_length(tree->pchan[a]->pose_mat[2], pchan_scale_data[a][1]); - } -#endif - /* 5. execute the IK solver */ execute_posetree(scene, ob, tree); @@ -571,14 +577,6 @@ void iksolver_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan where_is_ik_bone(tree->pchan[a], tree->basis_change[a]); } -#ifdef USE_NONUNIFORM_SCALE - for (a = 0; a < tree->totchannel; a++) { - normalize_v3_length(tree->pchan[a]->pose_mat[0], pchan_scale_data[a][0]); - normalize_v3_length(tree->pchan[a]->pose_mat[2], pchan_scale_data[a][2]); - } - MEM_freeN(pchan_scale_data); -#endif - /* 7. and free */ BLI_remlink(&pchan_root->iktree, tree); free_posetree(tree); diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt index b32f8c54cd6..c3950d8eb83 100644 --- a/source/blender/imbuf/CMakeLists.txt +++ b/source/blender/imbuf/CMakeLists.txt @@ -130,16 +130,6 @@ if(WITH_CODEC_AVI) add_definitions(-DWITH_AVI) endif() -if(WITH_CODEC_QUICKTIME) - list(APPEND INC - ../quicktime - ) - list(APPEND INC_SYS - ${QUICKTIME_INCLUDE_DIRS} - ) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_CODEC_FFMPEG) list(APPEND INC ../../../intern/ffmpeg diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index e7abfdc7d67..f1f36351e79 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -205,6 +205,7 @@ typedef enum IMB_BlendMode { IMB_BLEND_SATURATION = 21, IMB_BLEND_LUMINOSITY = 22, IMB_BLEND_COLOR = 23, + IMB_BLEND_INTERPOLATE = 24, IMB_BLEND_COPY = 1000, IMB_BLEND_COPY_RGB = 1001, diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 1701c2ba307..ee51854d7ed 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -295,7 +295,6 @@ typedef struct ImBuf { #endif /* DDS */ extern const char *imb_ext_image[]; -extern const char *imb_ext_image_qt[]; extern const char *imb_ext_movie[]; extern const char *imb_ext_audio[]; diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index 6d7ad7985f9..b10ae4f6fe9 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -63,12 +63,6 @@ # include "AVI_avi.h" #endif -#ifdef WITH_QUICKTIME -# if defined(_WIN32) || defined(__APPLE__) -# include "quicktime_import.h" -# endif /* _WIN32 || __APPLE__ */ -#endif /* WITH_QUICKTIME */ - #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -137,11 +131,6 @@ struct anim { PGETFRAME pgf; #endif -#ifdef WITH_QUICKTIME - /* quicktime */ - struct _QuicktimeMovie *qtime; -#endif /* WITH_QUICKTIME */ - #ifdef WITH_FFMPEG AVFormatContext *pFormatCtx; AVCodecContext *pCodecCtx; diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 9806ff006d7..25b0c0d7b1a 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -73,12 +73,6 @@ # include "AVI_avi.h" #endif -#ifdef WITH_QUICKTIME -#if defined(_WIN32) || defined(__APPLE__) -#include "quicktime_import.h" -#endif /* _WIN32 || __APPLE__ */ -#endif /* WITH_QUICKTIME */ - #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -221,9 +215,6 @@ void IMB_free_anim(struct anim *anim) free_anim_avi(anim); #endif -#ifdef WITH_QUICKTIME - free_anim_quicktime(anim); -#endif #ifdef WITH_FFMPEG free_anim_ffmpeg(anim); #endif @@ -513,6 +504,11 @@ static int startffmpeg(struct anim *anim) avformat_close_input(&pFormatCtx); return -1; } + if (pCodecCtx->pix_fmt == AV_PIX_FMT_NONE) { + avcodec_close(anim->pCodecCtx); + avformat_close_input(&pFormatCtx); + return -1; + } frame_rate = av_get_r_frame_rate_compat(pFormatCtx->streams[videoStream]); if (pFormatCtx->streams[videoStream]->nb_frames != 0) { @@ -1214,9 +1210,6 @@ static ImBuf *anim_getnew(struct anim *anim) free_anim_avi(anim); #endif -#ifdef WITH_QUICKTIME - free_anim_quicktime(anim); -#endif #ifdef WITH_FFMPEG free_anim_ffmpeg(anim); #endif @@ -1245,12 +1238,6 @@ static ImBuf *anim_getnew(struct anim *anim) ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0); break; #endif -#ifdef WITH_QUICKTIME - case ANIM_QTIME: - if (startquicktime(anim)) return (0); - ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0); - break; -#endif #ifdef WITH_FFMPEG case ANIM_FFMPEG: if (startffmpeg(anim)) return (0); @@ -1340,21 +1327,6 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim, int position, anim->curposition = position; break; #endif -#ifdef WITH_QUICKTIME - case ANIM_QTIME: - ibuf = qtime_fetchibuf(anim, position); - if (ibuf) { - if (ibuf->rect) { - /* OCIO_TODO: should happen in quicktime module, but it currently doesn't have access - * to color management's internals - */ - ibuf->rect_colorspace = colormanage_colorspace_get_named(anim->colorspace); - } - - anim->curposition = position; - } - break; -#endif #ifdef WITH_FFMPEG case ANIM_FFMPEG: ibuf = ffmpeg_fetchibuf(anim, position, tc); diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 03f71b5878c..863bce125c5 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -47,6 +47,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_filetype.h" +#include "IMB_filter.h" #include "IMB_moviecache.h" #include "MEM_guardedalloc.h" @@ -1521,6 +1522,10 @@ static bool is_ibuf_rect_in_display_space(ImBuf *ibuf, const ColorManagedViewSet { const char *from_colorspace = ibuf->rect_colorspace->name; const char *to_colorspace = IMB_colormanagement_get_display_colorspace_name(view_settings, display_settings); + ColorManagedLook *look_descr = colormanage_look_get_named(view_settings->look); + if (look_descr != NULL && !STREQ(look_descr->process_space, "")) { + return false; + } if (to_colorspace && STREQ(from_colorspace, to_colorspace)) return true; @@ -1635,12 +1640,13 @@ static void *do_processor_transform_thread(void *handle_v) if (float_from_byte) { IMB_buffer_float_from_byte(float_buffer, byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB, - true, + false, width, height, width, width); - IMB_colormanagement_processor_apply(handle->cm_processor, - float_buffer, - width, height, channels, - predivide); + IMB_colormanagement_processor_apply(handle->cm_processor, + float_buffer, + width, height, channels, + predivide); + IMB_premultiply_rect_float(float_buffer, 4, width, height); } else { if (byte_buffer != NULL) { @@ -1776,14 +1782,15 @@ void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer, unsig */ IMB_buffer_float_from_byte(float_buffer, byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB, - true, + false, width, height, width, width); + IMB_premultiply_rect_float(float_buffer, 4, width, height); return; } cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace); processor_transform_apply_threaded(byte_buffer, float_buffer, width, height, channels, - cm_processor, true, true); + cm_processor, false, true); IMB_colormanagement_processor_free(cm_processor); } @@ -2565,6 +2572,14 @@ const char *IMB_colormanagement_colorspace_get_indexed_name(int index) void IMB_colormanagment_colorspace_from_ibuf_ftype(ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf) { + /* Don't modify non-color data space, it does not change with file type. */ + ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name); + + if (colorspace && colorspace->is_data) { + return; + } + + /* Get color space from file type. */ const ImFileType *type; for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) { diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c index 3d3e8a0646a..7ed5c8ffbcb 100644 --- a/source/blender/imbuf/intern/filetype.c +++ b/source/blender/imbuf/intern/filetype.c @@ -47,10 +47,6 @@ #include "dds/dds_api.h" #endif -#ifdef WITH_QUICKTIME -#include "quicktime_import.h" -#endif - static int imb_ftype_default(const ImFileType *type, ImBuf *ibuf) { return (ibuf->ftype == type->filetype); @@ -101,10 +97,6 @@ void imb_filetypes_init(void) for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) if (type->init) type->init(); - -#ifdef WITH_QUICKTIME - quicktime_init(); -#endif } void imb_filetypes_exit(void) @@ -114,9 +106,5 @@ void imb_filetypes_exit(void) for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) if (type->exit) type->exit(); - -#ifdef WITH_QUICKTIME - quicktime_exit(); -#endif } diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c index 7a9fa2b9768..6c0849358a5 100644 --- a/source/blender/imbuf/intern/iris.c +++ b/source/blender/imbuf/intern/iris.c @@ -48,36 +48,24 @@ #define IMAGIC 0732 typedef struct { - unsigned short imagic; /* stuff saved on disk . . */ - unsigned short type; - unsigned short dim; - unsigned short xsize; - unsigned short ysize; - unsigned short zsize; - unsigned int min; - unsigned int max; - unsigned int wastebytes; - char name[80]; - unsigned int colormap; - - int file; /* stuff used in core only */ - unsigned short flags; - short dorev; - short x; - short y; - short z; - short cnt; - unsigned short *ptr; - unsigned short *base; - unsigned short *tmpbuf; - unsigned int offset; - unsigned int rleend; /* for rle images */ - unsigned int *rowstart; /* for rle images */ - const int *rowsize; /* for rle images */ + ushort imagic; /* stuff saved on disk . . */ + ushort type; + ushort dim; + ushort xsize; + ushort ysize; + ushort zsize; + uint min; + uint max; + uchar _pad1[4]; + char name[80]; + uint colormap; + uchar _pad2[404]; } IMAGE; #define HEADER_SIZE 512 +BLI_STATIC_ASSERT(sizeof(IMAGE) == HEADER_SIZE, "Invalid header size"); + #define RINTLUM (79) #define GINTLUM (156) #define BINTLUM (21) @@ -106,68 +94,72 @@ typedef struct { /* local struct for mem access */ typedef struct MFileOffset { const uchar *_file_data; - unsigned int _file_offset; + uint _file_offset; } MFileOffset; -#define MFILE_DATA(inf) ((void)0, (inf)->_file_data + (inf)->_file_offset) +#define MFILE_DATA(inf) ((void)0, ((inf)->_file_data + (inf)->_file_offset)) #define MFILE_STEP(inf, step) { (inf)->_file_offset += step; } ((void)0) #define MFILE_SEEK(inf, pos) { (inf)->_file_offset = pos; } ((void)0) +/* error flags */ +#define DIRTY_FLAG_EOF (1 << 0) +#define DIRTY_FLAG_ENCODING (1 << 1) + /* funcs */ static void readheader(MFileOffset *inf, IMAGE *image); static int writeheader(FILE *outf, IMAGE *image); -static unsigned short getshort(MFileOffset *inf); -static unsigned int getlong(MFileOffset *inf); -static void putshort(FILE *outf, unsigned short val); -static int putlong(FILE *outf, unsigned int val); -static int writetab(FILE *outf, unsigned int *tab, int len); -static void readtab(MFileOffset *inf, unsigned int *tab, int len); +static ushort getshort(MFileOffset *inf); +static uint getlong(MFileOffset *inf); +static void putshort(FILE *outf, ushort val); +static int putlong(FILE *outf, uint val); +static int writetab(FILE *outf, uint *tab, int len); +static void readtab(MFileOffset *inf, uint *tab, int len); -static void expandrow(unsigned char *optr, const unsigned char *iptr, int z); -static void expandrow2(float *optr, const unsigned char *iptr, int z); -static void interleaverow(unsigned char *lptr, const unsigned char *cptr, int z, int n); -static void interleaverow2(float *lptr, const unsigned char *cptr, int z, int n); -static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt); -static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n); +static int expandrow(uchar *optr, const uchar *optr_end, const uchar *iptr, const uchar *iptr_end, int z); +static int expandrow2(float *optr, const float *optr_end, const uchar *iptr, const uchar *iptr_end, int z); +static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n); +static void interleaverow2(float *lptr, const uchar *cptr, int z, int n); +static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int cnt); +static void lumrow(uchar *rgbptr, uchar *lumptr, int n); /* * byte order independent read/write of shorts and ints. * */ -static unsigned short getshort(MFileOffset *inf) +static ushort getshort(MFileOffset *inf) { - const unsigned char *buf; + const uchar *buf; buf = MFILE_DATA(inf); MFILE_STEP(inf, 2); - - return (buf[0] << 8) + (buf[1] << 0); + + return ((ushort)buf[0] << 8) + ((ushort)buf[1] << 0); } -static unsigned int getlong(MFileOffset *mofs) +static uint getlong(MFileOffset *mofs) { - const unsigned char *buf; + const uchar *buf; buf = MFILE_DATA(mofs); MFILE_STEP(mofs, 4); - - return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0); + + return ((uint)buf[0] << 24) + ((uint)buf[1] << 16) + ((uint)buf[2] << 8) + ((uint)buf[3] << 0); } -static void putshort(FILE *outf, unsigned short val) +static void putshort(FILE *outf, ushort val) { - unsigned char buf[2]; + uchar buf[2]; buf[0] = (val >> 8); buf[1] = (val >> 0); fwrite(buf, 2, 1, outf); } -static int putlong(FILE *outf, unsigned int val) +static int putlong(FILE *outf, uint val) { - unsigned char buf[4]; + uchar buf[4]; buf[0] = (val >> 24); buf[1] = (val >> 16); @@ -205,7 +197,7 @@ static int writeheader(FILE *outf, IMAGE *image) return fwrite("no name", 8, 1, outf); } -static int writetab(FILE *outf, unsigned int *tab, int len) +static int writetab(FILE *outf, uint *tab, int len) { int r = 0; @@ -216,7 +208,7 @@ static int writetab(FILE *outf, unsigned int *tab, int len) return r; } -static void readtab(MFileOffset *inf, unsigned int *tab, int len) +static void readtab(MFileOffset *inf, uint *tab, int len) { while (len) { *tab++ = getlong(inf); @@ -242,12 +234,12 @@ static void test_endian_zbuf(struct ImBuf *ibuf) } /* from misc_util: flip the bytes from x */ -#define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) +#define GS(x) (((uchar *)(x))[0] << 8 | ((uchar *)(x))[1]) /* this one is only def-ed once, strangely... */ #define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0]) -int imb_is_a_iris(const unsigned char *mem) +int imb_is_a_iris(const uchar *mem) { return ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC)); } @@ -259,46 +251,52 @@ int imb_is_a_iris(const unsigned char *mem) * */ -struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) +struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) { - unsigned int *base, *lptr = NULL; + uint *base, *lptr = NULL; float *fbase, *fptr = NULL; - unsigned int *zbase, *zptr; - const unsigned char *rledat; - unsigned int *starttab, *lengthtab; + uint *zbase, *zptr; + const uchar *rledat; + const uchar *mem_end = mem + size; MFileOffset _inf_data = {mem, 0}, *inf = &_inf_data; IMAGE image; int x, y, z, tablen; - int xsize, ysize, zsize; int bpp, rle, cur, badorder; ImBuf *ibuf; + uchar dirty_flag = 0; - (void)size; /* unused */ - - if (!imb_is_a_iris(mem)) return NULL; + if (size < HEADER_SIZE) { + return NULL; + } + + if (!imb_is_a_iris(mem)) { + return NULL; + } /* OCIO_TODO: only tested with 1 byte per pixel, not sure how to test with other settings */ colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE); - /*printf("new iris\n");*/ - readheader(inf, &image); if (image.imagic != IMAGIC) { fprintf(stderr, "longimagedata: bad magic number in image file\n"); return(NULL); } - + rle = ISRLE(image.type); bpp = BPP(image.type); if (bpp != 1 && bpp != 2) { fprintf(stderr, "longimagedata: image must have 1 or 2 byte per pix chan\n"); return(NULL); } - - xsize = image.xsize; - ysize = image.ysize; - zsize = image.zsize; - + if ((uint)image.zsize > 8) { + fprintf(stderr, "longimagedata: channels over 8 not supported\n"); + return(NULL); + } + + const int xsize = image.xsize; + const int ysize = image.ysize; + const int zsize = image.zsize; + if (flags & IB_test) { ibuf = IMB_allocImBuf(image.xsize, image.ysize, 8 * image.zsize, 0); if (ibuf) ibuf->ftype = IMB_FTYPE_IMAGIC; @@ -306,12 +304,17 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha } if (rle) { - tablen = ysize * zsize * sizeof(int); - starttab = (unsigned int *)MEM_mallocN(tablen, "iris starttab"); - lengthtab = (unsigned int *)MEM_mallocN(tablen, "iris endtab"); MFILE_SEEK(inf, HEADER_SIZE); - + + uint *starttab = MEM_mallocN(tablen, "iris starttab"); + uint *lengthtab = MEM_mallocN(tablen, "iris endtab"); + +#define MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(p) \ + if (UNLIKELY((p) > mem_end)) { dirty_flag |= DIRTY_FLAG_EOF; goto fail_rle; } ((void)0) + + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(MFILE_DATA(inf) + ((4 * 2) * tablen)); + readtab(inf, starttab, tablen); readtab(inf, lengthtab, tablen); @@ -335,7 +338,7 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect); if (ibuf->planes > 32) ibuf->planes = 32; base = ibuf->rect; - zbase = (unsigned int *)ibuf->zbuf; + zbase = (uint *)ibuf->zbuf; if (badorder) { for (z = 0; z < zsize; z++) { @@ -344,9 +347,11 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha MFILE_SEEK(inf, starttab[y + z * ysize]); rledat = MFILE_DATA(inf); MFILE_STEP(inf, lengthtab[y + z * ysize]); - - expandrow((uchar *)lptr, rledat, 3 - z); - lptr += xsize; + const uchar *rledat_next = MFILE_DATA(inf); + uint *lptr_next = lptr + xsize; + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next); + dirty_flag |= expandrow((uchar *)lptr, (uchar *)lptr_next, rledat, rledat_next, 3 - z); + lptr = lptr_next; } } } @@ -354,17 +359,25 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha lptr = base; zptr = zbase; for (y = 0; y < ysize; y++) { - + + uint *lptr_next = lptr + xsize; + uint *zptr_next = zptr + xsize; + for (z = 0; z < zsize; z++) { MFILE_SEEK(inf, starttab[y + z * ysize]); rledat = MFILE_DATA(inf); MFILE_STEP(inf, lengthtab[y + z * ysize]); - - if (z < 4) expandrow((uchar *)lptr, rledat, 3 - z); - else if (z < 8) expandrow((uchar *)zptr, rledat, 7 - z); + const uchar *rledat_next = MFILE_DATA(inf); + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next); + if (z < 4) { + dirty_flag |= expandrow((uchar *)lptr, (uchar *)lptr_next, rledat, rledat_next, 3 - z); + } + else if (z < 8) { + dirty_flag |= expandrow((uchar *)zptr, (uchar *)zptr_next, rledat, rledat_next, 7 - z); + } } - lptr += xsize; - zptr += xsize; + lptr = lptr_next; + zptr = zptr_next; } } @@ -383,14 +396,17 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha MFILE_SEEK(inf, starttab[y + z * ysize]); rledat = MFILE_DATA(inf); MFILE_STEP(inf, lengthtab[y + z * ysize]); - - expandrow2(fptr, rledat, 3 - z); - fptr += xsize * 4; + const uchar *rledat_next = MFILE_DATA(inf); + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next); + float *fptr_next = fptr + (xsize * 4); + dirty_flag |= expandrow2(fptr, fptr_next, rledat, rledat_next, 3 - z); + fptr = fptr_next; } } } else { fptr = fbase; + float *fptr_next = fptr + (xsize * 4); for (y = 0; y < ysize; y++) { @@ -398,27 +414,31 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha MFILE_SEEK(inf, starttab[y + z * ysize]); rledat = MFILE_DATA(inf); MFILE_STEP(inf, lengthtab[y + z * ysize]); - - expandrow2(fptr, rledat, 3 - z); - + const uchar *rledat_next = MFILE_DATA(inf); + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next); + dirty_flag |= expandrow2(fptr, fptr_next, rledat, rledat_next, 3 - z); } - fptr += xsize * 4; + fptr = fptr_next; } } } - +#undef MFILE_CAPACITY_AT_PTR_OK_OR_FAIL +fail_rle: MEM_freeN(starttab); MEM_freeN(lengthtab); - } else { + +#define MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(p) \ + if (UNLIKELY((p) > mem_end)) { dirty_flag |= DIRTY_FLAG_EOF; goto fail_uncompressed; } ((void)0) + if (bpp == 1) { ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect); if (ibuf->planes > 32) ibuf->planes = 32; base = ibuf->rect; - zbase = (unsigned int *)ibuf->zbuf; + zbase = (uint *)ibuf->zbuf; MFILE_SEEK(inf, HEADER_SIZE); rledat = MFILE_DATA(inf); @@ -427,12 +447,13 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha if (z < 4) lptr = base; else if (z < 8) lptr = zbase; - - for (y = 0; y < ysize; y++) { - interleaverow((uchar *)lptr, rledat, 3 - z, xsize); - rledat += xsize; - + for (y = 0; y < ysize; y++) { + const uchar *rledat_next = rledat + xsize; + const int z_ofs = 3 - z; + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs); + interleaverow((uchar *)lptr, rledat, z_ofs, xsize); + rledat = rledat_next; lptr += xsize; } } @@ -450,20 +471,23 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha for (z = 0; z < zsize; z++) { fptr = fbase; - - for (y = 0; y < ysize; y++) { - interleaverow2(fptr, rledat, 3 - z, xsize); - rledat += xsize * 2; - + for (y = 0; y < ysize; y++) { + const uchar *rledat_next = rledat + xsize * 2; + const int z_ofs = 3 - z; + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs); + interleaverow2(fptr, rledat, z_ofs, xsize); + rledat = rledat_next; fptr += xsize * 4; } } } +#undef MFILE_CAPACITY_AT_PTR_OK_OR_FAIL +fail_uncompressed: + (void)0; } - - + if (bpp == 1) { uchar *rect; @@ -528,6 +552,9 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha } + if (dirty_flag) { + fprintf(stderr, "longimagedata: corrupt file content (%d)\n", dirty_flag); + } ibuf->ftype = IMB_FTYPE_IMAGIC; test_endian_zbuf(ibuf); @@ -541,7 +568,7 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha /* static utility functions for longimagedata */ -static void interleaverow(unsigned char *lptr, const unsigned char *cptr, int z, int n) +static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n) { lptr += z; while (n--) { @@ -550,7 +577,7 @@ static void interleaverow(unsigned char *lptr, const unsigned char *cptr, int z, } } -static void interleaverow2(float *lptr, const unsigned char *cptr, int z, int n) +static void interleaverow2(float *lptr, const uchar *cptr, int z, int n) { lptr += z; while (n--) { @@ -560,19 +587,34 @@ static void interleaverow2(float *lptr, const unsigned char *cptr, int z, int n) } } -static void expandrow2(float *optr, const unsigned char *iptr, int z) +static int expandrow2( + float *optr, const float *optr_end, + const uchar *iptr, const uchar *iptr_end, int z) { - unsigned short pixel, count; + ushort pixel, count; float pixel_f; +#define EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next) \ + if (UNLIKELY(iptr_next > iptr_end)) { goto fail; } + +#define EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next) \ + if (UNLIKELY(optr_next > optr_end)) { goto fail; } + optr += z; + optr_end += z; while (1) { + const uchar *iptr_next = iptr + 2; + EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next); pixel = (iptr[0] << 8) | (iptr[1] << 0); - iptr += 2; - + iptr = iptr_next; + if (!(count = (pixel & 0x7f)) ) - return; + return false; + const float *optr_next = optr + count; + EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next); if (pixel & 0x80) { + iptr_next = iptr + (count * 2); + EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next); while (count >= 8) { optr[0 * 4] = ((iptr[0] << 8) | (iptr[1] << 0)) / (float)0xFFFF; optr[1 * 4] = ((iptr[2] << 8) | (iptr[3] << 0)) / (float)0xFFFF; @@ -591,10 +633,13 @@ static void expandrow2(float *optr, const unsigned char *iptr, int z) iptr += 2; optr += 4; } + BLI_assert(iptr == iptr_next); } else { + iptr_next = iptr + 2; + EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next); pixel_f = ((iptr[0] << 8) | (iptr[1] << 0)) / (float)0xFFFF; - iptr += 2; + iptr = iptr_next; while (count >= 8) { optr[0 * 4] = pixel_f; @@ -612,20 +657,45 @@ static void expandrow2(float *optr, const unsigned char *iptr, int z) *optr = pixel_f; optr += 4; } + BLI_assert(iptr == iptr_next); } + BLI_assert(optr == optr_next); } + return false; + +#undef EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL +#undef EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL +fail: + return DIRTY_FLAG_ENCODING; } -static void expandrow(unsigned char *optr, const unsigned char *iptr, int z) +static int expandrow( + uchar *optr, const uchar *optr_end, + const uchar *iptr, const uchar *iptr_end, int z) { - unsigned char pixel, count; + uchar pixel, count; + +#define EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next) \ + if (UNLIKELY(iptr_next > iptr_end)) { goto fail; } + +#define EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next) \ + if (UNLIKELY(optr_next > optr_end)) { goto fail; } optr += z; + optr_end += z; while (1) { - pixel = *iptr++; + const uchar *iptr_next = iptr + 1; + EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next); + pixel = *iptr; + iptr = iptr_next; if (!(count = (pixel & 0x7f)) ) - return; + return false; + const uchar *optr_next = optr + ((int)count * 4); + EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next); + if (pixel & 0x80) { + iptr_next = iptr + count; + EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next); while (count >= 8) { optr[0 * 4] = iptr[0]; optr[1 * 4] = iptr[1]; @@ -643,8 +713,11 @@ static void expandrow(unsigned char *optr, const unsigned char *iptr, int z) *optr = *iptr++; optr += 4; } + BLI_assert(iptr == iptr_next); } else { + iptr_next = iptr + 1; + EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next); pixel = *iptr++; while (count >= 8) { optr[0 * 4] = pixel; @@ -662,8 +735,17 @@ static void expandrow(unsigned char *optr, const unsigned char *iptr, int z) *optr = pixel; optr += 4; } + BLI_assert(iptr == iptr_next); } + BLI_assert(optr == optr_next); } + + return false; + +#undef EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL +#undef EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL +fail: + return DIRTY_FLAG_ENCODING; } /* @@ -679,14 +761,14 @@ static void expandrow(unsigned char *optr, const unsigned char *iptr, int z) * Added: zbuf write */ -static int output_iris(unsigned int *lptr, int xsize, int ysize, int zsize, const char *name, int *zptr) +static int output_iris(uint *lptr, int xsize, int ysize, int zsize, const char *name, int *zptr) { FILE *outf; IMAGE *image; int tablen, y, z, pos, len = 0; - unsigned int *starttab, *lengthtab; - unsigned char *rlebuf; - unsigned int *lumbuf; + uint *starttab, *lengthtab; + uchar *rlebuf; + uint *lumbuf; int rlebuflen, goodwrite; goodwrite = 1; @@ -696,14 +778,14 @@ static int output_iris(unsigned int *lptr, int xsize, int ysize, int zsize, cons tablen = ysize * zsize * sizeof(int); image = (IMAGE *)MEM_mallocN(sizeof(IMAGE), "iris image"); - starttab = (unsigned int *)MEM_mallocN(tablen, "iris starttab"); - lengthtab = (unsigned int *)MEM_mallocN(tablen, "iris lengthtab"); + starttab = (uint *)MEM_mallocN(tablen, "iris starttab"); + lengthtab = (uint *)MEM_mallocN(tablen, "iris lengthtab"); rlebuflen = 1.05 * xsize + 10; - rlebuf = (unsigned char *)MEM_mallocN(rlebuflen, "iris rlebuf"); - lumbuf = (unsigned int *)MEM_mallocN(xsize * sizeof(int), "iris lumbuf"); + rlebuf = (uchar *)MEM_mallocN(rlebuflen, "iris rlebuf"); + lumbuf = (uint *)MEM_mallocN(xsize * sizeof(int), "iris lumbuf"); memset(image, 0, sizeof(IMAGE)); - image->imagic = IMB_FTYPE_IMAGIC; + image->imagic = IMAGIC; image->type = RLE(1); if (zsize > 1) image->dim = 3; @@ -765,7 +847,7 @@ static int output_iris(unsigned int *lptr, int xsize, int ysize, int zsize, cons /* static utility functions for output_iris */ -static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n) +static void lumrow(uchar *rgbptr, uchar *lumptr, int n) { lumptr += CHANOFFSET(0); while (n--) { @@ -775,9 +857,9 @@ static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n) } } -static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt) +static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int cnt) { - unsigned char *iptr, *ibufend, *sptr, *optr; + uchar *iptr, *ibufend, *sptr, *optr; short todo, cc; int count; @@ -830,7 +912,7 @@ static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cn } } *optr++ = 0; - return optr - (unsigned char *)rlebuf; + return optr - (uchar *)rlebuf; } int imb_saveiris(struct ImBuf *ibuf, const char *name, int flags) diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c index 390f2502ee7..388c2734fe9 100644 --- a/source/blender/imbuf/intern/jp2.c +++ b/source/blender/imbuf/intern/jp2.c @@ -588,7 +588,7 @@ static opj_image_t *ibuftoimage(ImBuf *ibuf, opj_cparameters_t *parameters) img_fol_t img_fol; /* only needed for cinema presets */ memset(&img_fol, 0, sizeof(img_fol_t)); - if (ibuf->float_colorspace) { + if (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) { /* float buffer was managed already, no need in color space conversion */ chanel_colormanage_cb = channel_colormanage_noop; } diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c index 4b49076dcd6..89955711384 100644 --- a/source/blender/imbuf/intern/moviecache.c +++ b/source/blender/imbuf/intern/moviecache.c @@ -49,7 +49,7 @@ #include "IMB_imbuf.h" #ifdef DEBUG_MESSAGES -# if defined __GNUC__ || defined __sun +# if defined __GNUC__ # define PRINT(format, args ...) printf(format, ##args) # else # define PRINT(format, ...) printf(__VA_ARGS__) diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index ec544e65355..1fa3b943524 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -1104,7 +1104,7 @@ void IMB_exr_write_channels(void *handle) if (data->channels.first) { const size_t num_pixels = ((size_t)data->width) * data->height; - half *rect_half = NULL, *current_rect_half; + half *rect_half = NULL, *current_rect_half = NULL; /* We allocate teporary storage for half pixels for all the channels at once. */ if (data->num_half_channels != 0) { diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index 503e63a3fb1..dded0f7aecf 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -152,7 +152,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) compression = (int)(((float)(ibuf->foptions.quality) / 11.1111f)); compression = compression < 0 ? 0 : (compression > 9 ? 9 : compression); - if (ibuf->float_colorspace) { + if (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) { /* float buffer was managed already, no need in color space conversion */ chanel_colormanage_cb = channel_colormanage_noop; } diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index 3360fd7548e..c4325caac91 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -301,8 +301,8 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height, IMB_BlendMode mode, bool accumulate) { - unsigned int *drect = NULL, *orect, *srect = NULL, *dr, *or, *sr; - float *drectf = NULL, *orectf, *srectf = NULL, *drf, *orf, *srf; + unsigned int *drect = NULL, *orect = NULL, *srect = NULL, *dr, *or, *sr; + float *drectf = NULL, *orectf = NULL, *srectf = NULL, *drf, *orf, *srf; unsigned short *cmaskrect = curvemask, *cmr; unsigned short *dmaskrect = dmask, *dmr; unsigned short *texmaskrect = texmask, *tmr; @@ -424,6 +424,7 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, else { switch (mode) { case IMB_BLEND_MIX: + case IMB_BLEND_INTERPOLATE: func = blend_color_mix_byte; func_float = blend_color_mix_float; break; @@ -563,9 +564,15 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, mask_src[0] = src[0]; mask_src[1] = src[1]; mask_src[2] = src[2]; - mask_src[3] = divide_round_i(src[3] * mask, 65535); - func((unsigned char *)dr, (unsigned char *)or, mask_src); + if (mode == IMB_BLEND_INTERPOLATE) { + mask_src[3] = src[3]; + blend_color_interpolate_byte((unsigned char *)dr, (unsigned char *)or, mask_src, mask / 65535.0f); + } + else { + mask_src[3] = divide_round_i(src[3] * mask, 65535); + func((unsigned char *)dr, (unsigned char *)or, mask_src); + } } } } @@ -588,9 +595,15 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, mask_src[0] = src[0]; mask_src[1] = src[1]; mask_src[2] = src[2]; - mask_src[3] = divide_round_i(src[3] * mask, 65535); - func((unsigned char *)dr, (unsigned char *)or, mask_src); + if (mode == IMB_BLEND_INTERPOLATE) { + mask_src[3] = src[3]; + blend_color_interpolate_byte((unsigned char *)dr, (unsigned char *)or, mask_src, mask / 65535.0f); + } + else { + mask_src[3] = divide_round_i(src[3] * mask, 65535); + func((unsigned char *)dr, (unsigned char *)or, mask_src); + } } } } @@ -642,12 +655,16 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, mask = min_ff(mask, 65535.0); if (mask > *dmr) { - float mask_srf[4]; - *dmr = mask; - mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); - func_float(drf, orf, mask_srf); + if (mode == IMB_BLEND_INTERPOLATE) { + blend_color_interpolate_float(drf, orf, srf, mask / 65535.0f); + } + else { + float mask_srf[4]; + mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); + func_float(drf, orf, mask_srf); + } } } } @@ -664,11 +681,15 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, mask = min_ff(mask, 65535.0); if (srf[3] && (mask > 0.0f)) { - float mask_srf[4]; - - mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); + if (mode == IMB_BLEND_INTERPOLATE) { + blend_color_interpolate_float(drf, orf, srf, mask / 65535.0f); + } + else { + float mask_srf[4]; + mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); + func_float(drf, orf, mask_srf); + } - func_float(drf, orf, mask_srf); } } } diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index 4368a428186..8e5cf80e013 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -822,7 +822,7 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags) /* convert from float source */ float rgb[4]; - if (ibuf->float_colorspace) { + if (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) { /* float buffer was managed already, no need in color space conversion */ copy_v3_v3(rgb, &fromf[from_i]); } diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index ba8480b636f..76a44aa81f7 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -52,10 +52,6 @@ #include "IMB_anim.h" -#ifdef WITH_QUICKTIME -#include "quicktime_import.h" -#endif - #ifdef WITH_FFMPEG #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> @@ -107,28 +103,6 @@ const char *imb_ext_image_filepath_only[] = { NULL }; -const char *imb_ext_image_qt[] = { - ".gif", - ".psd", - ".pct", ".pict", - ".pntg", - ".qtif", - NULL -}; - -#if 0 /* UNUSED */ -const char *imb_ext_movie_qt[] = { - ".avi", - ".flc", - ".dv", - ".r3d", - ".mov", - ".movie", - ".mv", - NULL -}; -#endif - const char *imb_ext_movie[] = { ".avi", ".flc", @@ -247,13 +221,6 @@ static int isavi(const char *name) #endif } -#ifdef WITH_QUICKTIME -static int isqtime(const char *name) -{ - return anim_is_quicktime(name); -} -#endif - #ifdef WITH_FFMPEG /* BLI_vsnprintf in ffmpeg_log_callback() causes invalid warning */ @@ -383,9 +350,6 @@ int imb_get_anim_type(const char *name) if (UTIL_DEBUG) printf("%s: %s\n", __func__, name); #ifndef _WIN32 -# ifdef WITH_QUICKTIME - if (isqtime(name)) return (ANIM_QTIME); -# endif # ifdef WITH_FFMPEG /* stat test below fails on large files > 4GB */ if (isffmpeg(name)) return (ANIM_FFMPEG); @@ -401,9 +365,6 @@ int imb_get_anim_type(const char *name) if (((st.st_mode) & S_IFMT) != S_IFREG) return(0); if (ismovie(name)) return (ANIM_MOVIE); -# ifdef WITH_QUICKTIME - if (isqtime(name)) return (ANIM_QTIME); -# endif # ifdef WITH_FFMPEG if (isffmpeg(name)) return (ANIM_FFMPEG); # endif diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index da0f505c4f3..b2a3cb4f9bc 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -127,8 +127,7 @@ typedef struct ID { /** * LIB_TAG_... tags (runtime only, cleared at read time). */ - short tag; - short pad_s1; + int tag; int us; int icon_id; IDProperty *properties; @@ -288,7 +287,7 @@ typedef enum ID_Type { #ifdef GS # undef GS #endif -#define GS(a) (CHECK_TYPE_ANY(a, char *, const char *, char [66], const char[66]), (*((const short *)(a)))) +#define GS(a) (CHECK_TYPE_ANY(a, char *, const char *, char [66], const char[66]), (ID_Type)(*((const short *)(a)))) #define ID_NEW_SET(_id, _idn) \ (((ID *)(_id))->newid = (ID *)(_idn), ((ID *)(_id))->newid->tag |= LIB_TAG_NEW, (void *)((ID *)(_id))->newid) @@ -350,6 +349,13 @@ enum { LIB_TAG_ID_RECALC_DATA = 1 << 13, LIB_TAG_ANIM_NO_RECALC = 1 << 14, LIB_TAG_ID_RECALC_ALL = (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA), + + /* RESET_NEVER tag datablock for freeing etc. behavior (usually set when copying real one into temp/runtime one). */ + LIB_TAG_NO_MAIN = 1 << 16, /* Datablock is not listed in Main database. */ + LIB_TAG_NO_USER_REFCOUNT = 1 << 17, /* Datablock does not refcount usages of other IDs. */ + /* Datablock was not allocated by standard system (BKE_libblock_alloc), do not free its memory + * (usual type-specific freeing is called though). */ + LIB_TAG_NOT_ALLOCATED = 1 << 18, }; /* To filter ID types (filter_id) */ diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 1083400ece2..d49960771d0 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -514,7 +514,7 @@ typedef enum eActionGroup_Flag { AGRP_MODIFIERS_OFF = (1 << 7), AGRP_TEMP = (1 << 30), - AGRP_MOVED = (1 << 31) + AGRP_MOVED = (1u << 31) } eActionGroup_Flag; @@ -757,7 +757,7 @@ typedef enum ACHAN_FLAG { ACHAN_EXPANDED = (1 << 4), ACHAN_SHOWIPO = (1 << 5), ACHAN_SHOWCONS = (1 << 6), - ACHAN_MOVED = (1 << 31) + ACHAN_MOVED = (1u << 31) } ACHAN_FLAG; #endif /* __DNA_ACTION_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index e50a2637fff..935a893f689 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -685,7 +685,7 @@ typedef enum eNlaStrip_Flag { /* temporary editing flags */ /* NLA-Strip is really just a temporary meta used to facilitate easier transform code */ NLASTRIP_FLAG_TEMP_META = (1<<30), - NLASTRIP_FLAG_EDIT_TOUCHED = (1<<31) + NLASTRIP_FLAG_EDIT_TOUCHED = (1u << 31) } eNlaStrip_Flag; /* NLA Strip Type */ diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index f4a1677efc4..67a35d4e207 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -210,7 +210,7 @@ typedef enum BrushFlags { BRUSH_CUSTOM_ICON = (1 << 28), BRUSH_LINE = (1 << 29), BRUSH_ABSOLUTE_JITTER = (1 << 30), - BRUSH_CURVE = (1 << 31) + BRUSH_CURVE = (1u << 31) } BrushFlags; typedef enum { @@ -315,7 +315,21 @@ enum { PAINT_BLEND_MUL = 3, PAINT_BLEND_BLUR = 4, PAINT_BLEND_LIGHTEN = 5, - PAINT_BLEND_DARKEN = 6 + PAINT_BLEND_DARKEN = 6, + PAINT_BLEND_AVERAGE = 7, + PAINT_BLEND_SMEAR = 8, + PAINT_BLEND_COLORDODGE = 9, + PAINT_BLEND_DIFFERENCE = 10, + PAINT_BLEND_SCREEN = 11, + PAINT_BLEND_HARDLIGHT = 12, + PAINT_BLEND_OVERLAY = 13, + PAINT_BLEND_SOFTLIGHT = 14, + PAINT_BLEND_EXCLUSION = 15, + PAINT_BLEND_LUMINOCITY = 16, + PAINT_BLEND_SATURATION = 17, + PAINT_BLEND_HUE = 18, + PAINT_BLEND_ALPHA_SUB = 19, + PAINT_BLEND_ALPHA_ADD = 20, }; typedef enum { diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 823a7f0812f..64856b2eb76 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -98,7 +98,7 @@ typedef enum ModifierMode { eModifierMode_Expanded = (1 << 4), eModifierMode_Virtual = (1 << 5), eModifierMode_ApplyOnSpline = (1 << 6), - eModifierMode_DisableTemporary = (1 << 31) + eModifierMode_DisableTemporary = (1u << 31) } ModifierMode; typedef struct ModifierData { @@ -278,6 +278,7 @@ typedef struct MirrorModifierData { short flag; float tolerance; float uv_offset[2]; + float uv_offset_copy[2]; struct Object *mirror_ob; } MirrorModifierData; @@ -654,7 +655,8 @@ typedef struct BooleanModifierData { struct Object *object; char operation; char solver; - char pad[2]; + char pad; + char bm_flag; float double_threshold; } BooleanModifierData; @@ -669,6 +671,13 @@ typedef enum { eBooleanModifierSolver_BMesh = 1, } BooleanSolver; +/* bm_flag (only used when G_DEBUG) */ +enum { + eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 0), + eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 1), + eBooleanModifierBMeshFlag_BMesh_NoConnectRegions = (1 << 2), +}; + typedef struct MDefInfluence { int vertex; float weight; @@ -924,9 +933,10 @@ typedef struct ScrewModifierData { unsigned int iter; float screw_ofs; float angle; - char axis; - char pad; + float merge_dist; short flag; + char axis; + char pad[5]; } ScrewModifierData; enum { @@ -937,6 +947,7 @@ enum { MOD_SCREW_SMOOTH_SHADING = (1 << 5), MOD_SCREW_UV_STRETCH_U = (1 << 6), MOD_SCREW_UV_STRETCH_V = (1 << 7), + MOD_SCREW_MERGE = (1 << 8), }; typedef struct OceanModifierData { @@ -1515,7 +1526,7 @@ enum { MOD_DATATRANSFER_USE_VERT = 1 << 28, MOD_DATATRANSFER_USE_EDGE = 1 << 29, MOD_DATATRANSFER_USE_LOOP = 1 << 30, - MOD_DATATRANSFER_USE_POLY = 1 << 31, + MOD_DATATRANSFER_USE_POLY = 1u << 31, }; /* Set Split Normals modifier */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index b922ac072b0..e6bc315b728 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -111,7 +111,7 @@ typedef struct bNodeSocket { short stack_index; /* local stack index */ /* XXX deprecated, kept for forward compatibility */ short stack_type DNA_DEPRECATED; - int pad; + char draw_shape, pad[3]; void *cache; /* cached data from execution */ @@ -143,6 +143,13 @@ typedef enum eNodeSocketDatatype { SOCK_STRING = 7 } eNodeSocketDatatype; +/* socket shape */ +typedef enum eNodeSocketDrawShape { + SOCK_DRAW_SHAPE_CIRCLE = 0, + SOCK_DRAW_SHAPE_SQUARE = 1, + SOCK_DRAW_SHAPE_DIAMOND = 2 +} eNodeSocketDrawShape; + /* socket side (input/output) */ typedef enum eNodeSocketInOut { SOCK_IN = 1, diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 6d79e6d49f8..0f341aa4001 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -683,6 +683,9 @@ typedef enum ObjectMode { /* any mode where the brush system is used */ #define OB_MODE_ALL_PAINT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT) +/* any mode that uses ob->sculpt */ +#define OB_MODE_ALL_SCULPT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) + #define MAX_DUPLI_RECUR 8 #ifdef __cplusplus diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 92c789f2feb..76cac158b5f 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -99,42 +99,6 @@ typedef struct AviCodecData { char avicodecname[128]; } AviCodecData; -typedef struct QuicktimeCodecData { - /*Old quicktime implementation compatibility fields, read only in 2.5 - deprecated*/ - void *cdParms; /* codec/compressor options */ - void *pad; /* padding */ - - unsigned int cdSize; /* size of cdParms buffer */ - unsigned int pad2; /* padding */ - - char qtcodecname[128]; -} QuicktimeCodecData; - -typedef struct QuicktimeCodecSettings { - /* Codec settings detailed for 2.5 implementation*/ - int codecType; /* Types defined in quicktime_export.h */ - int codecSpatialQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */ - - /* Settings not available in current QTKit API */ - int codec; - int codecFlags; - int colorDepth; - int codecTemporalQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */ - int minSpatialQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */ - int minTemporalQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */ - int keyFrameRate; - int bitRate; /* bitrate in bps */ - - /* Audio Codec settings */ - int audiocodecType; - int audioSampleRate; - short audioBitDepth; - short audioChannels; - int audioCodecFlags; - int audioBitRate; - int pad1; -} QuicktimeCodecSettings; - typedef enum FFMpegPreset { FFM_PRESET_NONE, FFM_PRESET_ULTRAFAST, @@ -456,7 +420,7 @@ typedef struct ImageFormatData { #define R_IMF_IMTYPE_AVIJPEG 16 #define R_IMF_IMTYPE_PNG 17 /* #define R_IMF_IMTYPE_AVICODEC 18 */ /* avicodec is nomore */ -#define R_IMF_IMTYPE_QUICKTIME 19 +/* #define R_IMF_IMTYPE_QUICKTIME 19 */ /* quicktime is nomore */ #define R_IMF_IMTYPE_BMP 20 #define R_IMF_IMTYPE_RADHDR 21 #define R_IMF_IMTYPE_TIFF 22 @@ -585,8 +549,6 @@ typedef struct RenderData { struct ImageFormatData im_format; struct AviCodecData *avicodecdata; - struct QuicktimeCodecData *qtcodecdata; - struct QuicktimeCodecSettings qtcodecsettings; struct FFMpegCodecData ffcodecdata; int cfra, sfra, efra; /* frames as in 'images' */ @@ -751,7 +713,7 @@ typedef struct RenderData { /* sequencer options */ char seq_prev_type; - char seq_rend_type; + char seq_rend_type; /* UNUSED! */ char seq_flag; /* flag use for sequence render/draw */ char pad5[5]; @@ -790,14 +752,13 @@ typedef struct RenderData { struct BakeData bake; int preview_start_resolution; + short preview_pixel_size; /* Type of the debug pass to use. * Only used when built with debug passes support. */ short debug_pass_type; - short pad; - /* MultiView */ ListBase views; /* SceneRenderView */ short actview; @@ -1156,13 +1117,8 @@ typedef struct UvSculpt { /* Vertex Paint */ typedef struct VPaint { Paint paint; - short flag, pad; - int tot; /* allocation size of prev buffers */ - unsigned int *vpaint_prev; /* previous mesh colors */ - struct MDeformVert *wpaint_prev; /* previous vertex weights */ - - void *paintcursor; /* wm handle */ + int radial_symm[3]; /* For mirrored painting */ } VPaint; /* VPaint.flag */ @@ -1668,8 +1624,7 @@ typedef struct Scene { struct Object *obedit; /* name replaces old G.obedit */ float cursor[3]; /* 3d cursor location */ - float twcent[3]; /* center for transform widget */ - float twmin[3], twmax[3]; /* boundbox of selection for transform widget */ + char _pad[4]; unsigned int lay; /* bitflags for layer visibility */ int layact; /* active layer */ @@ -1730,6 +1685,8 @@ typedef struct Scene { /* Movie Tracking */ struct MovieClip *clip; /* active movie clip */ + void *pad4; + uint64_t customdata_mask; /* XXX. runtime flag for drawing, actually belongs in the window, only used by BKE_object_handle_update() */ uint64_t customdata_mask_modal; /* XXX. same as above but for temp operator use (gl renders) */ @@ -1750,8 +1707,7 @@ typedef struct Scene { /* use preview range */ #define SCER_PRV_RANGE (1<<0) #define SCER_LOCK_FRAME_SELECTION (1<<1) - /* timeline/keyframe jumping - only selected items (on by default) */ -#define SCE_KEYS_NO_SELONLY (1<<2) + /* show/use subframes (for checking motion blur) */ #define SCER_SHOW_SUBFRAME (1<<3) /* mode (int now) */ @@ -1791,7 +1747,7 @@ typedef struct Scene { #define R_USE_WS_SHADING 0x8000000 /* use world space interpretation of lighting data */ /* seq_flag */ -#define R_SEQ_GL_PREV 1 +// #define R_SEQ_GL_PREV 1 // UNUSED, we just use setting from seq_prev_type now. // #define R_SEQ_GL_REND 2 // UNUSED, opengl render has its own operator now. #define R_SEQ_SOLID_TEX 4 @@ -1936,16 +1892,18 @@ extern const char *RE_engine_id_CYCLES; /* **************** SCENE ********************* */ /* note that much higher maxframes give imprecise sub-frames, see: T46859 */ +/* Current precision is 16 for the sub-frames closer to MAXFRAME. */ + /* for general use */ -#define MAXFRAME 500000 -#define MAXFRAMEF 500000.0f +#define MAXFRAME 1048574 +#define MAXFRAMEF 1048574.0f #define MINFRAME 0 #define MINFRAMEF 0.0f /* (minimum frame number for current-frame) */ -#define MINAFRAME -500000 -#define MINAFRAMEF -500000.0f +#define MINAFRAME -1048574 +#define MINAFRAMEF -1048574.0f /* depricate this! */ #define TESTBASE(v3d, base) ( \ @@ -2085,6 +2043,7 @@ typedef enum eVGroupSelect { #define SCE_DS_COLLAPSED (1<<1) #define SCE_NLA_EDIT_ON (1<<2) #define SCE_FRAME_DROP (1<<3) +#define SCE_KEYS_NO_SELONLY (1<<4) /* return flag BKE_scene_base_iter_next functions */ diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index e208ef39719..fd63d7c471c 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -366,7 +366,7 @@ enum { /* uiList filter orderby type */ enum { UILST_FLT_SORT_ALPHA = 1 << 0, - UILST_FLT_SORT_REVERSE = 1 << 31 /* Special value, bitflag used to reverse order! */ + UILST_FLT_SORT_REVERSE = 1u << 31 /* Special value, bitflag used to reverse order! */ }; #define UILST_FLT_SORT_MASK (((unsigned int)UILST_FLT_SORT_REVERSE) - 1) diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 1f4e4df4660..74a1a13c2eb 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -442,7 +442,7 @@ enum { /* access scene strips directly (like a metastrip) */ SEQ_SCENE_STRIPS = (1 << 30), - SEQ_INVALID_EFFECT = (1 << 31), + SEQ_INVALID_EFFECT = (1u << 31), }; /* StripProxy->storage */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 0e5d9bd33e6..d6490d99016 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -741,7 +741,7 @@ typedef enum eFileSel_File_Types { FILE_TYPE_ALEMBIC = (1 << 16), FILE_TYPE_DIR = (1 << 30), /* An FS directory (i.e. S_ISDIR on its path is true). */ - FILE_TYPE_BLENDERLIB = (1 << 31), + FILE_TYPE_BLENDERLIB = (1u << 31), } eFileSel_File_Types; /* Selection Flags in filesel: struct direntry, unsigned char selflag */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 5e7e7366e35..cddb1e06b8c 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -48,7 +48,8 @@ struct ColorBand; #define MAX_STYLE_NAME 64 -/* default uifont_id offered by Blender */ +/* default offered by Blender. + * uiFont.uifont_id */ typedef enum eUIFont_ID { UIFONT_DEFAULT = 0, /* UIFONT_BITMAP = 1 */ /* UNUSED */ @@ -64,7 +65,7 @@ typedef struct uiFont { struct uiFont *next, *prev; char filename[1024];/* 1024 = FILE_MAX */ short blf_id; /* from blfont lib */ - short uifont_id; /* own id */ + short uifont_id; /* own id (eUIFont_ID) */ short r_to_l; /* fonts that read from left to right */ short hinting; } uiFont; @@ -84,7 +85,7 @@ typedef struct uiFontStyle { float shadowcolor; /* 1 value, typically white or black anyway */ } uiFontStyle; -/* uiFontStyle->align */ +/* uiFontStyle.align */ typedef enum eFontStyle_Align { UI_STYLE_TEXT_LEFT = 0, UI_STYLE_TEXT_CENTER = 1, @@ -354,11 +355,11 @@ typedef struct ThemeWireColor { char select[4]; char active[4]; - short flag; + short flag; /* eWireColor_Flags */ short pad; } ThemeWireColor; -/* flags for ThemeWireColor */ +/* ThemeWireColor.flag */ typedef enum eWireColor_Flags { TH_WIRECOLOR_CONSTCOLS = (1 << 0), TH_WIRECOLOR_TEXTCOLS = (1 << 1), @@ -434,7 +435,8 @@ typedef struct UserDef { /* UserDef has separate do-version handling, and can be read from other files */ int versionfile, subversionfile; - int flag, dupflag; + int flag; /* eUserPref_Flag */ + int dupflag; /* eDupli_ID_Flags */ int savetime; char tempdir[768]; /* FILE_MAXDIR length */ char fontdir[768]; @@ -450,14 +452,15 @@ typedef struct UserDef { int anim_player_preset; short v2d_min_gridsize; /* minimum spacing between gridlines in View2D grids */ - short timecode_style; /* style of timecode display */ + short timecode_style; /* eTimecodeStyles, style of timecode display */ short versions; short dbl_click_time; short gameflags; short wheellinescroll; - int uiflag, uiflag2; + int uiflag; /* eUserpref_UI_Flag */ + int uiflag2; /* eUserpref_UI_Flag2 */ int language; short userpref, viewzoom; @@ -470,10 +473,10 @@ typedef struct UserDef { int scrollback; /* console scrollback limit */ int dpi; /* range 48-128? */ float ui_scale; /* interface scale */ - int pad1; + int ui_line_width; /* interface line width */ char node_margin; /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */ char pad2; - short transopts; + short transopts; /* eUserpref_Translation_Flags */ short menuthreshold1, menuthreshold2; /* startup template */ @@ -491,12 +494,12 @@ typedef struct UserDef { short undosteps; short undomemory; short gp_manhattendist, gp_euclideandist, gp_eraser; - short gp_settings; + short gp_settings; /* eGP_UserdefSettings */ short tb_leftmouse, tb_rightmouse; struct SolidLight light[3]; short tw_hotspot, tw_flag, tw_handlesize, tw_size; short textimeout, texcollectrate; - short wmdrawmethod; /* removed wmpad */ + short wmdrawmethod; /* eWM_DrawMethod */ short dragthreshold; int memcachelimit; int prefetchframes; @@ -509,13 +512,13 @@ typedef struct UserDef { short smooth_viewtx; /* miliseconds to spend spinning the view */ short glreslimit; short curssize; - short color_picker_type; + short color_picker_type; /* eColorPicker_Types */ char ipo_new; /* interpolation mode for newly added F-Curves */ char keyhandles_new; /* handle types for newly added keyframes */ char gpu_select_method; char gpu_select_pick_deph; char pad4; - char view_frame_type; + char view_frame_type; /* eZoomFrame_Mode */ int view_frame_keyframes; /* number of keyframes to zoom around current frame */ float view_frame_seconds; /* seconds to zoom around current frame */ @@ -530,15 +533,16 @@ typedef struct UserDef { float ndof_sensitivity; /* overall sensitivity of 3D mouse */ float ndof_orbit_sensitivity; float ndof_deadzone; /* deadzone of 3D mouse */ - int ndof_flag; /* flags for 3D mouse */ + int ndof_flag; /* eNdof_Flag, flags for 3D mouse */ - short ogl_multisamples; /* amount of samples for OpenGL FSA, if zero no FSA */ + short ogl_multisamples; /* eMultiSample_Type, amount of samples for OpenGL FSA, if zero no FSA */ - short image_draw_method; /* Method to be used to draw the images (AUTO, GLSL, Textures or DrawPixels) */ + /* eImageDrawMethod, Method to be used to draw the images (AUTO, GLSL, Textures or DrawPixels) */ + short image_draw_method; float glalphaclip; - short autokey_mode; /* autokeying mode */ + short autokey_mode; /* eAutokey_Mode, autokeying mode */ short autokey_flag; /* flags for autokeying */ short text_render, pad9; /* options for text rendering */ @@ -582,7 +586,7 @@ extern UserDef U; /* from blenkernel blender.c */ /* ***************** USERDEF ****************** */ -/* userpref/section */ +/* UserDef.userpref (UI active_section) */ typedef enum eUserPref_Section { USER_SECTION_INTERFACE = 0, USER_SECTION_EDIT = 1, @@ -593,19 +597,19 @@ typedef enum eUserPref_Section { USER_SECTION_ADDONS = 6, } eUserPref_Section; -/* flag */ +/* UserDef.flag */ typedef enum eUserPref_Flag { USER_AUTOSAVE = (1 << 0), -/* USER_AUTOGRABGRID = (1 << 1), deprecated */ -/* USER_AUTOROTGRID = (1 << 2), deprecated */ -/* USER_AUTOSIZEGRID = (1 << 3), deprecated */ + USER_FLAG_DEPRECATED_1 = (1 << 1), /* cleared */ + USER_FLAG_DEPRECATED_2 = (1 << 2), /* cleared */ + USER_FLAG_DEPRECATED_3 = (1 << 3), /* cleared */ USER_SCENEGLOBAL = (1 << 4), USER_TRACKBALL = (1 << 5), -/* USER_DUPLILINK = (1 << 6), deprecated */ -/* USER_FSCOLLUM = (1 << 7), deprecated */ + USER_FLAG_DEPRECATED_6 = (1 << 6), /* cleared */ + USER_FLAG_DEPRECATED_7 = (1 << 7), /* cleared */ USER_MAT_ON_OB = (1 << 8), -/* USER_NO_CAPSLOCK = (1 << 9), */ /* not used anywhere */ -/* USER_VIEWMOVE = (1 << 10), */ /* not used anywhere */ + USER_FLAG_DEPRECATED_9 = (1 << 9), /* cleared */ + USER_FLAG_DEPRECATED_10 = (1 << 10), /* cleared */ USER_TOOLTIPS = (1 << 11), USER_TWOBUTTONMOUSE = (1 << 12), USER_NONUMPAD = (1 << 13), @@ -624,7 +628,7 @@ typedef enum eUserPref_Flag { USER_TOOLTIPS_PYTHON = (1 << 26), } eUserPref_Flag; -/* flag */ +/* bPathCompare.flag */ typedef enum ePathCompare_Flag { USER_PATHCMP_GLOB = (1 << 0), } ePathCompare_Flag; @@ -635,33 +639,34 @@ typedef enum ePathCompare_Flag { cfra = 0; \ } (void)0 -/* viewzoom */ +/* UserDef.viewzoom */ typedef enum eViewZoom_Style { USER_ZOOM_CONT = 0, USER_ZOOM_SCALE = 1, USER_ZOOM_DOLLY = 2 } eViewZoom_Style; -/* navigation_mode */ +/* UserDef.navigation_mode */ typedef enum eViewNavigation_Method { VIEW_NAVIGATION_WALK = 0, VIEW_NAVIGATION_FLY = 1, } eViewNavigation_Method; -/* flag */ +/* UserDef.flag */ typedef enum eWalkNavigation_Flag { USER_WALK_GRAVITY = (1 << 0), USER_WALK_MOUSE_REVERSE = (1 << 1), } eWalkNavigation_Flag; -/* uiflag */ +/* UserDef.uiflag */ typedef enum eUserpref_UI_Flag { /* flags 0 and 1 were old flags (for autokeying) that aren't used anymore */ USER_WHEELZOOMDIR = (1 << 2), USER_FILTERFILEEXTS = (1 << 3), USER_DRAWVIEWINFO = (1 << 4), USER_PLAINMENUS = (1 << 5), - /* flags 6 and 7 were old flags that are no-longer used */ + USER_LOCK_CURSOR_ADJUST = (1 << 6), + USER_UIFLAG_DEPRECATED_7 = (1 << 7), /* cleared */ USER_ALLWINCODECS = (1 << 8), USER_MENUOPENAUTO = (1 << 9), USER_ZBUF_CURSOR = (1 << 10), @@ -685,17 +690,18 @@ typedef enum eUserpref_UI_Flag { USER_HIDE_RECENT = (1 << 28), USER_SHOW_THUMBNAILS = (1 << 29), USER_QUIT_PROMPT = (1 << 30), - USER_HIDE_SYSTEM_BOOKMARKS = (1 << 31) + USER_HIDE_SYSTEM_BOOKMARKS = (1u << 31) } eUserpref_UI_Flag; -/* uiflag2 */ +/* UserDef.uiflag2 */ typedef enum eUserpref_UI_Flag2 { USER_KEEP_SESSION = (1 << 0), USER_REGION_OVERLAP = (1 << 1), USER_TRACKPAD_NATURAL = (1 << 2), } eUserpref_UI_Flag2; -/* Auto-Keying mode */ +/* Auto-Keying mode. + * UserDef.autokey_mode */ typedef enum eAutokey_Mode { /* AUTOKEY_ON is a bitflag */ AUTOKEY_ON = 1, @@ -705,7 +711,8 @@ typedef enum eAutokey_Mode { AUTOKEY_MODE_EDITKEYS = 5 } eAutokey_Mode; -/* Zoom to frame mode */ +/* Zoom to frame mode. + * UserDef.view_frame_type */ typedef enum eZoomFrame_Mode { ZOOM_FRAME_MODE_KEEP_RANGE = 0, ZOOM_FRAME_MODE_SECONDS = 1, @@ -728,20 +735,20 @@ typedef enum eAutokey_Flag { ANIMRECORD_FLAG_WITHNLA = (1 << 10), } eAutokey_Flag; -/* transopts */ +/* UserDef.transopts */ typedef enum eUserpref_Translation_Flags { USER_TR_TOOLTIPS = (1 << 0), USER_TR_IFACE = (1 << 1), -/* USER_TR_MENUS = (1 << 2), deprecated */ -/* USER_TR_FILESELECT = (1 << 3), deprecated */ -/* USER_TR_TEXTEDIT = (1 << 4), deprecated */ + USER_TR_DEPRECATED_2 = (1 << 2), /* cleared */ + USER_TR_DEPRECATED_3 = (1 << 3), /* cleared */ + USER_TR_DEPRECATED_4 = (1 << 4), /* cleared */ USER_DOTRANSLATE = (1 << 5), - USER_USETEXTUREFONT = (1 << 6), -/* CONVERT_TO_UTF8 = (1 << 7), deprecated */ + USER_TR_DEPRECATED_6 = (1 << 6), /* cleared */ + USER_TR_DEPRECATED_7 = (1 << 7), /* cleared */ USER_TR_NEWDATANAME = (1 << 8), } eUserpref_Translation_Flags; -/* dupflag */ +/* UserDef.dupflag */ typedef enum eDupli_ID_Flags { USER_DUP_MESH = (1 << 0), USER_DUP_CURVE = (1 << 1), @@ -757,14 +764,13 @@ typedef enum eDupli_ID_Flags { USER_DUP_PSYS = (1 << 11) } eDupli_ID_Flags; -/* gameflags */ +/* UserDef.gameflags */ typedef enum eOpenGL_RenderingOptions { - /* USER_DEPRECATED_FLAG = (1 << 0), */ - /* USER_DISABLE_SOUND = (1 << 1), */ /* deprecated, don't use without checking for */ - /* backwards compatibilty in do_versions! */ - USER_DISABLE_MIPMAP = (1 << 2), - /* USER_DISABLE_VBO = (1 << 3), */ /* DEPRECATED we always use vertex buffers now */ - /* USER_DISABLE_AA = (1 << 4), */ /* DEPRECATED */ + USER_GL_RENDER_DEPRECATED_0 = (1 << 0), + USER_GL_RENDER_DEPRECATED_1 = (1 << 1), + USER_DISABLE_MIPMAP = (1 << 2), + USER_GL_RENDER_DEPRECATED_3 = (1 << 3), + USER_GL_RENDER_DEPRECATED_4 = (1 << 4), } eOpenGL_RenderingOptions; /* selection method for opengl gpu_select_method */ @@ -774,7 +780,8 @@ typedef enum eOpenGL_SelectOptions { USER_SELECT_USE_SELECT_RENDERMODE = 2 } eOpenGL_SelectOptions; -/* wm draw method */ +/* wm draw method. + * UserDef.wmdrawmethod */ typedef enum eWM_DrawMethod { USER_DRAW_TRIPLE = 0, USER_DRAW_OVERLAP = 1, @@ -783,20 +790,23 @@ typedef enum eWM_DrawMethod { USER_DRAW_OVERLAP_FLIP = 4, } eWM_DrawMethod; -/* text draw options */ +/* text draw options + * UserDef.text_render */ typedef enum eText_Draw_Options { USER_TEXT_DISABLE_AA = (1 << 0), } eText_Draw_Options; /* tw_flag (transform widget) */ -/* gp_settings (Grease Pencil Settings) */ +/* Grease Pencil Settings. + * UserDef.gp_settings */ typedef enum eGP_UserdefSettings { GP_PAINT_DOSMOOTH = (1 << 0), GP_PAINT_DOSIMPLIFY = (1 << 1), } eGP_UserdefSettings; -/* color picker types */ +/* Color Picker Types. + * UserDef.color_picker_type */ typedef enum eColorPicker_Types { USER_CP_CIRCLE_HSV = 0, USER_CP_SQUARE_SV = 1, @@ -805,7 +815,8 @@ typedef enum eColorPicker_Types { USER_CP_CIRCLE_HSL = 4, } eColorPicker_Types; -/* timecode display styles */ +/* timecode display styles + * UserDef.timecode_style */ typedef enum eTimecodeStyles { /* as little info as is necessary to show relevant info * with '+' to denote the frames @@ -840,7 +851,7 @@ typedef enum eTheme_DrawTypes { TH_SHADED = 4 } eTheme_DrawTypes; -/* ndof_flag (3D mouse options) */ +/* UserDef.ndof_flag (3D mouse options) */ typedef enum eNdof_Flag { NDOF_SHOW_GUIDE = (1 << 0), NDOF_FLY_HELICOPTER = (1 << 1), @@ -873,6 +884,7 @@ typedef enum eNdof_Flag { #define NDOF_PIXELS_PER_SECOND 600.0f +/* UserDef.ogl_multisamples */ typedef enum eMultiSample_Type { USER_MULTISAMPLE_NONE = 0, USER_MULTISAMPLE_2 = 2, @@ -880,7 +892,8 @@ typedef enum eMultiSample_Type { USER_MULTISAMPLE_8 = 8, USER_MULTISAMPLE_16 = 16, } eMultiSample_Type; - + +/* UserDef.image_draw_method */ typedef enum eImageDrawMethod { /* IMAGE_DRAW_METHOD_AUTO = 0, */ /* Currently unused */ IMAGE_DRAW_METHOD_GLSL = 1, @@ -888,6 +901,7 @@ typedef enum eImageDrawMethod { IMAGE_DRAW_METHOD_DRAWPIXELS = 3, } eImageDrawMethod; +/* UserDef.virtual_pixel */ typedef enum eUserpref_VirtualPixel { VIRTUAL_PIXEL_NATIVE = 0, VIRTUAL_PIXEL_DOUBLE = 1, diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 4c243507e82..b9894d46b5b 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -225,7 +225,8 @@ typedef struct View3D { struct GPUFXSettings fx_settings; void *properties_storage; /* Nkey panel stores stuff here (runtime only!) */ - struct Material *defmaterial; /* used by matcap now */ + /* Allocated per view, not library data (used by matcap). */ + struct Material *defmaterial; /* XXX deprecated? */ struct bGPdata *gpd DNA_DEPRECATED; /* Grease-Pencil Data (annotation layers) */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index a1af3f98274..178d2d398e9 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -488,7 +488,6 @@ extern StructRNA RNA_PropertyGroupItem; extern StructRNA RNA_PropertySensor; extern StructRNA RNA_PythonConstraint; extern StructRNA RNA_PythonController; -extern StructRNA RNA_QuickTimeSettings; extern StructRNA RNA_RadarSensor; extern StructRNA RNA_RandomSensor; extern StructRNA RNA_RaySensor; @@ -783,6 +782,9 @@ const struct ListBase *RNA_struct_type_functions(StructRNA *srna); char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len); +bool RNA_struct_available_or_report(struct ReportList *reports, const char *identifier); +bool RNA_struct_bl_idname_ok_or_report(struct ReportList *reports, const char *identifier, const char *sep); + /* Properties * * Access to struct properties. All this works with RNA pointers rather than @@ -1197,7 +1199,7 @@ StructRNA *ID_code_to_RNA_type(short idcode); } (void)0 /* macro which inserts the function name */ -#if defined __GNUC__ || defined __sun +#if defined __GNUC__ # define RNA_warning(format, args ...) _RNA_warning("%s: " format "\n", __func__, ##args) #else # define RNA_warning(format, ...) _RNA_warning("%s: " format "\n", __FUNCTION__, __VA_ARGS__) diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index 6e62313b00a..42ffe774720 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -62,7 +62,8 @@ void RNA_def_struct_refine_func(StructRNA *srna, const char *refine); void RNA_def_struct_idprops_func(StructRNA *srna, const char *refine); void RNA_def_struct_register_funcs(StructRNA *srna, const char *reg, const char *unreg, const char *instance); void RNA_def_struct_path_func(StructRNA *srna, const char *path); -void RNA_def_struct_identifier(StructRNA *srna, const char *identifier); +void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier); +void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier); void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char *description); void RNA_def_struct_ui_icon(StructRNA *srna, int icon); void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *ext); @@ -216,8 +217,8 @@ void RNA_enum_item_end(EnumPropertyItem **items, int *totitem); /* Memory management */ -void RNA_def_struct_duplicate_pointers(StructRNA *srna); -void RNA_def_struct_free_pointers(StructRNA *srna); +void RNA_def_struct_duplicate_pointers(BlenderRNA *brna, StructRNA *srna); +void RNA_def_struct_free_pointers(BlenderRNA *brna, StructRNA *srna); void RNA_def_func_duplicate_pointers(FunctionRNA *func); void RNA_def_func_free_pointers(FunctionRNA *func); void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA *prop); diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 1c9b3593d17..f8e240d57bf 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -114,6 +114,8 @@ extern EnumPropertyItem rna_enum_brush_image_tool_items[]; extern EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[]; +extern EnumPropertyItem rna_enum_uv_sculpt_tool_items[]; + extern EnumPropertyItem rna_enum_axis_xy_items[]; extern EnumPropertyItem rna_enum_axis_xyz_items[]; diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index cd04f9e8a6d..e119c49401e 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -178,7 +178,7 @@ typedef enum PropertyFlag { * after every typed char, instead of waiting final validation. Used e.g. for text searchbox. * It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag * for search/filter properties, but this works just fine for now. */ - PROP_TEXTEDIT_UPDATE = (1 << 31), + PROP_TEXTEDIT_UPDATE = (1u << 31), /* icon */ PROP_ICONS_CONSECUTIVE = (1 << 12), @@ -436,6 +436,8 @@ typedef enum StructFlag { STRUCT_NO_IDPROPERTIES = (1 << 6), /* Menus and Panels don't need properties */ STRUCT_NO_DATABLOCK_IDPROPERTIES = (1 << 7), /* e.g. for Operator */ STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES = (1 << 8), /* for PropertyGroup which contains pointers to datablocks */ + STRUCT_PUBLIC_NAMESPACE = (1 << 9), /* Added to type-map #BlenderRNA.structs_map */ + STRUCT_PUBLIC_NAMESPACE_INHERIT = (1 << 10), /* All subtypes are added too. */ } StructFlag; typedef int (*StructValidateFunc)(struct PointerRNA *ptr, void *data, int *have_function); diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 6a08d762920..743d192f0c5 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -140,6 +140,9 @@ set(GENSRC_CFLAGS) if(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang")) set(GENSRC_CFLAGS "-Wno-missing-prototypes") endif() +if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(GENSRC_CFLAGS "${GENSRC_CFLAGS} -Wno-missing-variable-declarations") +endif() if(GENSRC_CFLAGS) set_source_files_properties(${GENSRC} PROPERTIES COMPILE_FLAGS "${GENSRC_CFLAGS}") @@ -229,13 +232,6 @@ if(WITH_AUDASPACE) ) endif() -if(WITH_CODEC_QUICKTIME) - list(APPEND INC - ../../quicktime - ) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_CODEC_FFMPEG) list(APPEND INC ../../../../intern/ffmpeg diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index de436172bfd..9471d0e3fcf 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -2583,17 +2583,23 @@ static void rna_generate_blender(BlenderRNA *brna, FILE *f) { StructRNA *srna; - fprintf(f, "BlenderRNA BLENDER_RNA = {"); - + fprintf(f, + "BlenderRNA BLENDER_RNA = {\n" + "\t.structs = {" + ); srna = brna->structs.first; - if (srna) fprintf(f, "{&RNA_%s, ", srna->identifier); - else fprintf(f, "{NULL, "); + if (srna) fprintf(f, "&RNA_%s, ", srna->identifier); + else fprintf(f, "NULL, "); srna = brna->structs.last; - if (srna) fprintf(f, "&RNA_%s}", srna->identifier); - else fprintf(f, "NULL}"); + if (srna) fprintf(f, "&RNA_%s},\n", srna->identifier); + else fprintf(f, "NULL},\n"); - fprintf(f, "};\n\n"); + fprintf(f, + "\t.structs_map = NULL,\n" + "\t.structs_len = 0,\n" + "};\n\n" + ); } static void rna_generate_property_prototypes(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE *f) diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index a74758a4f71..bf767d47994 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -250,9 +250,10 @@ void rna_PropertyGroup_unregister(Main *UNUSED(bmain), StructRNA *type) RNA_struct_free(&BLENDER_RNA, type); } -StructRNA *rna_PropertyGroup_register(Main *UNUSED(bmain), ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc UNUSED(call), - StructFreeFunc UNUSED(free)) +StructRNA *rna_PropertyGroup_register( + Main *UNUSED(bmain), ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc UNUSED(call), + StructFreeFunc UNUSED(free)) { PointerRNA dummyptr; diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 5a4db47d281..bfa1e7cef93 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -76,6 +76,9 @@ void RNA_init(void) StructRNA *srna; PropertyRNA *prop; + BLENDER_RNA.structs_map = BLI_ghash_str_new_ex(__func__, 2048); + BLENDER_RNA.structs_len = 0; + for (srna = BLENDER_RNA.structs.first; srna; srna = srna->cont.next) { if (!srna->cont.prophash) { srna->cont.prophash = BLI_ghash_str_new("RNA_init gh"); @@ -86,6 +89,9 @@ void RNA_init(void) } } } + BLI_assert(srna->flag & STRUCT_PUBLIC_NAMESPACE); + BLI_ghash_insert(BLENDER_RNA.structs_map, (void *)srna->identifier, srna); + BLENDER_RNA.structs_len += 1; } } @@ -513,13 +519,7 @@ static const char *rna_ensure_property_name(const PropertyRNA *prop) StructRNA *RNA_struct_find(const char *identifier) { - StructRNA *type; - if (identifier) { - for (type = BLENDER_RNA.structs.first; type; type = type->cont.next) - if (STREQ(type->identifier, identifier)) - return type; - } - return NULL; + return BLI_ghash_lookup(BLENDER_RNA.structs_map, identifier); } const char *RNA_struct_identifier(const StructRNA *type) @@ -815,6 +815,89 @@ char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, i return NULL; } +/** + * Use when registering structs with the #STRUCT_PUBLIC_NAMESPACE flag. + */ +bool RNA_struct_available_or_report(ReportList *reports, const char *identifier) +{ + const StructRNA *srna_exists = RNA_struct_find(identifier); + if (UNLIKELY(srna_exists != NULL)) { + /* Use comprehensive string construction since this is such a rare occurrence + * and information here may cut down time troubleshooting. */ + DynStr *dynstr = BLI_dynstr_new(); + BLI_dynstr_appendf(dynstr, "Type identifier '%s' is already in use: '", identifier); + BLI_dynstr_append(dynstr, srna_exists->identifier); + int i = 0; + if (srna_exists->base) { + for (const StructRNA *base = srna_exists->base; base; base = base->base) { + BLI_dynstr_append(dynstr, "("); + BLI_dynstr_append(dynstr, base->identifier); + i += 1; + } + while (i--) { + BLI_dynstr_append(dynstr, ")"); + } + } + BLI_dynstr_append(dynstr, "'."); + char *result = BLI_dynstr_get_cstring(dynstr); + BLI_dynstr_free(dynstr); + BKE_report(reports, RPT_ERROR, result); + MEM_freeN(result); + return false; + } + else { + return true; + } +} + +bool RNA_struct_bl_idname_ok_or_report(ReportList *reports, const char *identifier, const char *sep) +{ + const int len_sep = strlen(sep); + const int len_id = strlen(identifier); + const char *p = strstr(identifier, sep); + /* TODO: make error, for now warning until add-ons update. */ +#if 1 + const int report_level = RPT_WARNING; + const bool failure = true; +#else + const int report_level = RPT_ERROR; + const bool failure = false; +#endif + if (p == NULL || p == identifier || p + len_sep >= identifier + len_id) { + BKE_reportf(reports, report_level, "'%s' doesn't contain '%s' with prefix & suffix", identifier, sep); + return failure; + } + + const char *c, *start, *end, *last; + start = identifier; + end = p; + last = end - 1; + for (c = start; c != end; c++) { + if (((*c >= 'A' && *c <= 'Z') || + ((c != start) && (*c >= '0' && *c <= '9')) || + ((c != start) && (c != last) && (*c == '_'))) == 0) + { + BKE_reportf(reports, report_level, "'%s' doesn't have upper case alpha-numeric prefix", identifier); + return failure; + } + } + + start = p + len_sep; + end = identifier + len_id; + last = end - 1; + for (c = start; c != end; c++) { + if (((*c >= 'A' && *c <= 'Z') || + (*c >= 'a' && *c <= 'z') || + (*c >= '0' && *c <= '9') || + ((c != start) && (c != last) && (*c == '_'))) == 0) + { + BKE_reportf(reports, report_level, "'%s' doesn't have an alpha-numeric suffix", identifier); + return failure; + } + } + return true; +} + /* Property Information */ const char *RNA_property_identifier(PropertyRNA *prop) diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index f271bccd326..47b2c84a67f 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -246,8 +246,9 @@ static void rna_KeyingSetInfo_unregister(Main *bmain, StructRNA *type) ANIM_keyingset_info_unregister(bmain, ksi); } -static StructRNA *rna_KeyingSetInfo_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_KeyingSetInfo_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { KeyingSetInfo dummyksi = {NULL}; KeyingSetInfo *ksi; @@ -270,9 +271,10 @@ static StructRNA *rna_KeyingSetInfo_register(Main *bmain, ReportList *reports, v /* check if we have registered this info before, and remove it */ ksi = ANIM_keyingset_info_find_name(dummyksi.idname); - if (ksi && ksi->ext.srna) + if (ksi && ksi->ext.srna) { rna_KeyingSetInfo_unregister(bmain, ksi->ext.srna); - + } + /* create a new KeyingSetInfo type */ ksi = MEM_callocN(sizeof(KeyingSetInfo), "python keying set info"); memcpy(ksi, &dummyksi, sizeof(KeyingSetInfo)); diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 891f5c43ca6..ec700eb00de 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -480,7 +480,7 @@ static int rna_Armature_is_editmode_get(PointerRNA *ptr) static void rna_Armature_transform(struct bArmature *arm, float *mat) { - ED_armature_transform(arm, (float (*)[4])mat); + ED_armature_transform(arm, (float (*)[4])mat, true); } #else diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index ac348c1750c..fe8e1bb7e6e 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -94,6 +94,21 @@ EnumPropertyItem rna_enum_brush_vertex_tool_items[] = { {PAINT_BLEND_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", "Blur the color with surrounding values"}, {PAINT_BLEND_LIGHTEN, "LIGHTEN", ICON_BRUSH_LIGHTEN, "Lighten", "Use lighten blending mode while painting"}, {PAINT_BLEND_DARKEN, "DARKEN", ICON_BRUSH_DARKEN, "Darken", "Use darken blending mode while painting"}, + {PAINT_BLEND_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", "Use average blending mode while painting"}, + {PAINT_BLEND_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", "Use smear blending mode while painting"}, + {PAINT_BLEND_COLORDODGE, "COLORDODGE", ICON_BRUSH_BLUR, "Color Dodge", "Use color dodge blending mode while painting" }, + {PAINT_BLEND_DIFFERENCE, "DIFFERENCE", ICON_BRUSH_BLUR, "Difference", "Use difference blending mode while painting"}, + {PAINT_BLEND_SCREEN, "SCREEN", ICON_BRUSH_BLUR, "Screen", "Use screen blending mode while painting"}, + {PAINT_BLEND_HARDLIGHT, "HARDLIGHT", ICON_BRUSH_BLUR, "Hardlight", "Use hardlight blending mode while painting"}, + {PAINT_BLEND_OVERLAY, "OVERLAY", ICON_BRUSH_BLUR, "Overlay", "Use overlay blending mode while painting"}, + {PAINT_BLEND_SOFTLIGHT, "SOFTLIGHT", ICON_BRUSH_BLUR, "Softlight", "Use softlight blending mode while painting"}, + {PAINT_BLEND_EXCLUSION, "EXCLUSION", ICON_BRUSH_BLUR, "Exclusion", "Use exclusion blending mode while painting"}, + {PAINT_BLEND_LUMINOCITY, "LUMINOCITY", ICON_BRUSH_BLUR, "Luminocity", "Use luminocity blending mode while painting"}, + {PAINT_BLEND_SATURATION, "SATURATION", ICON_BRUSH_BLUR, "Saturation", "Use saturation blending mode while painting"}, + {PAINT_BLEND_HUE, "HUE", ICON_BRUSH_BLUR, "Hue", "Use hue blending mode while painting"}, + {PAINT_BLEND_ALPHA_SUB, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"}, + {PAINT_BLEND_ALPHA_ADD, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"}, + {0, NULL, 0, NULL, NULL} }; @@ -1248,7 +1263,7 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Restore Mesh", "Allow a single dot to be carefully positioned"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - /* only for projection paint, TODO, other paint modes */ + /* only for projection paint & vertex paint, TODO, other paint modes */ prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BRUSH_LOCK_ALPHA); RNA_def_property_ui_text(prop, "Alpha", "When this is disabled, lock alpha while painting"); diff --git a/source/blender/makesrna/intern/rna_curve_api.c b/source/blender/makesrna/intern/rna_curve_api.c index b4b3aa84ec5..be6808567bb 100644 --- a/source/blender/makesrna/intern/rna_curve_api.c +++ b/source/blender/makesrna/intern/rna_curve_api.c @@ -45,7 +45,7 @@ #ifdef RNA_RUNTIME static void rna_Curve_transform(Curve *cu, float *mat, int shape_keys) { - BKE_curve_transform(cu, (float (*)[4])mat, shape_keys); + BKE_curve_transform(cu, (float (*)[4])mat, shape_keys, true); DAG_id_tag_update(&cu->id, 0); } diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 42c0344f46e..118dd0b15de 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -44,6 +44,8 @@ #include "BLT_translation.h" +#include "UI_interface.h" /* For things like UI_PRECISION_FLOAT_MAX... */ + #include "RNA_define.h" #include "rna_internal.h" @@ -135,6 +137,38 @@ void rna_freelistN(ListBase *listbase) listbase->first = listbase->last = NULL; } +static void rna_brna_structs_add(BlenderRNA *brna, StructRNA *srna) +{ + rna_addtail(&brna->structs, srna); + brna->structs_len += 1; + + /* This exception is only needed for pre-processing. + * otherwise we don't allow empty names. */ + if ((srna->flag & STRUCT_PUBLIC_NAMESPACE) && + (srna->identifier[0] != '\0')) + { + BLI_ghash_insert(brna->structs_map, (void *)srna->identifier, srna); + } +} + +#ifdef RNA_RUNTIME +static void rna_brna_structs_remove_and_free(BlenderRNA *brna, StructRNA *srna) +{ + if ((srna->flag & STRUCT_PUBLIC_NAMESPACE) && brna->structs_map) { + if (srna->identifier[0] != '\0') { + BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, NULL, NULL); + } + } + + RNA_def_struct_free_pointers(NULL, srna); + + if (srna->flag & STRUCT_RUNTIME) { + rna_freelinkN(&brna->structs, srna); + } + brna->structs_len -= 1; +} +#endif + StructDefRNA *rna_find_struct_def(StructRNA *srna) { StructDefRNA *dsrna; @@ -534,6 +568,8 @@ BlenderRNA *RNA_create(void) const char *error_message = NULL; BLI_listbase_clear(&DefRNA.structs); + brna->structs_map = BLI_ghash_str_new_ex(__func__, 2048); + DefRNA.error = 0; DefRNA.preprocess = 1; @@ -640,10 +676,8 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna) rna_freelinkN(&srna->functions, func); } - RNA_def_struct_free_pointers(srna); - if (srna->flag & STRUCT_RUNTIME) - rna_freelinkN(&brna->structs, srna); + rna_brna_structs_remove_and_free(brna, srna); #else UNUSED_VARS(brna, srna); #endif @@ -654,6 +688,9 @@ void RNA_free(BlenderRNA *brna) StructRNA *srna, *nextsrna; FunctionRNA *func; + BLI_ghash_free(brna->structs_map, NULL, NULL); + brna->structs_map = NULL; + if (DefRNA.preprocess) { RNA_define_free(brna); @@ -730,12 +767,19 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN BLI_listbase_clear(&srna->functions); srna->py_type = NULL; + srna->base = srnafrom; + if (DefRNA.preprocess) { - srna->base = srnafrom; dsfrom = rna_find_def_struct(srnafrom); } - else - srna->base = srnafrom; + else { + if (srnafrom->flag & STRUCT_PUBLIC_NAMESPACE_INHERIT) { + srna->flag |= STRUCT_PUBLIC_NAMESPACE | STRUCT_PUBLIC_NAMESPACE_INHERIT; + } + else { + srna->flag &= ~(STRUCT_PUBLIC_NAMESPACE | STRUCT_PUBLIC_NAMESPACE_INHERIT); + } + } } srna->identifier = identifier; @@ -747,7 +791,11 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN if (!srnafrom) srna->icon = ICON_DOT; - rna_addtail(&brna->structs, srna); + if (DefRNA.preprocess) { + srna->flag |= STRUCT_PUBLIC_NAMESPACE; + } + + rna_brna_structs_add(brna, srna); if (DefRNA.preprocess) { ds = MEM_callocN(sizeof(StructDefRNA), "StructDefRNA"); @@ -819,10 +867,8 @@ StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char * if (from) { /* find struct to derive from */ - for (srnafrom = brna->structs.first; srnafrom; srnafrom = srnafrom->cont.next) - if (STREQ(srnafrom->identifier, from)) - break; - + /* Inline RNA_struct_find(...) because it wont link from here. */ + srnafrom = BLI_ghash_lookup(brna->structs_map, from); if (!srnafrom) { fprintf(stderr, "%s: struct %s not found to define %s.\n", __func__, from, identifier); DefRNA.error = 1; @@ -901,10 +947,7 @@ void RNA_def_struct_nested(BlenderRNA *brna, StructRNA *srna, const char *struct StructRNA *srnafrom; /* find struct to derive from */ - for (srnafrom = brna->structs.first; srnafrom; srnafrom = srnafrom->cont.next) - if (STREQ(srnafrom->identifier, structname)) - break; - + srnafrom = BLI_ghash_lookup(brna->structs_map, structname); if (!srnafrom) { fprintf(stderr, "%s: struct %s not found for %s.\n", __func__, structname, srna->identifier); DefRNA.error = 1; @@ -965,7 +1008,32 @@ void RNA_def_struct_path_func(StructRNA *srna, const char *path) if (path) srna->path = (StructPathFunc)path; } -void RNA_def_struct_identifier(StructRNA *srna, const char *identifier) +void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier) +{ + if (DefRNA.preprocess) { + fprintf(stderr, "%s: only at runtime.\n", __func__); + return; + } + + /* Operator registration may set twice, see: operator_properties_init */ + if (srna->flag & STRUCT_PUBLIC_NAMESPACE) { + if (identifier != srna->identifier) { + if (srna->identifier[0] != '\0') { + BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, NULL, NULL); + } + if (identifier[0] != '\0') { + BLI_ghash_insert(brna->structs_map, (void *)identifier, srna); + } + } + } + + srna->identifier = identifier; +} + +/** + * Only used in one case when we name the struct for the purpose of useful error messages. + */ +void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier) { if (DefRNA.preprocess) { fprintf(stderr, "%s: only at runtime.\n", __func__); @@ -1339,13 +1407,13 @@ void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, bool consecutive) * For ints, whole values are used. * * \param precision The number of zeros to show - * (as a whole number - common range is 1 - 6), see PRECISION_FLOAT_MAX + * (as a whole number - common range is 1 - 6), see UI_PRECISION_FLOAT_MAX */ void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision) { StructRNA *srna = DefRNA.laststruct; -#ifdef DEBUG +#ifndef NDEBUG if (min > max) { fprintf(stderr, "%s: \"%s.%s\", min > max.\n", __func__, srna->identifier, prop->identifier); @@ -1358,8 +1426,8 @@ void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double DefRNA.error = 1; } - if (precision < -1 || precision > 10) { - fprintf(stderr, "%s: \"%s.%s\", step outside range.\n", + if (precision < -1 || precision > UI_PRECISION_FLOAT_MAX) { + fprintf(stderr, "%s: \"%s.%s\", precision outside range.\n", __func__, srna->identifier, prop->identifier); DefRNA.error = 1; } @@ -1381,21 +1449,6 @@ void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double fprop->softmax = (float)max; fprop->step = (float)step; fprop->precision = (int)precision; -#if 0 /* handy but annoying */ - if (DefRNA.preprocess) { - /* check we're not over PRECISION_FLOAT_MAX */ - if (fprop->precision > 6) { - fprintf(stderr, "%s: \"%s.%s\", precision value over maximum.\n", - __func__, srna->identifier, prop->identifier); - DefRNA.error = 1; - } - else if (fprop->precision < 1) { - fprintf(stderr, "%s: \"%s.%s\", precision value under minimum.\n", - __func__, srna->identifier, prop->identifier); - DefRNA.error = 1; - } - } -#endif break; } default: @@ -3262,21 +3315,41 @@ void RNA_enum_item_end(EnumPropertyItem **items, int *totitem) /* Memory management */ #ifdef RNA_RUNTIME -void RNA_def_struct_duplicate_pointers(StructRNA *srna) +void RNA_def_struct_duplicate_pointers(BlenderRNA *brna, StructRNA *srna) { - if (srna->identifier) srna->identifier = BLI_strdup(srna->identifier); - if (srna->name) srna->name = BLI_strdup(srna->name); - if (srna->description) srna->description = BLI_strdup(srna->description); + if (srna->identifier) { + srna->identifier = BLI_strdup(srna->identifier); + if (srna->flag & STRUCT_PUBLIC_NAMESPACE) { + BLI_ghash_replace_key(brna->structs_map, (void *)srna->identifier); + } + } + if (srna->name) { + srna->name = BLI_strdup(srna->name); + } + if (srna->description) { + srna->description = BLI_strdup(srna->description); + } srna->flag |= STRUCT_FREE_POINTERS; } -void RNA_def_struct_free_pointers(StructRNA *srna) +void RNA_def_struct_free_pointers(BlenderRNA *brna, StructRNA *srna) { if (srna->flag & STRUCT_FREE_POINTERS) { - if (srna->identifier) MEM_freeN((void *)srna->identifier); - if (srna->name) MEM_freeN((void *)srna->name); - if (srna->description) MEM_freeN((void *)srna->description); + if (srna->identifier) { + if (srna->flag & STRUCT_PUBLIC_NAMESPACE) { + if (brna != NULL) { + BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, NULL, NULL); + } + } + MEM_freeN((void *)srna->identifier); + } + if (srna->name) { + MEM_freeN((void *)srna->name); + } + if (srna->description) { + MEM_freeN((void *)srna->description); + } } } diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 6e0d6ad2bcd..79e1e95b27a 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -74,7 +74,7 @@ static void rna_GPencil_editmode_update(Main *UNUSED(bmain), Scene *UNUSED(scene { /* Notify all places where GPencil data lives that the editing state is different */ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); - WM_main_add_notifier(NC_SCENE | ND_MODE, NULL); + WM_main_add_notifier(NC_SCENE | ND_MODE | NC_MOVIECLIP, NULL); } static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index b6e84cf8ac3..5ca7e624d88 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -192,6 +192,8 @@ static char *rna_ImageUser_path(PointerRNA *ptr) { return rna_Node_ImageUser_path(ptr); } + default: + break; } } diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 344c1781b46..61f1edc0af5 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -67,7 +67,7 @@ static void rna_ImagePackedFile_save(ImagePackedFile *imapf, ReportList *reports) { if (writePackedFile(reports, imapf->filepath, imapf->packedfile, 0) != RET_OK) { - BKE_reportf(reports, RPT_ERROR, "Image could not save packed file to '%s'", + BKE_reportf(reports, RPT_ERROR, "Could not save packed file to disk as '%s'", imapf->filepath); } } @@ -291,7 +291,7 @@ static void rna_Image_filepath_from_user(Image *image, ImageUser *image_user, ch static void rna_Image_buffers_free(Image *image) { - BKE_image_free_buffers(image); + BKE_image_free_buffers_ex(image, true); } #else diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index df591659fdb..a470c807091 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -413,6 +413,11 @@ struct StructRNA { struct BlenderRNA { ListBase structs; + /* A map of structs: {StructRNA.identifier -> StructRNA} + * These are ensured to have unique names (with STRUCT_PUBLIC_NAMESPACE enabled). */ + struct GHash *structs_map; + /* Needed because types with an empty identifier aren't included in 'structs_map'. */ + unsigned int structs_len; }; #define CONTAINER_RNA_ID(cont) (*(const char **)(((ContainerRNA *)(cont))+1)) diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index a5abc8a3be2..b960890457b 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -178,6 +178,8 @@ static Mesh *rna_KeyBlock_normals_get_mesh(PointerRNA *ptr, ID *id) return ob->data; } } + default: + break; } } diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index c110dbff6c4..871f50e992e 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -123,7 +123,8 @@ static void rna_idname_validate(const char *name, char *r_name) } -static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink) +static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, + int do_unlink, int do_id_user, int do_ui_user) { ID *id = id_ptr->data; if (do_unlink) { @@ -131,7 +132,7 @@ static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ RNA_POINTER_INVALIDATE(id_ptr); } else if (ID_REAL_USERS(id) <= 0) { - BKE_libblock_free(bmain, id); + BKE_libblock_free_ex(bmain, id, do_id_user, do_ui_user); RNA_POINTER_INVALIDATE(id_ptr); } else { @@ -184,7 +185,7 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports } } - rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink); + rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink, true, true); } else { BKE_reportf(reports, RPT_ERROR, "Scene '%s' is the last, cannot be removed", scene->id.name + 2); @@ -661,6 +662,10 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this camera before deleting it " "(WARNING: will also delete objects instancing that camera data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this camera"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this camera"); func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -739,6 +744,10 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this object before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this object"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this object"); func = RNA_def_function(srna, "tag", "rna_Main_objects_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -776,6 +785,10 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this material before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this material"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this material"); func = RNA_def_function(srna, "tag", "rna_Main_materials_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -820,6 +833,10 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this node tree before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this node tree"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this node tree"); func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -881,6 +898,10 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mesh before deleting it " "(WARNING: will also delete objects instancing that mesh data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this mesh data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this mesh data"); func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -921,6 +942,10 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this lamp before deleting it " "(WARNING: will also delete objects instancing that lamp data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this lamp data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this lamp data"); func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1037,6 +1062,10 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this image before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this image"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this image"); func = RNA_def_function(srna, "tag", "rna_Main_images_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1076,6 +1105,10 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this lattice before deleting it " "(WARNING: will also delete objects instancing that lattice data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this lattice data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this lattice data"); func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1116,6 +1149,10 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this curve before deleting it " "(WARNING: will also delete objects instancing that curve data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this curve data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this curve data"); func = RNA_def_function(srna, "tag", "rna_Main_curves_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1154,6 +1191,10 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this metaball before deleting it " "(WARNING: will also delete objects instancing that metaball data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this metaball data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this metaball data"); func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1192,6 +1233,10 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this font before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this font"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this font"); func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1230,6 +1275,10 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this texture before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this texture"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this texture"); func = RNA_def_function(srna, "tag", "rna_Main_textures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1267,6 +1316,10 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this brush before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this brush"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this brush"); func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1304,6 +1357,10 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this world before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this world"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this world"); func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1341,6 +1398,10 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this group before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this group"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this group"); func = RNA_def_function(srna, "tag", "rna_Main_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1380,6 +1441,10 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this speaker before deleting it " "(WARNING: will also delete objects instancing that speaker data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this speaker data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this speaker data"); func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1417,6 +1482,10 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this text before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this text"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this text"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_texts_load"); @@ -1467,6 +1536,10 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this sound before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this sound"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this sound"); func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1506,6 +1579,10 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this armature before deleting it " "(WARNING: will also delete objects instancing that armature data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this armature data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this armature data"); func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1542,6 +1619,10 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this action before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this action"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this action"); func = RNA_def_function(srna, "tag", "rna_Main_actions_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1578,6 +1659,10 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of those particle settings before deleting them"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this particle settings"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this particle settings"); func = RNA_def_function(srna, "tag", "rna_Main_particles_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1614,6 +1699,10 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this palette before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this palette"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this palette"); func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1694,6 +1783,10 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this grease pencil before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this grease pencil"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this grease pencil"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1723,6 +1816,10 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this movie clip before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this movie clip"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this movie clip"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_movieclip_load"); @@ -1775,6 +1872,10 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mask before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this mask"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this mask"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1812,6 +1913,10 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this line style before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this line style"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this line style"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index ad5f320625c..650caf20093 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -46,6 +46,7 @@ #include "RNA_access.h" #include "RNA_define.h" #include "RNA_types.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -303,7 +304,7 @@ static float rna_MeshVertex_bevel_weight_get(PointerRNA *ptr) static void rna_MeshVertex_bevel_weight_set(PointerRNA *ptr, float value) { MVert *mvert = (MVert *)ptr->data; - mvert->bweight = (char)(CLAMPIS(value * 255.0f, 0, 255)); + mvert->bweight = round_fl_to_uchar_clamp(value * 255.0f); } static float rna_MEdge_bevel_weight_get(PointerRNA *ptr) @@ -315,7 +316,7 @@ static float rna_MEdge_bevel_weight_get(PointerRNA *ptr) static void rna_MEdge_bevel_weight_set(PointerRNA *ptr, float value) { MEdge *medge = (MEdge *)ptr->data; - medge->bweight = (char)(CLAMPIS(value * 255.0f, 0, 255)); + medge->bweight = round_fl_to_uchar_clamp(value * 255.0f); } static float rna_MEdge_crease_get(PointerRNA *ptr) @@ -327,7 +328,7 @@ static float rna_MEdge_crease_get(PointerRNA *ptr) static void rna_MEdge_crease_set(PointerRNA *ptr, float value) { MEdge *medge = (MEdge *)ptr->data; - medge->crease = (char)(CLAMPIS(value * 255.0f, 0, 255)); + medge->crease = round_fl_to_uchar_clamp(value * 255.0f); } static void rna_MeshLoop_normal_get(PointerRNA *ptr, float *values) @@ -585,15 +586,17 @@ static void rna_MeshColor_color1_set(PointerRNA *ptr, const float *values) { MCol *mcol = (MCol *)ptr->data; - (&mcol[0].r)[2] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255)); - (&mcol[0].r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255)); - (&mcol[0].r)[0] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255)); + (&mcol[0].r)[2] = round_fl_to_uchar_clamp(values[0] * 255.0f); + (&mcol[0].r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f); + (&mcol[0].r)[0] = round_fl_to_uchar_clamp(values[2] * 255.0f); + (&mcol[0].r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f); } static void rna_MeshColor_color2_get(PointerRNA *ptr, float *values) { MCol *mcol = (MCol *)ptr->data; + values[3] = (&mcol[1].r)[3] / 255.0f; values[2] = (&mcol[1].r)[0] / 255.0f; values[1] = (&mcol[1].r)[1] / 255.0f; values[0] = (&mcol[1].r)[2] / 255.0f; @@ -603,15 +606,17 @@ static void rna_MeshColor_color2_set(PointerRNA *ptr, const float *values) { MCol *mcol = (MCol *)ptr->data; - (&mcol[1].r)[2] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255)); - (&mcol[1].r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255)); - (&mcol[1].r)[0] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255)); + (&mcol[1].r)[2] = round_fl_to_uchar_clamp(values[0] * 255.0f); + (&mcol[1].r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f); + (&mcol[1].r)[0] = round_fl_to_uchar_clamp(values[2] * 255.0f); + (&mcol[1].r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f); } static void rna_MeshColor_color3_get(PointerRNA *ptr, float *values) { MCol *mcol = (MCol *)ptr->data; + values[3] = (&mcol[2].r)[3] / 255.0f; values[2] = (&mcol[2].r)[0] / 255.0f; values[1] = (&mcol[2].r)[1] / 255.0f; values[0] = (&mcol[2].r)[2] / 255.0f; @@ -621,9 +626,10 @@ static void rna_MeshColor_color3_set(PointerRNA *ptr, const float *values) { MCol *mcol = (MCol *)ptr->data; - (&mcol[2].r)[2] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255)); - (&mcol[2].r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255)); - (&mcol[2].r)[0] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255)); + (&mcol[2].r)[2] = round_fl_to_uchar_clamp(values[0] * 255.0f); + (&mcol[2].r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f); + (&mcol[2].r)[0] = round_fl_to_uchar_clamp(values[2] * 255.0f); + (&mcol[2].r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f); } static void rna_MeshColor_color4_get(PointerRNA *ptr, float *values) @@ -633,15 +639,17 @@ static void rna_MeshColor_color4_get(PointerRNA *ptr, float *values) values[2] = (&mcol[3].r)[0] / 255.0f; values[1] = (&mcol[3].r)[1] / 255.0f; values[0] = (&mcol[3].r)[2] / 255.0f; + values[3] = (&mcol[3].r)[3] / 255.0f; } static void rna_MeshColor_color4_set(PointerRNA *ptr, const float *values) { MCol *mcol = (MCol *)ptr->data; - (&mcol[3].r)[2] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255)); - (&mcol[3].r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255)); - (&mcol[3].r)[0] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255)); + (&mcol[3].r)[2] = round_fl_to_uchar_clamp(values[0] * 255.0f); + (&mcol[3].r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f); + (&mcol[3].r)[0] = round_fl_to_uchar_clamp(values[2] * 255.0f); + (&mcol[3].r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f); } static void rna_MeshLoopColor_color_get(PointerRNA *ptr, float *values) @@ -651,15 +659,17 @@ static void rna_MeshLoopColor_color_get(PointerRNA *ptr, float *values) values[0] = (&mcol->r)[0] / 255.0f; values[1] = (&mcol->r)[1] / 255.0f; values[2] = (&mcol->r)[2] / 255.0f; + values[3] = (&mcol->r)[3] / 255.0f; } static void rna_MeshLoopColor_color_set(PointerRNA *ptr, const float *values) { MLoopCol *mcol = (MLoopCol *)ptr->data; - (&mcol->r)[0] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255)); - (&mcol->r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255)); - (&mcol->r)[2] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255)); + (&mcol->r)[0] = round_fl_to_uchar_clamp(values[0] * 255.0f); + (&mcol->r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f); + (&mcol->r)[2] = round_fl_to_uchar_clamp(values[2] * 255.0f); + (&mcol->r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f); } static int rna_Mesh_texspace_editable(PointerRNA *ptr, const char **UNUSED(r_info)) @@ -2503,28 +2513,28 @@ static void rna_def_mcol(BlenderRNA *brna) RNA_def_struct_path_func(srna, "rna_MeshColor_path"); prop = RNA_def_property(srna, "color1", PROP_FLOAT, PROP_COLOR); - RNA_def_property_array(prop, 3); + RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_float_funcs(prop, "rna_MeshColor_color1_get", "rna_MeshColor_color1_set", NULL); RNA_def_property_ui_text(prop, "Color 1", ""); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "color2", PROP_FLOAT, PROP_COLOR); - RNA_def_property_array(prop, 3); + RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_float_funcs(prop, "rna_MeshColor_color2_get", "rna_MeshColor_color2_set", NULL); RNA_def_property_ui_text(prop, "Color 2", ""); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "color3", PROP_FLOAT, PROP_COLOR); - RNA_def_property_array(prop, 3); + RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_float_funcs(prop, "rna_MeshColor_color3_get", "rna_MeshColor_color3_set", NULL); RNA_def_property_ui_text(prop, "Color 3", ""); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "color4", PROP_FLOAT, PROP_COLOR); - RNA_def_property_array(prop, 3); + RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_float_funcs(prop, "rna_MeshColor_color4_get", "rna_MeshColor_color4_set", NULL); RNA_def_property_ui_text(prop, "Color 4", ""); @@ -2574,7 +2584,7 @@ static void rna_def_mloopcol(BlenderRNA *brna) RNA_def_struct_path_func(srna, "rna_MeshColor_path"); prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); - RNA_def_property_array(prop, 3); + RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_float_funcs(prop, "rna_MeshLoopColor_color_get", "rna_MeshLoopColor_color_set", NULL); RNA_def_property_ui_text(prop, "Color", ""); diff --git a/source/blender/makesrna/intern/rna_meta_api.c b/source/blender/makesrna/intern/rna_meta_api.c index 3d8f375fd88..4c3fa787b94 100644 --- a/source/blender/makesrna/intern/rna_meta_api.c +++ b/source/blender/makesrna/intern/rna_meta_api.c @@ -45,7 +45,7 @@ #ifdef RNA_RUNTIME static void rna_Meta_transform(struct MetaBall *mb, float *mat) { - BKE_mball_transform(mb, (float (*)[4])mat); + BKE_mball_transform(mb, (float (*)[4])mat, true); DAG_id_tag_update(&mb->id, 0); } diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 1a8dd05a7b5..74aa3759d2d 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1518,26 +1518,40 @@ static void rna_def_modifier_mirror(BlenderRNA *brna) prop = RNA_def_property(srna, "use_mirror_u", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_MIRROR_U); - RNA_def_property_ui_text(prop, "Mirror U", "Mirror the U texture coordinate around the 0.5 point"); + RNA_def_property_ui_text(prop, "Mirror U", "Mirror the U texture coordinate around the flip offset point"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "use_mirror_v", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_MIRROR_V); - RNA_def_property_ui_text(prop, "Mirror V", "Mirror the V texture coordinate around the 0.5 point"); + RNA_def_property_ui_text(prop, "Mirror V", "Mirror the V texture coordinate around the flip offset point"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "mirror_offset_u", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "uv_offset[0]"); RNA_def_property_range(prop, -1, 1); RNA_def_property_ui_range(prop, -1, 1, 2, 4); - RNA_def_property_ui_text(prop, "U Offset", "Amount to offset mirrored UVs from the 0.5 point on the U axis"); + RNA_def_property_ui_text(prop, "Flip U Offset", "Amount to offset mirrored UVs flipping point from the 0.5 on the U axis"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "mirror_offset_v", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "uv_offset[1]"); RNA_def_property_range(prop, -1, 1); RNA_def_property_ui_range(prop, -1, 1, 2, 4); - RNA_def_property_ui_text(prop, "V Offset", "Amount to offset mirrored UVs from the 0.5 point on the V axis"); + RNA_def_property_ui_text(prop, "Flip V Offset", "Amount to offset mirrored UVs flipping point from the 0.5 point on the V axis"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "offset_u", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "uv_offset_copy[0]"); + RNA_def_property_range(prop, -10000.0f, 10000.0f); + RNA_def_property_ui_range(prop, -1, 1, 2, 4); + RNA_def_property_ui_text(prop, "U Offset", "Mirrored UV offset on the U axis"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "offset_v", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "uv_offset_copy[1]"); + RNA_def_property_range(prop, -10000.0f, 10000.0f); + RNA_def_property_ui_range(prop, -1, 1, 2, 4); + RNA_def_property_ui_text(prop, "V Offset", "Mirrored UV offset on the V axis"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE); @@ -1974,9 +1988,26 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) prop = RNA_def_property(srna, "double_threshold", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "double_threshold"); RNA_def_property_range(prop, 0, 1.0f); - RNA_def_property_ui_range(prop, 0, 1, 0.0001, 7); + RNA_def_property_ui_range(prop, 0, 1, 0.0001, 6); RNA_def_property_ui_text(prop, "Overlap Threshold", "Threshold for checking overlapping geometry"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + /* BMesh debugging options, only used when G_DEBUG is set */ + + /* BMesh intersection options */ + static EnumPropertyItem debug_items[] = { + {eBooleanModifierBMeshFlag_BMesh_Separate, "SEPARATE", 0, "Separate", ""}, + {eBooleanModifierBMeshFlag_BMesh_NoDissolve, "NO_DISSOLVE", 0, "NoDissolve", ""}, + {eBooleanModifierBMeshFlag_BMesh_NoConnectRegions, "NO_CONNECT_REGIONS", 0, "NoConnectRegions", ""}, + {0, NULL, 0, NULL, NULL} + }; + + prop = RNA_def_property(srna, "debug_options", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, debug_items); + RNA_def_property_enum_sdna(prop, NULL, "bm_flag"); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_ui_text(prop, "Debug", "Debugging options, only when started with '-d'"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_array(BlenderRNA *brna) @@ -3413,6 +3444,13 @@ static void rna_def_modifier_screw(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Screw", "Offset the revolution along its axis"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "merge_dist"); + RNA_def_property_range(prop, 0, FLT_MAX); + RNA_def_property_ui_range(prop, 0, 1, 1, 4); + RNA_def_property_ui_text(prop, "Merge Distance", "Limit below which to merge vertices"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "use_normal_flip", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_NORMAL_FLIP); RNA_def_property_ui_text(prop, "Flip", "Flip normals of lathed faces"); @@ -3428,6 +3466,12 @@ static void rna_def_modifier_screw(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Object Screw", "Use the distance between the objects to make a screw"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + /* Vertex merging parameters */ + prop = RNA_def_property(srna, "use_merge_vertices", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_MERGE); + RNA_def_property_ui_text(prop, "Merge Vertices", "Merge adjacent vertices (screw offset must be zero)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "use_smooth_shade", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_SMOOTH_SHADING); RNA_def_property_ui_text(prop, "Smooth Shading", "Output faces with smooth shading rather than flat shaded"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 10422c85579..ee4608b550f 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -73,6 +73,13 @@ EnumPropertyItem rna_enum_node_socket_in_out_items[] = { }; #ifndef RNA_RUNTIME +static EnumPropertyItem rna_enum_node_socket_draw_shape_items[] = { + {SOCK_DRAW_SHAPE_CIRCLE, "CIRCLE", 0, "Circle", ""}, + {SOCK_DRAW_SHAPE_SQUARE, "SQUARE", 0, "Square", ""}, + {SOCK_DRAW_SHAPE_DIAMOND, "DIAMOND", 0, "Diamond", ""}, + {0, NULL, 0, NULL, NULL } +}; + static EnumPropertyItem node_socket_type_items[] = { {SOCK_CUSTOM, "CUSTOM", 0, "Custom", ""}, {SOCK_FLOAT, "VALUE", 0, "Value", ""}, @@ -238,10 +245,10 @@ bNodeTreeType *rna_node_tree_type_from_enum(int value) EnumPropertyItem *rna_node_tree_type_itemf(void *data, int (*poll)(void *data, bNodeTreeType *), bool *r_free) { - EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem tmp = {0}; EnumPropertyItem *item = NULL; int totitem = 0, i = 0; - + NODE_TREE_TYPES_BEGIN (nt) { if (poll && !poll(data, nt)) { @@ -261,9 +268,14 @@ EnumPropertyItem *rna_node_tree_type_itemf(void *data, int (*poll)(void *data, b } NODE_TREE_TYPES_END; + if (totitem == 0) { + *r_free = false; + return DummyRNA_NULL_items; + } + RNA_enum_item_end(&item, &totitem); *r_free = true; - + return item; } @@ -310,9 +322,9 @@ bNodeType *rna_node_type_from_enum(int value) EnumPropertyItem *rna_node_type_itemf(void *data, int (*poll)(void *data, bNodeType *), bool *r_free) { EnumPropertyItem *item = NULL; - EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem tmp = {0}; int totitem = 0, i = 0; - + NODE_TYPES_BEGIN(ntype) if (poll && !poll(data, ntype)) { ++i; @@ -329,9 +341,15 @@ EnumPropertyItem *rna_node_type_itemf(void *data, int (*poll)(void *data, bNodeT ++i; NODE_TYPES_END + + if (totitem == 0) { + *r_free = false; + return DummyRNA_NULL_items; + } + RNA_enum_item_end(&item, &totitem); *r_free = true; - + return item; } @@ -378,10 +396,10 @@ bNodeSocketType *rna_node_socket_type_from_enum(int value) EnumPropertyItem *rna_node_socket_type_itemf(void *data, int (*poll)(void *data, bNodeSocketType *), bool *r_free) { EnumPropertyItem *item = NULL; - EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem tmp = {0}; int totitem = 0, i = 0; StructRNA *srna; - + NODE_SOCKET_TYPES_BEGIN(stype) if (poll && !poll(data, stype)) { ++i; @@ -399,9 +417,15 @@ EnumPropertyItem *rna_node_socket_type_itemf(void *data, int (*poll)(void *data, ++i; NODE_SOCKET_TYPES_END + + if (totitem == 0) { + *r_free = false; + return DummyRNA_NULL_items; + } + RNA_enum_item_end(&item, &totitem); *r_free = true; - + return item; } @@ -410,25 +434,25 @@ static EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), Pointer EnumPropertyItem *item = NULL; EnumPropertyItem tmp; int totitem = 0; - + /* hack, don't want to add include path to RNA just for this, since in the future RNA types * for nodes should be defined locally at runtime anyway ... */ - + tmp.value = NODE_CUSTOM; tmp.identifier = "CUSTOM"; tmp.name = "Custom"; tmp.description = "Custom Node"; tmp.icon = ICON_NONE; RNA_enum_item_add(&item, &totitem, &tmp); - + tmp.value = NODE_UNDEFINED; tmp.identifier = "UNDEFINED"; tmp.name = "UNDEFINED"; tmp.description = ""; tmp.icon = ICON_NONE; RNA_enum_item_add(&item, &totitem, &tmp); - + #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ if (STREQ(#Category, "Node")) { \ tmp.value = ID; \ @@ -440,7 +464,7 @@ static EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), Pointer } #include "../../nodes/NOD_static_types.h" #undef DefNode - + if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) { #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ if (STREQ(#Category, "ShaderNode")) { \ @@ -468,7 +492,7 @@ static EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), Pointer #include "../../nodes/NOD_static_types.h" #undef DefNode } - + if (RNA_struct_is_a(ptr->type, &RNA_TextureNode)) { #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ if (STREQ(#Category, "TextureNode")) { \ @@ -485,7 +509,7 @@ static EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), Pointer RNA_enum_item_end(&item, &totitem); *r_free = true; - + return item; } @@ -578,11 +602,10 @@ static void rna_NodeTree_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &nt->ext); + RNA_struct_free(&BLENDER_RNA, type); ntreeTypeFreeLink(nt); - RNA_struct_free(&BLENDER_RNA, type); - /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); } @@ -614,9 +637,10 @@ static StructRNA *rna_NodeTree_register( /* check if we have registered this tree type before, and remove it */ nt = ntreeTypeFind(dummynt.idname); - if (nt) + if (nt) { rna_NodeTree_unregister(bmain, nt->ext.srna); - + } + /* create a new node tree type */ nt = MEM_callocN(sizeof(bNodeTreeType), "node tree type"); memcpy(nt, &dummynt, sizeof(dummynt)); @@ -1331,11 +1355,11 @@ static void rna_Node_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &nt->ext); + RNA_struct_free(&BLENDER_RNA, type); /* this also frees the allocated nt pointer, no MEM_free call needed! */ nodeUnregisterType(nt); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); @@ -1376,8 +1400,9 @@ static bNodeType *rna_Node_register_base(Main *bmain, ReportList *reports, Struc /* check if we have registered this node type before, and remove it */ nt = nodeTypeFind(dummynt.idname); - if (nt) + if (nt) { rna_Node_unregister(bmain, nt->ext.srna); + } /* create a new node type */ nt = MEM_callocN(sizeof(bNodeType), "node type"); @@ -1793,10 +1818,10 @@ static void rna_NodeSocket_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &st->ext_socket); + RNA_struct_free(&BLENDER_RNA, type); nodeUnregisterSocketType(st); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); @@ -2617,9 +2642,9 @@ static void rna_Node_image_layer_update(Main *bmain, Scene *scene, PointerRNA *p static EnumPropertyItem *renderresult_layers_add_enum(RenderLayer *rl) { EnumPropertyItem *item = NULL; - EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem tmp = {0}; int i = 0, totitem = 0; - + while (rl) { tmp.identifier = rl->name; /* little trick: using space char instead empty string makes the item selectable in the dropdown */ @@ -2631,7 +2656,7 @@ static EnumPropertyItem *renderresult_layers_add_enum(RenderLayer *rl) RNA_enum_item_add(&item, &totitem, &tmp); rl = rl->next; } - + RNA_enum_item_end(&item, &totitem); return item; @@ -2644,18 +2669,17 @@ static EnumPropertyItem *rna_Node_image_layer_itemf(bContext *UNUSED(C), Pointer Image *ima = (Image *)node->id; EnumPropertyItem *item = NULL; RenderLayer *rl; - - if (ima && ima->rr) { - rl = ima->rr->layers.first; - item = renderresult_layers_add_enum(rl); - } - else { - int totitem = 0; - RNA_enum_item_end(&item, &totitem); + + if (ima == NULL || ima->rr == NULL) { + *r_free = false; + return DummyRNA_NULL_items; } - + + rl = ima->rr->layers.first; + item = renderresult_layers_add_enum(rl); + *r_free = true; - + return item; } @@ -2706,19 +2730,22 @@ static EnumPropertyItem *renderresult_views_add_enum(RenderView *rv) } static EnumPropertyItem *rna_Node_image_view_itemf(bContext *UNUSED(C), PointerRNA *ptr, - PropertyRNA *UNUSED(prop), bool *free) + PropertyRNA *UNUSED(prop), bool *r_free) { bNode *node = (bNode *)ptr->data; Image *ima = (Image *)node->id; EnumPropertyItem *item = NULL; RenderView *rv; - if (!ima || !(ima->rr)) return NULL; + if (ima == NULL || ima->rr == NULL) { + *r_free = false; + return DummyRNA_NULL_items; + } rv = ima->rr->views.first; item = renderresult_views_add_enum(rv); - *free = true; + *r_free = true; return item; } @@ -2730,18 +2757,17 @@ static EnumPropertyItem *rna_Node_scene_layer_itemf(bContext *UNUSED(C), Pointer Scene *sce = (Scene *)node->id; EnumPropertyItem *item = NULL; RenderLayer *rl; - - if (sce) { - rl = sce->r.layers.first; - item = renderresult_layers_add_enum(rl); - } - else { - int totitem = 0; - RNA_enum_item_end(&item, &totitem); + + if (sce == NULL) { + *r_free = false; + return DummyRNA_NULL_items; } - + + rl = sce->r.layers.first; + item = renderresult_layers_add_enum(rl); + *r_free = true; - + return item; } @@ -2758,7 +2784,7 @@ static EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C), PointerRNA { bNode *node = (bNode *)ptr->data; EnumPropertyItem *item = NULL; - EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem tmp = {0}; int totitem = 0; switch (node->custom1) { @@ -2795,7 +2821,7 @@ static EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C), PointerRNA RNA_enum_item_add(&item, &totitem, &tmp); break; default: - break; + return DummyRNA_NULL_items; } RNA_enum_item_end(&item, &totitem); @@ -3339,7 +3365,7 @@ static void def_frame(StructRNA *srna) prop = RNA_def_property(srna, "text", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Text"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Text", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -3609,7 +3635,7 @@ static void def_sh_lamp(StructRNA *srna) prop = RNA_def_property(srna, "lamp_object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Lamp_object_poll"); RNA_def_property_ui_text(prop, "Lamp Object", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -3983,7 +4009,7 @@ static void def_sh_tex_coord(StructRNA *srna) prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Object", "Use coordinates from this object (for object texture coordinates output)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -4099,7 +4125,7 @@ static void def_sh_tex_pointdensity(StructRNA *srna) prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Object", "Object to take point data from"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -4796,7 +4822,7 @@ static void def_cmp_render_layers(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_pointer_funcs(prop, NULL, "rna_Node_scene_set", NULL, NULL); RNA_def_property_struct_type(prop, "Scene"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Scene", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_scene_layer_update"); @@ -5453,7 +5479,7 @@ static void def_cmp_defocus(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_pointer_funcs(prop, NULL, "rna_Node_scene_set", NULL, NULL); RNA_def_property_struct_type(prop, "Scene"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Scene", "Scene from which to select the active camera (render scene if undefined)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -6968,6 +6994,13 @@ static void rna_def_node_socket(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Type", "Data type"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocket_update"); + prop = RNA_def_property(srna, "draw_shape", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "draw_shape"); + RNA_def_property_enum_items(prop, rna_enum_node_socket_draw_shape_items); + RNA_def_property_enum_default(prop, SOCK_DRAW_SHAPE_CIRCLE); + RNA_def_property_ui_text(prop, "Shape", "Socket shape"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocket_update"); + /* registration */ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "typeinfo->idname"); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index a167ab03ba1..1f018a6ddfc 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2392,7 +2392,7 @@ static void rna_def_object(BlenderRNA *brna) /* only for the transform-panel and conflicts with animating scale */ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_float_funcs(prop, "rna_Object_dimensions_get", "rna_Object_dimensions_set", NULL); - RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3); + RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_ui_text(prop, "Dimensions", "Absolute bounding box dimensions of the object"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 44dcb72264a..034782cc818 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -33,6 +33,8 @@ #include "BLI_utildefines.h" #include "BLI_path_util.h" +#include "BKE_scene.h" + #include "RNA_define.h" #include "RNA_enum_types.h" @@ -41,6 +43,7 @@ #include "RE_engine.h" #include "RE_pipeline.h" +#include "ED_render.h" /* Deprecated, only provided for API compatibility. */ EnumPropertyItem rna_enum_render_pass_type_items[] = { @@ -123,6 +126,11 @@ static int engine_support_display_space_shader(RenderEngine *UNUSED(engine), Sce return IMB_colormanagement_support_glsl_draw(&scene->view_settings); } +static int engine_get_preview_pixel_size(RenderEngine *UNUSED(engine), Scene *scene) +{ + return BKE_render_preview_pixel_size(&scene->r); +} + static void engine_bind_display_space_shader(RenderEngine *UNUSED(engine), Scene *scene) { IMB_colormanagement_setup_glsl_draw(&scene->view_settings, @@ -271,7 +279,7 @@ static void engine_update_render_passes(RenderEngine *engine, struct Scene *scen /* RenderEngine registration */ -static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type) +static void rna_RenderEngine_unregister(Main *bmain, StructRNA *type) { RenderEngineType *et = RNA_struct_blender_type_get(type); @@ -279,12 +287,16 @@ static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &et->ext); - BLI_freelinkN(&R_engines, et); RNA_struct_free(&BLENDER_RNA, type); + BLI_freelinkN(&R_engines, et); + + /* Stop all renders in case we were using this one. */ + ED_render_engine_changed(bmain); } -static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_RenderEngine_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { RenderEngineType *et, dummyet = {NULL}; RenderEngine dummyengine = {NULL}; @@ -647,6 +659,13 @@ static void rna_def_render_engine(BlenderRNA *brna) parm = RNA_def_boolean(func, "supported", 0, "Supported", ""); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "get_preview_pixel_size", "engine_get_preview_pixel_size"); + RNA_def_function_ui_description(func, "Get the pixel size that should be used for preview rendering"); + parm = RNA_def_pointer(func, "scene", "Scene", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "pixel_size", 0, 1, 8, "Pixel Size", "", 1, 8); + RNA_def_function_return(func, parm); + RNA_define_verify_sdna(0); prop = RNA_def_property(srna, "is_animation", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index abded187b33..502a9c42363 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -610,6 +610,22 @@ static int rna_Property_array_length_get(PointerRNA *ptr) return prop->totarraylength; } +static void rna_Property_array_dimensions_get(PointerRNA *ptr, int dimensions[RNA_MAX_ARRAY_DIMENSION]) +{ + PropertyRNA *prop = (PropertyRNA *)ptr->data; + rna_idproperty_check(&prop, ptr); + + if (prop->arraydimension > 1) { + for (int i = RNA_MAX_ARRAY_DIMENSION; i--; ) { + dimensions[i] = (i >= prop->arraydimension) ? 0 : prop->arraylength[i]; + } + } + else { + memset(dimensions, 0, sizeof(*dimensions) * RNA_MAX_ARRAY_DIMENSION); + dimensions[0] = prop->totarraylength; + } +} + static int rna_Property_is_registered_get(PointerRNA *ptr) { PropertyRNA *prop = (PropertyRNA *)ptr->data; @@ -983,21 +999,32 @@ static int rna_Function_use_self_type_get(PointerRNA *ptr) /* Blender RNA */ +static int rna_struct_is_publc(CollectionPropertyIterator *UNUSED(iter), void *data) +{ + StructRNA *srna = data; + + return !(srna->flag & STRUCT_PUBLIC_NAMESPACE); +} + + static void rna_BlenderRNA_structs_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { - rna_iterator_listbase_begin(iter, &((BlenderRNA *)ptr->data)->structs, NULL); + BlenderRNA *brna = ptr->data; + rna_iterator_listbase_begin(iter, &brna->structs, rna_struct_is_publc); } /* optional, for faster lookups */ static int rna_BlenderRNA_structs_length(PointerRNA *ptr) { - return BLI_listbase_count(&((BlenderRNA *)ptr->data)->structs); + BlenderRNA *brna = ptr->data; + BLI_assert(brna->structs_len == BLI_listbase_count(&brna->structs)); + return brna->structs_len; } static int rna_BlenderRNA_structs_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr) { - StructRNA *srna = BLI_findlink(&((BlenderRNA *)ptr->data)->structs, index); - - if (srna) { + BlenderRNA *brna = ptr->data; + StructRNA *srna = index < brna->structs_len ? BLI_findlink(&brna->structs, index) : NULL; + if (srna != NULL) { RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr); return true; } @@ -1007,12 +1034,11 @@ static int rna_BlenderRNA_structs_lookup_int(PointerRNA *ptr, int index, Pointer } static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) { - StructRNA *srna = ((BlenderRNA *)ptr->data)->structs.first; - for (; srna; srna = srna->cont.next) { - if (key[0] == srna->identifier[0] && STREQ(key, srna->identifier)) { - RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr); - return true; - } + BlenderRNA *brna = ptr->data; + StructRNA *srna = BLI_ghash_lookup(brna->structs_map, (void *)key); + if (srna != NULL) { + RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr); + return true; } return false; @@ -1344,6 +1370,12 @@ static void rna_def_number_property(StructRNA *srna, PropertyType type) RNA_def_property_int_funcs(prop, "rna_Property_array_length_get", NULL, NULL); RNA_def_property_ui_text(prop, "Array Length", "Maximum length of the array, 0 means unlimited"); + prop = RNA_def_property(srna, "array_dimensions", PROP_INT, PROP_UNSIGNED); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_array(prop, RNA_MAX_ARRAY_DIMENSION); + RNA_def_property_int_funcs(prop, "rna_Property_array_dimensions_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Array Dimensions", "Length of each dimension of the array"); + prop = RNA_def_property(srna, "is_array", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_boolean_funcs(prop, "rna_NumberProperty_is_array_get", NULL); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index b9231574a24..cd0bcaf4cea 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -58,11 +58,6 @@ #include "RE_engine.h" #include "RE_pipeline.h" -#ifdef WITH_QUICKTIME -# include "quicktime_export.h" -# include AUD_TYPES_H -#endif - #ifdef WITH_FFMPEG # include "BKE_writeffmpeg.h" # include <libavcodec/avcodec.h> @@ -94,13 +89,15 @@ EnumPropertyItem rna_enum_exr_codec_items[] = { }; #endif -EnumPropertyItem uv_sculpt_relaxation_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem uv_sculpt_relaxation_items[] = { {UV_SCULPT_TOOL_RELAX_LAPLACIAN, "LAPLACIAN", 0, "Laplacian", "Use Laplacian method for relaxation"}, {UV_SCULPT_TOOL_RELAX_HC, "HC", 0, "HC", "Use HC method for relaxation"}, {0, NULL, 0, NULL, NULL} }; +#endif -EnumPropertyItem uv_sculpt_tool_items[] = { +EnumPropertyItem rna_enum_uv_sculpt_tool_items[] = { {UV_SCULPT_TOOL_PINCH, "PINCH", 0, "Pinch", "Pinch UVs"}, {UV_SCULPT_TOOL_RELAX, "RELAX", 0, "Relax", "Relax UVs"}, {UV_SCULPT_TOOL_GRAB, "GRAB", 0, "Grab", "Grab UVs"}, @@ -175,11 +172,13 @@ EnumPropertyItem rna_enum_snap_node_element_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem snap_uv_element_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem snap_uv_element_items[] = { {SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments of grid"}, {SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"}, {0, NULL, 0, NULL, NULL} }; +#endif EnumPropertyItem rna_enum_curve_fit_method_items[] = { {CURVE_PAINT_FIT_METHOD_REFIT, "REFIT", 0, "Refit", "Incrementally re-fit the curve (high quality)"}, @@ -265,12 +264,14 @@ EnumPropertyItem rna_enum_curve_fit_method_items[] = { R_IMF_ENUM_TIFF \ -EnumPropertyItem image_only_type_items[] = { +#ifdef RNA_RUNTIME +static EnumPropertyItem image_only_type_items[] = { IMAGE_TYPE_ITEMS_IMAGE_ONLY {0, NULL, 0, NULL, NULL} }; +#endif EnumPropertyItem rna_enum_image_type_items[] = { {0, "", 0, N_("Image"), NULL}, @@ -286,9 +287,6 @@ EnumPropertyItem rna_enum_image_type_items[] = { #ifdef WITH_FFMPEG {R_IMF_IMTYPE_FFMPEG, "FFMPEG", ICON_FILE_MOVIE, "FFmpeg video", "The most versatile way to output video files"}, #endif -#ifdef WITH_QUICKTIME - {R_IMF_IMTYPE_QUICKTIME, "QUICKTIME", ICON_FILE_MOVIE, "QuickTime", "Output video in Quicktime format"}, -#endif {0, NULL, 0, NULL, NULL} }; @@ -408,7 +406,8 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = { /* interpolation */ {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"}, {GP_IPO_LINEAR, "LINEAR", ICON_IPO_LINEAR, "Linear", "Straight-line interpolation between A and B (i.e. no ease in/out)"}, @@ -431,6 +430,7 @@ EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = { {0, NULL, 0, NULL, NULL} }; +#endif #ifdef RNA_RUNTIME @@ -1118,9 +1118,6 @@ static void rna_ImageFormatSettings_file_format_set(PointerRNA *ptr, int value) #ifdef WITH_FFMPEG BKE_ffmpeg_image_type_verify(rd, imf); #endif -#ifdef WITH_QUICKTIME - quicktime_verify_image_type(rd, imf); -#endif (void)rd; } } @@ -1309,84 +1306,6 @@ static void rna_SceneRender_file_ext_get(PointerRNA *ptr, char *str) BKE_image_path_ensure_ext_from_imformat(str, &rd->im_format); } -#ifdef WITH_QUICKTIME -static int rna_RenderSettings_qtcodecsettings_codecType_get(PointerRNA *ptr) -{ - QuicktimeCodecSettings *settings = (QuicktimeCodecSettings *)ptr->data; - - return quicktime_rnatmpvalue_from_videocodectype(settings->codecType); -} - -static void rna_RenderSettings_qtcodecsettings_codecType_set(PointerRNA *ptr, int value) -{ - QuicktimeCodecSettings *settings = (QuicktimeCodecSettings *)ptr->data; - - settings->codecType = quicktime_videocodecType_from_rnatmpvalue(value); -} - -static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_codecType_itemf( - bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - EnumPropertyItem *item = NULL; - EnumPropertyItem tmp = {0, "", 0, "", ""}; - QuicktimeCodecTypeDesc *codecTypeDesc; - int i = 1, totitem = 0; - - for (i = 0; i < quicktime_get_num_videocodecs(); i++) { - codecTypeDesc = quicktime_get_videocodecType_desc(i); - if (!codecTypeDesc) break; - - tmp.value = codecTypeDesc->rnatmpvalue; - tmp.identifier = codecTypeDesc->codecName; - tmp.name = codecTypeDesc->codecName; - RNA_enum_item_add(&item, &totitem, &tmp); - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; -} - -static int rna_RenderSettings_qtcodecsettings_audiocodecType_get(PointerRNA *ptr) -{ - QuicktimeCodecSettings *settings = (QuicktimeCodecSettings *)ptr->data; - - return quicktime_rnatmpvalue_from_audiocodectype(settings->audiocodecType); -} - -static void rna_RenderSettings_qtcodecsettings_audiocodecType_set(PointerRNA *ptr, int value) -{ - QuicktimeCodecSettings *settings = (QuicktimeCodecSettings *)ptr->data; - - settings->audiocodecType = quicktime_audiocodecType_from_rnatmpvalue(value); -} - -static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_audiocodecType_itemf( - bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - EnumPropertyItem *item = NULL; - EnumPropertyItem tmp = {0, "", 0, "", ""}; - QuicktimeCodecTypeDesc *codecTypeDesc; - int i = 1, totitem = 0; - - for (i = 0; i < quicktime_get_num_audiocodecs(); i++) { - codecTypeDesc = quicktime_get_audiocodecType_desc(i); - if (!codecTypeDesc) break; - - tmp.value = codecTypeDesc->rnatmpvalue; - tmp.identifier = codecTypeDesc->codecName; - tmp.name = codecTypeDesc->codecName; - RNA_enum_item_add(&item, &totitem, &tmp); - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; -} -#endif - #ifdef WITH_FFMPEG static void rna_FFmpegSettings_lossless_output_set(PointerRNA *ptr, int value) { @@ -1838,6 +1757,13 @@ static void rna_Scene_simplify_update(Main *bmain, Scene *UNUSED(scene), Pointer rna_Scene_use_simplify_update(bmain, sce, ptr); } +static void rna_SceneRenderData_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + Scene *sce = ptr->id.data; + + DAG_id_tag_update(&sce->id, 0); +} + static void rna_Scene_use_persistent_data_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *sce = ptr->id.data; @@ -2665,7 +2591,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "uv_sculpt_tool", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "uv_sculpt_tool"); - RNA_def_property_enum_items(prop, uv_sculpt_tool_items); + RNA_def_property_enum_items(prop, rna_enum_uv_sculpt_tool_items); RNA_def_property_ui_text(prop, "UV Sculpt Tools", "Select Tools for the UV sculpt brushes"); prop = RNA_def_property(srna, "uv_relax_method", PROP_ENUM, PROP_NONE); @@ -5723,106 +5649,6 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Audio Channels", "Audio channel count"); } -#ifdef WITH_QUICKTIME -static void rna_def_scene_quicktime_settings(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - static EnumPropertyItem quicktime_codec_type_items[] = { - {0, "codec", 0, "codec", ""}, - {0, NULL, 0, NULL, NULL} - }; - - static EnumPropertyItem quicktime_audio_samplerate_items[] = { - {22050, "22050", 0, "22kHz", ""}, - {44100, "44100", 0, "44.1kHz", ""}, - {48000, "48000", 0, "48kHz", ""}, - {88200, "88200", 0, "88.2kHz", ""}, - {96000, "96000", 0, "96kHz", ""}, - {192000, "192000", 0, "192kHz", ""}, - {0, NULL, 0, NULL, NULL} - }; - - static EnumPropertyItem quicktime_audio_bitdepth_items[] = { - {AUD_FORMAT_U8, "8BIT", 0, "8bit", ""}, - {AUD_FORMAT_S16, "16BIT", 0, "16bit", ""}, - {AUD_FORMAT_S24, "24BIT", 0, "24bit", ""}, - {AUD_FORMAT_S32, "32BIT", 0, "32bit", ""}, - {AUD_FORMAT_FLOAT32, "FLOAT32", 0, "float32", ""}, - {AUD_FORMAT_FLOAT64, "FLOAT64", 0, "float64", ""}, - {0, NULL, 0, NULL, NULL} - }; - - static EnumPropertyItem quicktime_audio_bitrate_items[] = { - {64000, "64000", 0, "64kbps", ""}, - {112000, "112000", 0, "112kpbs", ""}, - {128000, "128000", 0, "128kbps", ""}, - {192000, "192000", 0, "192kbps", ""}, - {256000, "256000", 0, "256kbps", ""}, - {320000, "320000", 0, "320kbps", ""}, - {0, NULL, 0, NULL, NULL} - }; - - /* QuickTime */ - srna = RNA_def_struct(brna, "QuickTimeSettings", NULL); - RNA_def_struct_sdna(srna, "QuicktimeCodecSettings"); - RNA_def_struct_ui_text(srna, "QuickTime Settings", "QuickTime related settings for the scene"); - - prop = RNA_def_property(srna, "codec_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "codecType"); - RNA_def_property_enum_items(prop, quicktime_codec_type_items); - RNA_def_property_enum_funcs(prop, "rna_RenderSettings_qtcodecsettings_codecType_get", - "rna_RenderSettings_qtcodecsettings_codecType_set", - "rna_RenderSettings_qtcodecsettings_codecType_itemf"); - RNA_def_property_ui_text(prop, "Codec", "QuickTime codec type"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "codec_spatial_quality", PROP_INT, PROP_PERCENTAGE); - RNA_def_property_int_sdna(prop, NULL, "codecSpatialQuality"); - RNA_def_property_range(prop, 0, 100); - RNA_def_property_ui_text(prop, "Spatial quality", "Intra-frame spatial quality level"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "audiocodec_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "audiocodecType"); - RNA_def_property_enum_items(prop, quicktime_codec_type_items); - RNA_def_property_enum_funcs(prop, "rna_RenderSettings_qtcodecsettings_audiocodecType_get", - "rna_RenderSettings_qtcodecsettings_audiocodecType_set", - "rna_RenderSettings_qtcodecsettings_audiocodecType_itemf"); - RNA_def_property_ui_text(prop, "Audio Codec", "QuickTime audio codec type"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "audio_samplerate", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "audioSampleRate"); - RNA_def_property_enum_items(prop, quicktime_audio_samplerate_items); - RNA_def_property_ui_text(prop, "Smp Rate", "Sample Rate"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "audio_bitdepth", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "audioBitDepth"); - RNA_def_property_enum_items(prop, quicktime_audio_bitdepth_items); - RNA_def_property_ui_text(prop, "Bit Depth", "Bit Depth"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "audio_resampling_hq", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "audioCodecFlags", QTAUDIO_FLAG_RESAMPLE_NOHQ); - RNA_def_property_ui_text(prop, "HQ", "Use High Quality resampling algorithm"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "audio_codec_isvbr", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "audioCodecFlags", QTAUDIO_FLAG_CODEC_ISCBR); - RNA_def_property_ui_text(prop, "VBR", "Use Variable Bit Rate compression (improves quality at same bitrate)"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "audio_bitrate", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "audioBitRate"); - RNA_def_property_enum_items(prop, quicktime_audio_bitrate_items); - RNA_def_property_ui_text(prop, "Bitrate", "Compressed audio bitrate"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); -} -#endif - static void rna_def_scene_render_data(BlenderRNA *brna) { StructRNA *srna; @@ -5887,6 +5713,15 @@ static void rna_def_scene_render_data(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem pixel_size_items[] = { + {0, "AUTO", 0, "Automatic", "Automatic pixel size, depends on the UI scale"}, + {1, "1", 0, "1x", "Render at full resolution"}, + {2, "2", 0, "2x", "Render at 50% resolution"}, + {4, "4", 0, "4x", "Render at 25% resolution"}, + {8, "8", 0, "8x", "Render at 12.5% resolution"}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem octree_resolution_items[] = { {64, "64", 0, "64", ""}, {128, "128", 0, "128", ""}, @@ -5947,9 +5782,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) rna_def_scene_ffmpeg_settings(brna); -#ifdef WITH_QUICKTIME - rna_def_scene_quicktime_settings(brna); -#endif srna = RNA_def_struct(brna, "RenderSettings", NULL); RNA_def_struct_sdna(srna, "RenderData"); @@ -6010,6 +5842,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna) "progressively increasing it to the full viewport size"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "preview_pixel_size", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "preview_pixel_size"); + RNA_def_property_enum_items(prop, pixel_size_items); + RNA_def_property_ui_text(prop, "Pixel Size", "Pixel size for viewport rendering"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderData_update"); + prop = RNA_def_property(srna, "pixel_aspect_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "xasp"); RNA_def_property_flag(prop, PROP_PROPORTIONAL); @@ -6028,14 +5866,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) "Vertical aspect ratio - for anamorphic or non-square pixel output"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneCamera_update"); -#ifdef WITH_QUICKTIME - prop = RNA_def_property(srna, "quicktime", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "QuickTimeSettings"); - RNA_def_property_pointer_sdna(prop, NULL, "qtcodecsettings"); - RNA_def_property_flag(prop, PROP_NEVER_UNLINK); - RNA_def_property_ui_text(prop, "QuickTime Settings", "QuickTime related settings for the scene"); -#endif - prop = RNA_def_property(srna, "ffmpeg", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "FFmpegSettings"); RNA_def_property_pointer_sdna(prop, NULL, "ffcodecdata"); @@ -6242,8 +6072,8 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "blurfac"); RNA_def_property_ui_range(prop, 0.01f, 2.0f, 1, 2); - RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close " + "(NOTE: Blender Internal does not support animated shutter)"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); prop = RNA_def_property(srna, "motion_blur_shutter_curve", PROP_POINTER, PROP_NONE); @@ -6605,11 +6435,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) /* sequencer draw options */ - prop = RNA_def_property(srna, "use_sequencer_gl_preview", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "seq_flag", R_SEQ_GL_PREV); - RNA_def_property_ui_text(prop, "Sequencer OpenGL", ""); - RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SceneSequencer_update"); - #if 0 /* see R_SEQ_GL_REND comment */ prop = RNA_def_property(srna, "use_sequencer_gl_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "seq_flag", R_SEQ_GL_REND); @@ -6622,10 +6447,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Sequencer Preview Shading", "Method to draw in the sequencer view"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SceneSequencer_update"); +#if 0 /* UNUSED, see R_SEQ_GL_REND comment */ prop = RNA_def_property(srna, "sequencer_gl_render", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "seq_rend_type"); RNA_def_property_enum_items(prop, rna_enum_viewport_shade_items); + /* XXX Label and tooltips are obviously wrong! */ RNA_def_property_ui_text(prop, "Sequencer Preview Shading", "Method to draw in the sequencer view"); +#endif prop = RNA_def_property(srna, "use_sequencer_gl_textured_solid", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "seq_flag", R_SEQ_SOLID_TEX); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index ea7327cfa31..16d91a4964b 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -279,7 +279,7 @@ static void rna_Scene_collada_export( int include_shapekeys, int deform_bones_only, int active_uv_only, - int export_texture_type, + int export_texture_type, int use_texture_copies, int triangulate, int use_object_instantiation, diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 40aea37d9d2..09da34d59d8 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -28,6 +28,7 @@ #include <stdlib.h> #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -75,13 +76,15 @@ EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = { { 0, NULL, 0, NULL, NULL } }; -EnumPropertyItem rna_enum_gpencil_lockaxis_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem rna_enum_gpencil_lockaxis_items[] = { { GP_LOCKAXIS_NONE, "GP_LOCKAXIS_NONE", 0, "None", "" }, { GP_LOCKAXIS_X, "GP_LOCKAXIS_X", 0, "X", "Project strokes to plane locked to X" }, { GP_LOCKAXIS_Y, "GP_LOCKAXIS_Y", 0, "Y", "Project strokes to plane locked to Y" }, { GP_LOCKAXIS_Z, "GP_LOCKAXIS_Z", 0, "Z", "Project strokes to plane locked to Z" }, { 0, NULL, 0, NULL, NULL } }; +#endif EnumPropertyItem rna_enum_symmetrize_direction_items[] = { {BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""}, @@ -684,6 +687,15 @@ static void rna_def_vertex_paint(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_ONLYVGROUP); RNA_def_property_ui_text(prop, "Restrict", "Restrict painting to vertices in the group"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + /* Mirroring */ + prop = RNA_def_property(srna, "radial_symmetry", PROP_INT, PROP_XYZ); + RNA_def_property_int_sdna(prop, NULL, "radial_symm"); + RNA_def_property_int_default(prop, 1); + RNA_def_property_range(prop, 1, 64); + RNA_def_property_ui_range(prop, 1, 32, 1, 1); + RNA_def_property_ui_text(prop, "Radial Symmetry Count X Axis", + "Number of times to copy strokes across the surface"); } static void rna_def_image_paint(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index f628c5f14d9..520a1c2f730 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -725,8 +725,9 @@ static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), Poin static void rna_Sequence_sound_update(Main *bmain, Scene *scene, PointerRNA *ptr) { Sequence *seq = (Sequence *) ptr->data; - - BKE_sound_update_scene_sound(seq->scene_sound, seq->sound); + if (seq->sound != NULL) { + BKE_sound_update_scene_sound(seq->scene_sound, seq->sound); + } rna_Sequence_update(bmain, scene, ptr); } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index f2e856bf1ba..ed28b0d399b 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1045,6 +1045,8 @@ static void rna_SpaceProperties_pin_id_update(Main *UNUSED(bmain), Scene *UNUSED case ID_LA: WM_main_add_notifier(NC_LAMP, NULL); break; + default: + break; } } @@ -2836,6 +2838,16 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Is Perspective", ""); RNA_def_property_flag(prop, PROP_EDITABLE); + /* This isn't directly accessible from the UI, only an operator. */ + prop = RNA_def_property(srna, "use_clip_planes", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "rflag", RV3D_CLIPPING); + RNA_def_property_ui_text(prop, "Use Clip Planes", ""); + + prop = RNA_def_property(srna, "clip_planes", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "clip"); + RNA_def_property_multi_array(prop, 2, (int[]){6, 4}); + RNA_def_property_ui_text(prop, "Clipe Planes", ""); + prop = RNA_def_property(srna, "view_location", PROP_FLOAT, PROP_TRANSLATION); #if 0 RNA_def_property_float_sdna(prop, NULL, "ofs"); /* cant use because its negated */ @@ -4605,7 +4617,7 @@ static void rna_def_space_clip(BlenderRNA *brna) /* path length */ prop = RNA_def_property(srna, "path_length", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "path_length"); - RNA_def_property_range(prop, 0, 50); + RNA_def_property_range(prop, 0, INT_MAX); RNA_def_property_ui_text(prop, "Path Length", "Length of displaying path, in frames"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 1e88585a286..4ad2832b953 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -267,6 +267,8 @@ void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL); break; } + default: + break; } } diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 54b82fc89d6..08038b0b1ff 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -177,16 +177,17 @@ static void rna_Panel_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &pt->ext); + RNA_struct_free(&BLENDER_RNA, type); BLI_freelinkN(&art->paneltypes, pt); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); } -static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_Panel_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { ARegionType *art; PanelType *pt, dummypt = {NULL}; @@ -229,6 +230,12 @@ static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *dat break; } } + if (!RNA_struct_available_or_report(reports, dummypt.idname)) { + return NULL; + } + if (!RNA_struct_bl_idname_ok_or_report(reports, dummypt.idname, "_PT_")) { + return NULL; + } /* create a new panel type */ pt = MEM_callocN(sizeof(PanelType), "python buttons panel"); @@ -455,17 +462,17 @@ static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &ult->ext); + RNA_struct_free(&BLENDER_RNA, type); WM_uilisttype_freelink(ult); - RNA_struct_free(&BLENDER_RNA, type); - /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); } -static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_UIList_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { uiListType *ult, dummyult = {NULL}; uiList dummyuilist = {NULL}; @@ -489,8 +496,15 @@ static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *da /* check if we have registered this uilist type before, and remove it */ ult = WM_uilisttype_find(dummyult.idname, true); - if (ult && ult->ext.srna) + if (ult && ult->ext.srna) { rna_UIList_unregister(bmain, ult->ext.srna); + } + if (!RNA_struct_available_or_report(reports, dummyult.idname)) { + return NULL; + } + if (!RNA_struct_bl_idname_ok_or_report(reports, dummyult.idname, "_UL_")) { + return NULL; + } /* create a new menu type */ ult = MEM_callocN(sizeof(uiListType) + over_alloc, "python uilist"); @@ -551,16 +565,17 @@ static void rna_Header_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &ht->ext); + RNA_struct_free(&BLENDER_RNA, type); BLI_freelinkN(&art->headertypes, ht); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); } -static StructRNA *rna_Header_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_Header_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { ARegionType *art; HeaderType *ht, dummyht = {NULL}; @@ -593,6 +608,12 @@ static StructRNA *rna_Header_register(Main *bmain, ReportList *reports, void *da break; } } + if (!RNA_struct_available_or_report(reports, dummyht.idname)) { + return NULL; + } + if (!RNA_struct_bl_idname_ok_or_report(reports, dummyht.idname, "_HT_")) { + return NULL; + } /* create a new header type */ ht = MEM_callocN(sizeof(HeaderType), "python buttons header"); @@ -673,17 +694,17 @@ static void rna_Menu_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &mt->ext); + RNA_struct_free(&BLENDER_RNA, type); WM_menutype_freelink(mt); - RNA_struct_free(&BLENDER_RNA, type); - /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); } -static StructRNA *rna_Menu_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_Menu_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { MenuType *mt, dummymt = {NULL}; Menu dummymenu = {NULL}; @@ -714,8 +735,15 @@ static StructRNA *rna_Menu_register(Main *bmain, ReportList *reports, void *data /* check if we have registered this menu type before, and remove it */ mt = WM_menutype_find(dummymt.idname, true); - if (mt && mt->ext.srna) + if (mt && mt->ext.srna) { rna_Menu_unregister(bmain, mt->ext.srna); + } + if (!RNA_struct_available_or_report(reports, dummymt.idname)) { + return NULL; + } + if (!RNA_struct_bl_idname_ok_or_report(reports, dummymt.idname, "_MT_")) { + return NULL; + } /* create a new menu type */ if (_menu_descr[0]) { @@ -937,6 +965,7 @@ static void rna_def_panel(BlenderRNA *brna) RNA_def_struct_refine_func(srna, "rna_Panel_refine"); RNA_def_struct_register_funcs(srna, "rna_Panel_register", "rna_Panel_unregister", NULL); RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT); /* poll */ func = RNA_def_function(srna, "poll", NULL); @@ -1039,7 +1068,7 @@ static void rna_def_uilist(BlenderRNA *brna) RNA_def_struct_refine_func(srna, "rna_UIList_refine"); RNA_def_struct_register_funcs(srna, "rna_UIList_register", "rna_UIList_unregister", NULL); RNA_def_struct_idprops_func(srna, "rna_UIList_idprops"); - RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); + RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES | STRUCT_PUBLIC_NAMESPACE_INHERIT); /* Registration */ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); @@ -1161,6 +1190,7 @@ static void rna_def_header(BlenderRNA *brna) RNA_def_struct_sdna(srna, "Header"); RNA_def_struct_refine_func(srna, "rna_Header_refine"); RNA_def_struct_register_funcs(srna, "rna_Header_register", "rna_Header_unregister", NULL); + RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT); /* draw */ func = RNA_def_function(srna, "draw", NULL); @@ -1208,6 +1238,7 @@ static void rna_def_menu(BlenderRNA *brna) RNA_def_struct_refine_func(srna, "rna_Menu_refine"); RNA_def_struct_register_funcs(srna, "rna_Menu_register", "rna_Menu_unregister", NULL); RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT); /* poll */ func = RNA_def_function(srna, "poll", NULL); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index c0f2dbd0706..b50cbee4885 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -606,16 +606,17 @@ static void rna_AddonPref_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &apt->ext); + RNA_struct_free(&BLENDER_RNA, type); BKE_addon_pref_type_remove(apt); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); } -static StructRNA *rna_AddonPref_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_AddonPref_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bAddonPrefType *apt, dummyapt = {{'\0'}}; bAddon dummyaddon = {NULL}; @@ -638,10 +639,8 @@ static StructRNA *rna_AddonPref_register(Main *bmain, ReportList *reports, void /* check if we have registered this header type before, and remove it */ apt = BKE_addon_pref_type_find(dummyaddon.module, true); - if (apt) { - if (apt->ext.srna) { - rna_AddonPref_unregister(bmain, apt->ext.srna); - } + if (apt && apt->ext.srna) { + rna_AddonPref_unregister(bmain, apt->ext.srna); } /* create a new header type */ @@ -3304,6 +3303,13 @@ static void rna_def_userdef_view(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem line_width[] = { + {-1, "THIN", 0, "Thin", "Thinner lines than the default"}, + { 0, "AUTO", 0, "Auto", "Automatic line width based on UI scale"}, + { 1, "THICK", 0, "Thick", "Thicker lines than the default"}, + {0, NULL, 0, NULL, NULL} + }; + PropertyRNA *prop; StructRNA *srna; @@ -3321,6 +3327,12 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); + prop = RNA_def_property(srna, "ui_line_width", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, line_width); + RNA_def_property_ui_text(prop, "UI Line Width", + "Changes the thickness of lines and points in the interface"); + RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); + /* display */ prop = RNA_def_property(srna, "show_tooltips", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_TOOLTIPS); @@ -3445,6 +3457,11 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Cursor Depth", "Use the depth under the mouse when placing the cursor"); + prop = RNA_def_property(srna, "use_cursor_lock_adjust", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_LOCK_CURSOR_ADJUST); + RNA_def_property_ui_text(prop, "Cursor Lock Adjust", + "Place the cursor without 'jumping' to the new location (when lock-to-cursor is used)"); + prop = RNA_def_property(srna, "use_camera_lock_parent", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "uiflag", USER_CAM_LOCK_NO_PARENT); RNA_def_property_ui_text(prop, "Camera Parent Lock", @@ -3926,12 +3943,18 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop = RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "DPI", "Font size and resolution for display"); + RNA_def_property_ui_text(prop, "DPI", + "DPI for add-ons to use when drawing custom user interface elements, controlled by " + "operating system settings and Blender UI scale, with a reference value of 72 DPI " + "(note that since this value includes a user defined scale, it is not always the " + "actual monitor DPI)"); prop = RNA_def_property(srna, "pixel_size", PROP_FLOAT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_float_sdna(prop, NULL, "pixelsize"); - RNA_def_property_ui_text(prop, "Pixel Size", ""); + RNA_def_property_ui_text(prop, "Pixel Size", + "Suggested line thickness and point size in pixels, for add-ons drawing custom user " + "interface elements, controlled by operating system settings and Blender UI scale"); prop = RNA_def_property(srna, "font_path_ui", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "font_path_ui"); @@ -3979,11 +4002,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Translate New Names", "Translate new data names (when adding/creating some)"); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop = RNA_def_property(srna, "use_textured_fonts", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_USETEXTUREFONT); - RNA_def_property_ui_text(prop, "Textured Fonts", "Use textures for drawing international fonts"); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - /* System & OpenGL */ prop = RNA_def_property(srna, "solid_lights", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index b5ecaf739c7..df3eae4f221 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -32,6 +32,7 @@ #include "DNA_windowmanager_types.h" #include "BLI_utildefines.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" @@ -1124,8 +1125,8 @@ static StructRNA *rna_Operator_register( struct { char idname[OP_MAX_TYPENAME]; char name[OP_MAX_TYPENAME]; - char descr[RNA_DYN_DESCR_MAX]; - char ctxt[RNA_DYN_DESCR_MAX]; + char description[RNA_DYN_DESCR_MAX]; + char translation_context[RNA_DYN_DESCR_MAX]; char undo_group[OP_MAX_TYPENAME]; } temp_buffers; @@ -1133,92 +1134,57 @@ static StructRNA *rna_Operator_register( dummyop.type = &dummyot; dummyot.idname = temp_buffers.idname; /* only assigne the pointer, string is NULL'd */ dummyot.name = temp_buffers.name; /* only assigne the pointer, string is NULL'd */ - dummyot.description = temp_buffers.descr; /* only assigne the pointer, string is NULL'd */ - dummyot.translation_context = temp_buffers.ctxt; /* only assigne the pointer, string is NULL'd */ + dummyot.description = temp_buffers.description; /* only assigne the pointer, string is NULL'd */ + dummyot.translation_context = temp_buffers.translation_context; /* only assigne the pointer, string is NULL'd */ dummyot.undo_group = temp_buffers.undo_group; /* only assigne the pointer, string is NULL'd */ RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr); /* clear in case they are left unset */ - temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.descr[0] = temp_buffers.undo_group[0] = '\0'; + temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.description[0] = temp_buffers.undo_group[0] = '\0'; /* We have to set default op context! */ - strcpy(temp_buffers.ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + strcpy(temp_buffers.translation_context, BLT_I18NCONTEXT_OPERATOR_DEFAULT); /* validate the python class */ if (validate(&dummyotr, data, have_function) != 0) return NULL; - { /* convert foo.bar to FOO_OT_bar - * allocate the description and the idname in 1 go */ - - /* inconveniently long name sanity check */ - { - char *ch = temp_buffers.idname; - int i; - int dot = 0; - for (i = 0; *ch; i++) { - if ((*ch >= 'a' && *ch <= 'z') || (*ch >= '0' && *ch <= '9') || *ch == '_') { - /* pass */ - } - else if (*ch == '.') { - dot++; - } - else { - BKE_reportf(reports, RPT_ERROR, - "Registering operator class: '%s', invalid bl_idname '%s', at position %d", - identifier, temp_buffers.idname, i); - return NULL; - } + /* check if we have registered this operator type before, and remove it */ + { + wmOperatorType *ot = WM_operatortype_find(dummyot.idname, true); + if (ot && ot->ext.srna) + rna_Operator_unregister(bmain, ot->ext.srna); + } - ch++; - } + if (!WM_operator_py_idname_ok_or_report(reports, identifier, dummyot.idname)) { + return NULL; + } - if (i > ((int)sizeof(dummyop.idname)) - 3) { - BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', " - "is too long, maximum length is %d", identifier, temp_buffers.idname, - (int)sizeof(dummyop.idname) - 3); - return NULL; - } + char idname_conv[sizeof(dummyop.idname)]; + WM_operator_bl_idname(idname_conv, dummyot.idname); /* convert the idname from python */ - if (dot != 1) { - BKE_reportf(reports, RPT_ERROR, - "Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character", - identifier, temp_buffers.idname); - return NULL; - } - } - /* end sanity check */ - - { - const uint idname_len = strlen(temp_buffers.idname) + 4; - const uint name_len = strlen(temp_buffers.name) + 1; - const uint desc_len = strlen(temp_buffers.descr) + 1; - const uint ctxt_len = strlen(temp_buffers.ctxt) + 1; - const uint undo_group_len = strlen(temp_buffers.undo_group) + 1; - /* 2 terminators and 3 to convert a.b -> A_OT_b */ - char *ch = MEM_mallocN( - sizeof(char) * (idname_len + name_len + desc_len + ctxt_len + undo_group_len), __func__); - WM_operator_bl_idname(ch, temp_buffers.idname); /* convert the idname from python */ - dummyot.idname = ch; - ch += idname_len; - memcpy(ch, temp_buffers.name, name_len); - dummyot.name = ch; - ch += name_len; - memcpy(ch, temp_buffers.descr, desc_len); - dummyot.description = ch; - ch += desc_len; - memcpy(ch, temp_buffers.ctxt, ctxt_len); - dummyot.translation_context = ch; - ch += ctxt_len; - memcpy(ch, temp_buffers.undo_group, undo_group_len); - dummyot.undo_group = ch; - } + if (!RNA_struct_available_or_report(reports, idname_conv)) { + return NULL; } - /* check if we have registered this operator type before, and remove it */ + /* Convert foo.bar to FOO_OT_bar + * allocate all strings at once. */ { - wmOperatorType *ot = WM_operatortype_find(dummyot.idname, true); - if (ot && ot->ext.srna) - rna_Operator_unregister(bmain, ot->ext.srna); + const char *strings[] = { + idname_conv, + temp_buffers.name, + temp_buffers.description, + temp_buffers.translation_context, + temp_buffers.undo_group, + }; + char *strings_table[ARRAY_SIZE(strings)]; + BLI_string_join_array_by_sep_char_with_tableN('\0', strings_table, strings, ARRAY_SIZE(strings)); + + dummyot.idname = strings_table[0]; /* allocated string stored here */ + dummyot.name = strings_table[1]; + dummyot.description = strings_table[2]; + dummyot.translation_context = strings_table[3]; + dummyot.undo_group = strings_table[4]; + BLI_assert(ARRAY_SIZE(strings) == 5); } /* XXX, this doubles up with the operator name [#29666] @@ -1269,10 +1235,11 @@ static void rna_Operator_unregister(struct Main *bmain, StructRNA *type) idname = ot->idname; WM_operatortype_remove_ptr(ot); - MEM_freeN((void *)idname); /* not to be confused with the RNA_struct_free that WM_operatortype_remove calls, they are 2 different srna's */ RNA_struct_free(&BLENDER_RNA, type); + + MEM_freeN((void *)idname); } static void **rna_Operator_instance(PointerRNA *ptr) @@ -1293,8 +1260,8 @@ static StructRNA *rna_MacroOperator_register( struct { char idname[OP_MAX_TYPENAME]; char name[OP_MAX_TYPENAME]; - char descr[RNA_DYN_DESCR_MAX]; - char ctxt[RNA_DYN_DESCR_MAX]; + char description[RNA_DYN_DESCR_MAX]; + char translation_context[RNA_DYN_DESCR_MAX]; char undo_group[OP_MAX_TYPENAME]; } temp_buffers; @@ -1302,15 +1269,15 @@ static StructRNA *rna_MacroOperator_register( dummyop.type = &dummyot; dummyot.idname = temp_buffers.idname; /* only assigne the pointer, string is NULL'd */ dummyot.name = temp_buffers.name; /* only assigne the pointer, string is NULL'd */ - dummyot.description = temp_buffers.descr; /* only assigne the pointer, string is NULL'd */ - dummyot.translation_context = temp_buffers.ctxt; /* only assigne the pointer, string is NULL'd */ + dummyot.description = temp_buffers.description; /* only assigne the pointer, string is NULL'd */ + dummyot.translation_context = temp_buffers.translation_context; /* only assigne the pointer, string is NULL'd */ dummyot.undo_group = temp_buffers.undo_group; /* only assigne the pointer, string is NULL'd */ RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr); /* clear in case they are left unset */ - temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.descr[0] = temp_buffers.undo_group[0] = '\0'; + temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.description[0] = temp_buffers.undo_group[0] = '\0'; /* We have to set default op context! */ - strcpy(temp_buffers.ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + strcpy(temp_buffers.translation_context, BLT_I18NCONTEXT_OPERATOR_DEFAULT); /* validate the python class */ if (validate(&dummyotr, data, have_function) != 0) @@ -1322,32 +1289,6 @@ static StructRNA *rna_MacroOperator_register( return NULL; } - { /* convert foo.bar to FOO_OT_bar - * allocate the description and the idname in 1 go */ - const uint idname_len = strlen(temp_buffers.idname) + 4; - const uint name_len = strlen(temp_buffers.name) + 1; - const uint desc_len = strlen(temp_buffers.descr) + 1; - const uint ctxt_len = strlen(temp_buffers.ctxt) + 1; - const uint undo_group_len = strlen(temp_buffers.undo_group) + 1; - /* 2 terminators and 3 to convert a.b -> A_OT_b */ - char *ch = MEM_mallocN( - sizeof(char) * (idname_len + name_len + desc_len + ctxt_len + undo_group_len), __func__); - WM_operator_bl_idname(ch, temp_buffers.idname); /* convert the idname from python */ - dummyot.idname = ch; - ch += idname_len; - memcpy(ch, temp_buffers.name, name_len); - dummyot.name = ch; - ch += name_len; - memcpy(ch, temp_buffers.descr, desc_len); - dummyot.description = ch; - ch += desc_len; - memcpy(ch, temp_buffers.ctxt, ctxt_len); - dummyot.translation_context = ch; - ch += ctxt_len; - memcpy(ch, temp_buffers.undo_group, undo_group_len); - dummyot.undo_group = ch; - } - /* check if we have registered this operator type before, and remove it */ { wmOperatorType *ot = WM_operatortype_find(dummyot.idname, true); @@ -1355,6 +1296,38 @@ static StructRNA *rna_MacroOperator_register( rna_Operator_unregister(bmain, ot->ext.srna); } + if (!WM_operator_py_idname_ok_or_report(reports, identifier, dummyot.idname)) { + return NULL; + } + + char idname_conv[sizeof(dummyop.idname)]; + WM_operator_bl_idname(idname_conv, dummyot.idname); /* convert the idname from python */ + + if (!RNA_struct_available_or_report(reports, idname_conv)) { + return NULL; + } + + /* Convert foo.bar to FOO_OT_bar + * allocate all strings at once. */ + { + const char *strings[] = { + idname_conv, + temp_buffers.name, + temp_buffers.description, + temp_buffers.translation_context, + temp_buffers.undo_group, + }; + char *strings_table[ARRAY_SIZE(strings)]; + BLI_string_join_array_by_sep_char_with_tableN('\0', strings_table, strings, ARRAY_SIZE(strings)); + + dummyot.idname = strings_table[0]; /* allocated string stored here */ + dummyot.name = strings_table[1]; + dummyot.description = strings_table[2]; + dummyot.translation_context = strings_table[3]; + dummyot.undo_group = strings_table[4]; + BLI_assert(ARRAY_SIZE(strings) == 5); + } + /* XXX, this doubles up with the operator name [#29666] * for now just remove from dir(bpy.types) */ @@ -1488,6 +1461,7 @@ static void rna_def_operator(BlenderRNA *brna) RNA_def_struct_register_funcs(srna, "rna_Operator_register", "rna_Operator_unregister", "rna_Operator_instance"); #endif RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1591,6 +1565,7 @@ static void rna_def_macro_operator(BlenderRNA *brna) "rna_Operator_instance"); #endif RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 2400dbcb898..f2f76f13883 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -64,13 +64,13 @@ static void initData(ModifierData *md) static void copyData(ModifierData *md, ModifierData *target) { +#if 0 ArmatureModifierData *amd = (ArmatureModifierData *) md; +#endif ArmatureModifierData *tamd = (ArmatureModifierData *) target; - tamd->object = amd->object; - tamd->deformflag = amd->deformflag; - tamd->multi = amd->multi; - BLI_strncpy(tamd->defgrp_name, amd->defgrp_name, sizeof(tamd->defgrp_name)); + modifier_copyData_generic(md, target); + tamd->prevCos = NULL; } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md)) diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 5874029ae08..93dc0203f83 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -65,19 +65,11 @@ static void initData(ModifierData *md) static void copyData(ModifierData *md, ModifierData *target) { +#if 0 BevelModifierData *bmd = (BevelModifierData *) md; BevelModifierData *tbmd = (BevelModifierData *) target; - - tbmd->value = bmd->value; - tbmd->res = bmd->res; - tbmd->flags = bmd->flags; - tbmd->val_flags = bmd->val_flags; - tbmd->lim_flags = bmd->lim_flags; - tbmd->e_flags = bmd->e_flags; - tbmd->mat = bmd->mat; - tbmd->profile = bmd->profile; - tbmd->bevel_angle = bmd->bevel_angle; - BLI_strncpy(tbmd->defgrp_name, bmd->defgrp_name, sizeof(tbmd->defgrp_name)); +#endif + modifier_copyData_generic(md, target); } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index f86d8b99f3c..1140460161f 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -59,6 +59,7 @@ #include "BLI_alloca.h" #include "BLI_math_geom.h" #include "BKE_material.h" +#include "BKE_global.h" /* only to check G.debug */ #include "MEM_guardedalloc.h" #include "bmesh.h" @@ -224,6 +225,8 @@ static DerivedMesh *applyModifier_bmesh( result = get_quick_derivedMesh(ob, dm, bmd->object, dm_other, bmd->operation); if (result == NULL) { + const bool is_flip = (is_negative_m4(ob->obmat) != is_negative_m4(bmd->object->obmat)); + BMesh *bm; const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm, dm_other); @@ -235,6 +238,16 @@ static DerivedMesh *applyModifier_bmesh( &((struct BMeshCreateParams){.use_toolflags = false,})); DM_to_bmesh_ex(dm_other, bm, true); + + if (UNLIKELY(is_flip)) { + const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); + BMIter iter; + BMFace *efa; + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + BM_face_normal_flip_ex(bm, efa, cd_loop_mdisp_offset, true); + } + } + DM_to_bmesh_ex(dm, bm, true); /* main bmesh intersection setup */ @@ -246,7 +259,7 @@ static DerivedMesh *applyModifier_bmesh( looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__); - BM_mesh_calc_tessellation(bm, looptris, &tottri); + BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri); /* postpone this until after tessellating * so we can use the original normals before the vertex are moved */ @@ -262,7 +275,6 @@ static DerivedMesh *applyModifier_bmesh( invert_m4_m4(imat, ob->obmat); mul_m4_m4m4(omat, imat, bmd->object->obmat); - BMVert *eve; i = 0; BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { @@ -275,8 +287,13 @@ static DerivedMesh *applyModifier_bmesh( /* we need face normals because of 'BM_face_split_edgenet' * we could calculate on the fly too (before calling split). */ { - float nmat[4][4]; - invert_m4_m4(nmat, omat); + float nmat[3][3]; + copy_m3_m4(nmat, omat); + invert_m3(nmat); + + if (UNLIKELY(is_flip)) { + negate_m3(nmat); + } const short ob_src_totcol = bmd->object->totcol; short *material_remap = BLI_array_alloca(material_remap, ob_src_totcol ? ob_src_totcol : 1); @@ -286,7 +303,7 @@ static DerivedMesh *applyModifier_bmesh( BMFace *efa; i = 0; BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - mul_transposed_mat3_m4_v3(nmat, efa->no); + mul_transposed_m3_v3(nmat, efa->no); normalize_v3(efa->no); BM_elem_flag_enable(efa, BM_FACE_TAG); /* temp tag to test which side split faces are from */ @@ -306,11 +323,17 @@ static DerivedMesh *applyModifier_bmesh( * currently this is ok for 'BM_mesh_intersect' */ // BM_mesh_normals_update(bm); - /* change for testing */ bool use_separate = false; bool use_dissolve = true; bool use_island_connect = true; + /* change for testing */ + if (G.debug & G_DEBUG) { + use_separate = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0; + use_dissolve = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0; + use_island_connect = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == 0; + } + BM_mesh_intersect( bm, looptris, tottri, diff --git a/source/blender/modifiers/intern/MOD_boolean_util.c b/source/blender/modifiers/intern/MOD_boolean_util.c index 061b1198f7e..49010664aa8 100644 --- a/source/blender/modifiers/intern/MOD_boolean_util.c +++ b/source/blender/modifiers/intern/MOD_boolean_util.c @@ -390,6 +390,9 @@ static void exporter_InitGeomArrays(ExportMeshData *export_data, * the operand. Data for those layers will not be allocated or initialized. */ + CustomData_merge(&dm_left->vertData, &dm->vertData, merge_mask, CD_DEFAULT, num_verts); + CustomData_merge(&dm_right->vertData, &dm->vertData, merge_mask, CD_DEFAULT, num_verts); + CustomData_merge(&dm_left->loopData, &dm->loopData, merge_mask, CD_DEFAULT, num_loops); CustomData_merge(&dm_right->loopData, &dm->loopData, merge_mask, CD_DEFAULT, num_loops); diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index a364eef2974..56a274b9ac9 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -47,6 +47,8 @@ #include "BKE_particle.h" #include "BKE_scene.h" + + #ifdef _OPENMP # include "BKE_mesh.h" /* BKE_MESH_OMP_LIMIT */ #endif diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index e7ff0a90fbc..74e49dda074 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -40,7 +40,6 @@ #include "BLI_math.h" #include "BLI_utildefines.h" - #include "BKE_collision.h" #include "BKE_cdderivedmesh.h" #include "BKE_global.h" @@ -48,6 +47,8 @@ #include "BKE_pointcache.h" #include "BKE_scene.h" +#include "MOD_modifiertypes.h" + static void initData(ModifierData *md) { CollisionModifierData *collmd = (CollisionModifierData *) md; @@ -152,8 +153,6 @@ static void deformVerts(ModifierData *md, Object *ob, collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame collmd->mvert_num = mvert_num; - - DM_ensure_looptri(dm); collmd->tri_num = dm->getNumLoopTri(dm); { diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index 3c6ba7acc88..c9a910d769b 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -39,7 +39,6 @@ #include "BLI_utildefines.h" - #include "BKE_cdderivedmesh.h" #include "BKE_lattice.h" #include "BKE_library_query.h" @@ -48,6 +47,7 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" +#include "MOD_modifiertypes.h" static void initData(ModifierData *md) { diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 3325f05025f..fb8c0dd05a5 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -75,14 +75,10 @@ static void copyData(ModifierData *md, ModifierData *target) { #if 0 DisplaceModifierData *dmd = (DisplaceModifierData *) md; -#endif DisplaceModifierData *tdmd = (DisplaceModifierData *) target; +#endif modifier_copyData_generic(md, target); - - if (tdmd->texture) { - id_us_plus(&tdmd->texture->id); - } } static void freeData(ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index 83a42504180..eec97828091 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -43,6 +43,7 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" +#include "MOD_modifiertypes.h" static void initData(ModifierData *md) { diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index 4441edb299b..a17870f2bf4 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -48,6 +48,7 @@ #include "DNA_object_types.h" +#include "MOD_modifiertypes.h" static DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd) { diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index ca7b3ce8039..72bc046b440 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -51,9 +51,9 @@ #include "BKE_particle.h" #include "BKE_scene.h" - #include "MEM_guardedalloc.h" +#include "MOD_modifiertypes.h" static void initData(ModifierData *md) { diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c index 1964e940cb2..53f955b15f0 100644 --- a/source/blender/modifiers/intern/MOD_fluidsim.c +++ b/source/blender/modifiers/intern/MOD_fluidsim.c @@ -47,6 +47,8 @@ #include "DEG_depsgraph_build.h" #include "MOD_fluidsim_util.h" +#include "MOD_modifiertypes.h" + #include "MEM_guardedalloc.h" /* Fluidsim */ diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index ce3fdc4bbe8..c2896e83a0b 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -29,7 +29,7 @@ */ #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_math.h" #include "BLI_string.h" @@ -539,7 +539,7 @@ static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh STACK_PUSH(index_anchors, i); } } - DM_ensure_looptri(dm); + total_anchors = STACK_SIZE(index_anchors); lmd->cache_system = initLaplacianSystem(numVerts, dm->getNumEdges(dm), dm->getNumLoopTri(dm), total_anchors, lmd->anchor_grp_name, lmd->repeat); diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c index dcc7fe4d4f1..18caf4a39f4 100644 --- a/source/blender/modifiers/intern/MOD_mask.c +++ b/source/blender/modifiers/intern/MOD_mask.c @@ -53,6 +53,8 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" +#include "MOD_modifiertypes.h" + #include "BLI_strict_flags.h" static void copyData(ModifierData *md, ModifierData *target) diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c index 8360c8ffda7..4b2b3f17d18 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c +++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c @@ -146,7 +146,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp, return false; } - if (fseek(fp, sizeof(float) * 3 * index * pc2_head.verts_tot , SEEK_CUR) != 0) { + if (fseek(fp, sizeof(float) * 3 * index * pc2_head.verts_tot, SEEK_CUR) != 0) { *err_str = "Failed to seek frame"; return false; } diff --git a/source/blender/modifiers/intern/MOD_meshcache_util.c b/source/blender/modifiers/intern/MOD_meshcache_util.c index c263c4810e4..10861f5b02b 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_util.c +++ b/source/blender/modifiers/intern/MOD_meshcache_util.c @@ -36,7 +36,7 @@ void MOD_meshcache_calc_range(const float frame, const char interp, int r_index_range[2], float *r_factor) { if (interp == MOD_MESHCACHE_INTERP_NONE) { - r_index_range[0] = r_index_range[1] = max_ii(0, min_ii(frame_tot - 1, iroundf(frame))); + r_index_range[0] = r_index_range[1] = max_ii(0, min_ii(frame_tot - 1, round_fl_to_int(frame))); *r_factor = 1.0f; /* dummy */ } else { diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index f0edcc31a10..5b059ef89d2 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -25,12 +25,14 @@ */ #include "DNA_cachefile_types.h" +#include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BKE_cachefile.h" #include "BKE_DerivedMesh.h" +#include "BKE_cdderivedmesh.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -95,11 +97,15 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, - ModifierApplyFlag flag) + ModifierApplyFlag UNUSED(flag)) { #ifdef WITH_ALEMBIC MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; + /* Only used to check whether we are operating on org data or not... */ + Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; + DerivedMesh *org_dm = dm; + Scene *scene = md->scene; const float frame = BKE_scene_frame_get(scene); const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS); @@ -121,6 +127,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, } } + if (me != NULL) { + MVert *mvert = dm->getVertArray(dm); + MEdge *medge = dm->getEdgeArray(dm); + MPoly *mpoly = dm->getPolyArray(dm); + if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) { + /* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */ + dm = CDDM_copy(dm); + } + } + DerivedMesh *result = ABC_read_mesh(mcmd->reader, ob, dm, @@ -132,11 +148,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, modifier_setError(md, "%s", err_str); } + if (!ELEM(result, NULL, dm) && (dm != org_dm)) { + dm->release(dm); + dm = org_dm; + } + return result ? result : dm; - UNUSED_VARS(flag); #else return dm; - UNUSED_VARS(md, ob, flag); + UNUSED_VARS(md, ob); #endif } diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 9705edc580c..157f37e973c 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -48,6 +48,8 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" +#include "MOD_modifiertypes.h" + static void initData(ModifierData *md) { MirrorModifierData *mmd = (MirrorModifierData *) md; @@ -263,7 +265,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, /* handle uvs, * let tessface recalc handle updating the MTFace data */ - if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) { + if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) || (is_zero_v2(mmd->uv_offset_copy) == false)) { const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0; const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0; @@ -276,6 +278,8 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, for (; j-- > 0; dmloopuv++) { if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0]; if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1]; + dmloopuv->uv[0] += mmd->uv_offset_copy[0]; + dmloopuv->uv[1] += mmd->uv_offset_copy[1]; } } } diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index 90ad1bdfdc2..f9f17b88fa4 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -46,6 +46,8 @@ #include "BKE_modifier.h" #include "BKE_subsurf.h" +#include "MOD_modifiertypes.h" + static void initData(ModifierData *md) { MultiresModifierData *mmd = (MultiresModifierData *)md; diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index 2c0bfc86e7d..8d8565e7e62 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -44,6 +44,8 @@ #include "BKE_modifier.h" #include "BKE_ocean.h" +#include "MOD_modifiertypes.h" + #ifdef WITH_OCEANSIM static void init_cache_data(Object *ob, struct OceanModifierData *omd) { diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index fbf5a958254..0c91cb08da7 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -54,6 +54,8 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" +#include "MOD_modifiertypes.h" + static void initData(ModifierData *md) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 87859cd240a..2c3d7f394bb 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -112,6 +112,56 @@ static void screwvert_iter_step(ScrewVertIter *iter) } } +static DerivedMesh *dm_remove_doubles_on_axis( + DerivedMesh *result, MVert *mvert_new, const uint totvert, const uint step_tot, + const float axis_vec[3], const float axis_offset[3], const float merge_threshold) +{ + const float merge_threshold_sq = SQUARE(merge_threshold); + const bool use_offset = axis_offset != NULL; + uint tot_doubles = 0; + for (uint i = 0; i < totvert; i += 1) { + float axis_co[3]; + if (use_offset) { + float offset_co[3]; + sub_v3_v3v3(offset_co, mvert_new[i].co, axis_offset); + project_v3_v3v3_normalized(axis_co, offset_co, axis_vec); + add_v3_v3(axis_co, axis_offset); + } + else { + project_v3_v3v3_normalized(axis_co, mvert_new[i].co, axis_vec); + } + const float dist_sq = len_squared_v3v3(axis_co, mvert_new[i].co); + if (dist_sq <= merge_threshold_sq) { + mvert_new[i].flag |= ME_VERT_TMP_TAG; + tot_doubles += 1; + copy_v3_v3(mvert_new[i].co, axis_co); + } + } + + if (tot_doubles != 0) { + uint tot = totvert * step_tot; + int *full_doubles_map = MEM_mallocN(sizeof(int) * tot, __func__); + copy_vn_i(full_doubles_map, (int)tot, -1); + + uint tot_doubles_left = tot_doubles; + for (uint i = 0; i < totvert; i += 1) { + if (mvert_new[i].flag & ME_VERT_TMP_TAG) { + int *doubles_map = &full_doubles_map[totvert + i] ; + for (uint step = 1; step < step_tot; step += 1) { + *doubles_map = (int)i; + doubles_map += totvert; + } + tot_doubles_left -= 1; + if (tot_doubles_left == 0) { + break; + } + } + } + result = CDDM_merge_verts(result, full_doubles_map, (int)(tot_doubles * (step_tot - 1)), CDDM_MERGE_VERTS_DUMP_IF_MAPPED); + MEM_freeN(full_doubles_map); + } + return result; +} static void initData(ModifierData *md) { @@ -123,6 +173,7 @@ static void initData(ModifierData *md) ltmd->steps = 16; ltmd->render_steps = 16; ltmd->iter = 1; + ltmd->merge_dist = 0.01f; } static void copyData(ModifierData *md, ModifierData *target) @@ -1050,6 +1101,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, MEM_freeN(vert_loop_map); } + if ((ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f)) { + DerivedMesh *result_prev = result; + result = dm_remove_doubles_on_axis( + result, mvert_new, totvert, step_tot, + axis_vec, ltmd->ob_axis ? mtx_tx[3] : NULL, ltmd->merge_dist); + if (result != result_prev) { + result->dirty |= DM_DIRTY_NORMALS; + } + } + if ((ltmd->flag & MOD_SCREW_NORMAL_CALC) == 0) { result->dirty |= DM_DIRTY_NORMALS; } diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 8ed623734be..ad1e4badd3e 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -77,6 +77,8 @@ #include "BKE_mesh_mapping.h" #include "BKE_modifier.h" +#include "MOD_modifiertypes.h" + #include "bmesh.h" typedef struct { diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c index c105a3ab3a7..7f2d9e42fe6 100644 --- a/source/blender/modifiers/intern/MOD_smoke.c +++ b/source/blender/modifiers/intern/MOD_smoke.c @@ -45,7 +45,6 @@ #include "BLI_utildefines.h" - #include "BKE_cdderivedmesh.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -56,6 +55,8 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" +#include "MOD_modifiertypes.h" + static void initData(ModifierData *md) { SmokeModifierData *smd = (SmokeModifierData *) md; diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index 911b6997058..e96771e0665 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -36,7 +36,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_bitmap.h" #include "BLI_math.h" diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c index 6fad2756f82..b057d6d5a86 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.c +++ b/source/blender/modifiers/intern/MOD_triangulate.c @@ -35,6 +35,8 @@ #include "bmesh.h" #include "bmesh_tools.h" +#include "MOD_modifiertypes.h" + static DerivedMesh *triangulate_dm(DerivedMesh *dm, const int quad_method, const int ngon_method) { DerivedMesh *result; diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index f0c4940816e..b4990c5250e 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -90,14 +90,10 @@ static void copyData(ModifierData *md, ModifierData *target) { #if 0 WaveModifierData *wmd = (WaveModifierData *) md; -#endif WaveModifierData *twmd = (WaveModifierData *) target; +#endif modifier_copyData_generic(md, target); - - if (twmd->texture) { - id_us_plus(&twmd->texture->id); - } } static bool dependsOnTime(ModifierData *UNUSED(md)) diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index cd30b54350c..13a97c1c13d 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -50,7 +50,9 @@ #include "DEG_depsgraph_build.h" #include "MEM_guardedalloc.h" + #include "MOD_weightvg_util.h" +#include "MOD_modifiertypes.h" /************************************** * Modifiers functions. * @@ -91,10 +93,6 @@ static void copyData(ModifierData *md, ModifierData *target) modifier_copyData_generic(md, target); twmd->cmap_curve = curvemapping_copy(wmd->cmap_curve); - - if (twmd->mask_texture) { - id_us_plus(&twmd->mask_texture->id); - } } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 1b3188c83b3..392f42040b0 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -47,7 +47,9 @@ #include "DEG_depsgraph_build.h" #include "MEM_guardedalloc.h" + #include "MOD_weightvg_util.h" +#include "MOD_modifiertypes.h" /** @@ -136,14 +138,10 @@ static void copyData(ModifierData *md, ModifierData *target) { #if 0 WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; -#endif WeightVGMixModifierData *twmd = (WeightVGMixModifierData *) target; +#endif modifier_copyData_generic(md, target); - - if (twmd->mask_texture) { - id_us_plus(&twmd->mask_texture->id); - } } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 2c87838aeab..2ca380ba5c2 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -51,7 +51,9 @@ #include "DEG_depsgraph_build.h" #include "MEM_guardedalloc.h" + #include "MOD_weightvg_util.h" +#include "MOD_modifiertypes.h" //#define USE_TIMEIT @@ -286,14 +288,10 @@ static void copyData(ModifierData *md, ModifierData *target) { #if 0 WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; -#endif WeightVGProximityModifierData *twmd = (WeightVGProximityModifierData *) target; +#endif modifier_copyData_generic(md, target); - - if (twmd->mask_texture) { - id_us_plus(&twmd->mask_texture->id); - } } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index 8139e29bade..a95c3233132 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -178,6 +178,9 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node, LinkNod cmp_node_image_add_pass_output(ntree, node, "Alpha", RE_PASSNAME_COMBINED, -1, SOCK_FLOAT, false, available_sockets, &prev_index); if (ima) { + if (!ima->rr) { + cmp_node_image_add_pass_output(ntree, node, RE_PASSNAME_Z, RE_PASSNAME_Z, -1, SOCK_FLOAT, false, available_sockets, &prev_index); + } BKE_image_release_ibuf(ima, ibuf, NULL); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c index 5a9e33a4053..8262b70fc44 100644 --- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c +++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c @@ -51,14 +51,23 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *UNUSED(node), bNodeE return GPU_stack_link(mat, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION)); } -static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) +static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) { ShadeInput *shi = ((ShaderCallData *)data)->shi; - float eta = max_ff(in[0]->vec[0], 0.00001); + + /* Compute IOR. */ + float eta; + nodestack_get_vec(&eta, SOCK_FLOAT, in[0]); + eta = max_ff(eta, 0.00001); + eta = shi->flippednor ? 1 / eta : eta; + + /* Get normal from socket, but only if linked. */ + bNodeSocket *sock_normal = node->inputs.first; + sock_normal = sock_normal->next; float n[3]; - if (in[1]->hasinput) { - copy_v3_v3(n, in[1]->vec); + if (sock_normal->link) { + nodestack_get_vec(n, SOCK_VECTOR, in[1]); } else { copy_v3_v3(n, shi->vn); @@ -68,7 +77,7 @@ static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *UNUS mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), n); } - out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, shi->flippednor ? 1 / eta : eta); + out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, eta); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c index a0b2408a7bb..998e1a5687e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c +++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c @@ -52,24 +52,33 @@ static int node_shader_gpu_layer_weight(GPUMaterial *mat, bNode *UNUSED(node), b return GPU_stack_link(mat, "node_layer_weight", in, out, GPU_builtin(GPU_VIEW_POSITION)); } -static void node_shader_exec_layer_weight(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) +static void node_shader_exec_layer_weight(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) { ShadeInput *shi = ((ShaderCallData *)data)->shi; - float blend = in[0]->vec[0]; + + /* Compute IOR. */ + float blend; + nodestack_get_vec(&blend, SOCK_FLOAT, in[0]); float eta = max_ff(1 - blend, 0.00001); + eta = shi->flippednor ? eta : 1 / eta; + + /* Get normal from socket, but only if linked. */ + bNodeSocket *sock_normal = node->inputs.first; + sock_normal = sock_normal->next; float n[3]; - if (in[1]->hasinput) { - copy_v3_v3(n, in[1]->vec); + if (sock_normal->link) { + nodestack_get_vec(n, SOCK_VECTOR, in[1]); } else { copy_v3_v3(n, shi->vn); } + if (shi->use_world_space_shading) mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), n); - out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, shi->flippednor ? eta : 1 / eta); + out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, eta); float facing = fabs(dot_v3v3(shi->view, n)); if (blend != 0.5) { diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c index 8f287918a4a..6598d402f72 100644 --- a/source/blender/python/bmesh/bmesh_py_ops_call.c +++ b/source/blender/python/bmesh/bmesh_py_ops_call.c @@ -44,6 +44,7 @@ #include "bmesh_py_types.h" #include "../generic/python_utildefines.h" +#include "../generic/py_capi_utils.h" static int bpy_bm_op_as_py_error(BMesh *bm) { @@ -152,11 +153,9 @@ static int bpy_slot_from_py( switch (slot->slot_type) { case BMO_OP_SLOT_BOOL: { - int param; + const int param = PyC_Long_AsBool(value); - param = PyLong_AsLong(value); - - if (param < 0) { + if (param == -1) { PyErr_Format(PyExc_TypeError, "%.200s: keyword \"%.200s\" expected True/False or 0/1, not %.200s", opname, slot_name, Py_TYPE(value)->tp_name); @@ -170,23 +169,16 @@ static int bpy_slot_from_py( } case BMO_OP_SLOT_INT: { - int overflow; - long param = PyLong_AsLongAndOverflow(value, &overflow); - if (overflow || (param > INT_MAX) || (param < INT_MIN)) { - PyErr_Format(PyExc_ValueError, - "%.200s: keyword \"%.200s\" value not in 'int' range " - "(" STRINGIFY(INT_MIN) ", " STRINGIFY(INT_MAX) ")", - opname, slot_name, Py_TYPE(value)->tp_name); - return -1; - } - else if (param == -1 && PyErr_Occurred()) { + const int param = PyC_Long_AsI32(value); + + if (param == -1 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "%.200s: keyword \"%.200s\" expected an int, not %.200s", opname, slot_name, Py_TYPE(value)->tp_name); return -1; } else { - BMO_SLOT_AS_INT(slot) = (int)param; + BMO_SLOT_AS_INT(slot) = param; } break; } @@ -208,26 +200,19 @@ static int bpy_slot_from_py( { /* XXX - BMesh operator design is crappy here, operator slot should define matrix size, * not the caller! */ - unsigned short size; - if (!MatrixObject_Check(value)) { - PyErr_Format(PyExc_TypeError, - "%.200s: keyword \"%.200s\" expected a Matrix, not %.200s", - opname, slot_name, Py_TYPE(value)->tp_name); + MatrixObject *pymat; + if (!Matrix_ParseAny(value, &pymat)) { return -1; } - else if (BaseMath_ReadCallback((MatrixObject *)value) == -1) { - return -1; - } - else if (((size = ((MatrixObject *)value)->num_col) != ((MatrixObject *)value)->num_row) || - (ELEM(size, 3, 4) == false)) - { + const ushort size = pymat->num_col; + if ((size != pymat->num_row) || (!ELEM(size, 3, 4))) { PyErr_Format(PyExc_TypeError, "%.200s: keyword \"%.200s\" expected a 3x3 or 4x4 matrix Matrix", opname, slot_name); return -1; } - BMO_slot_mat_set(bmop, bmop->slots_in, slot_name, ((MatrixObject *)value)->matrix, size); + BMO_slot_mat_set(bmop, bmop->slots_in, slot_name, pymat->matrix, size); break; } case BMO_OP_SLOT_VEC: @@ -436,7 +421,7 @@ static int bpy_slot_from_py( return -1; /* error is set in bpy_slot_from_py_elem_check() */ } - value_i = PyLong_AsLong(arg_value); + value_i = PyC_Long_AsI32(arg_value); if (value_i == -1 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, @@ -466,7 +451,7 @@ static int bpy_slot_from_py( return -1; /* error is set in bpy_slot_from_py_elem_check() */ } - value_i = PyLong_AsLong(arg_value); + value_i = PyC_Long_AsI32(arg_value); if (value_i == -1 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index b20c03bee28..52ca475297d 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -124,25 +124,19 @@ static int bpy_bm_elem_hflag_set(BPy_BMElem *self, PyObject *value, void *flag) BPY_BM_CHECK_INT(self); - param = PyLong_AsLong(value); - - if ((unsigned int)param <= 1) { - if (hflag == BM_ELEM_SELECT) - BM_elem_select_set(self->bm, self->ele, param); - else - BM_elem_flag_set(self->ele, hflag, param); + if ((param = PyC_Long_AsBool(value)) == -1) { + return -1; + } - return 0; + if (hflag == BM_ELEM_SELECT) { + BM_elem_select_set(self->bm, self->ele, param); } else { - PyErr_Format(PyExc_TypeError, - "expected True/False or 0/1, not %.200s", - Py_TYPE(value)->tp_name); - return -1; + BM_elem_flag_set(self->ele, hflag, param); } + return 0; } - PyDoc_STRVAR(bpy_bm_elem_index_doc, "Index of this element.\n" "\n" @@ -169,21 +163,17 @@ static int bpy_bm_elem_index_set(BPy_BMElem *self, PyObject *value, void *UNUSED BPY_BM_CHECK_INT(self); - param = PyLong_AsLong(value); - - if (param == -1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "expected an int type"); + if (((param = PyC_Long_AsI32(value)) == -1) && PyErr_Occurred()) { + /* error is set */ return -1; } - else { - BM_elem_index_set(self->ele, param); /* set_dirty! */ - /* when setting the index assume its set invalid */ - self->bm->elem_index_dirty |= self->ele->head.htype; + BM_elem_index_set(self->ele, param); /* set_dirty! */ - return 0; - } + /* when setting the index assume its set invalid */ + self->bm->elem_index_dirty |= self->ele->head.htype; + + return 0; } /* type specific get/sets @@ -506,14 +496,12 @@ static int bpy_bmface_material_index_set(BPy_BMFace *self, PyObject *value) BPY_BM_CHECK_INT(self); - param = PyLong_AsLong(value); - - if (param == -1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "expected an int type"); + if (((param = PyC_Long_AsI32(value)) == -1) && PyErr_Occurred()) { + /* error is set */ return -1; } - else if ((param < 0) || (param > MAXMAT)) { + + if ((param < 0) || (param > MAXMAT)) { /* normally we clamp but in this case raise an error */ PyErr_SetString(PyExc_ValueError, "material index outside of usable range (0 - 32766)"); @@ -1049,6 +1037,13 @@ PyDoc_STRVAR(bpy_bmesh_from_mesh_doc, " :type use_shape_key: boolean\n" " :arg shape_key_index: The shape key index to use.\n" " :type shape_key_index: int\n" +"\n" +" .. note::\n" +"\n" +" Multiple calls can be used to join multiple meshes.\n" +"\n" +" Custom-data layers are only copied from ``mesh`` on initialization.\n" +" Further calls will copy custom-data to matching layers, layers missing on the target mesh wont be added.\n" ); static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw) { @@ -1113,15 +1108,16 @@ static PyObject *bpy_bmesh_select_flush(BPy_BMesh *self, PyObject *value) BPY_BM_CHECK_OBJ(self); - param = PyLong_AsLong(value); - if (param != false && param != true) { - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + if ((param = PyC_Long_AsBool(value)) == -1) { return NULL; } - if (param) BM_mesh_select_flush(self->bm); - else BM_mesh_deselect_flush(self->bm); + if (param) { + BM_mesh_select_flush(self->bm); + } + else { + BM_mesh_deselect_flush(self->bm); + } Py_RETURN_NONE; } @@ -1301,10 +1297,7 @@ static PyObject *bpy_bm_elem_select_set(BPy_BMElem *self, PyObject *value) BPY_BM_CHECK_OBJ(self); - param = PyLong_AsLong(value); - if (param != false && param != true) { - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + if ((param = PyC_Long_AsBool(value)) == -1) { return NULL; } @@ -1329,10 +1322,7 @@ static PyObject *bpy_bm_elem_hide_set(BPy_BMElem *self, PyObject *value) BPY_BM_CHECK_OBJ(self); - param = PyLong_AsLong(value); - if (param != false && param != true) { - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + if ((param = PyC_Long_AsBool(value)) == -1) { return NULL; } diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index 908f6b5a734..cb95ded4f0d 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -43,6 +43,7 @@ #include "../mathutils/mathutils.h" #include "../generic/python_utildefines.h" +#include "../generic/py_capi_utils.h" #include "BKE_customdata.h" @@ -1074,9 +1075,9 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj } case CD_PROP_INT: { - int tmp_val = PyLong_AsLong(py_value); + int tmp_val = PyC_Long_AsI32(py_value); if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) { - PyErr_Format(PyExc_TypeError, "expected an int, not a %.200s", Py_TYPE(py_value)->tp_name); + /* error is set */ ret = -1; } else { diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c index 92c11a03433..b01d3f89d4e 100644 --- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c @@ -45,6 +45,7 @@ #include "bmesh_py_types_meshdata.h" +#include "../generic/py_capi_utils.h" #include "../generic/python_utildefines.h" @@ -188,7 +189,7 @@ static int bpy_bmloopuv_flag_set(BPy_BMLoopUV *self, PyObject *value, void *flag { const int flag = GET_INT_FROM_POINTER(flag_p); - switch (PyLong_AsLong(value)) { + switch (PyC_Long_AsBool(value)) { case true: self->data->flag |= flag; return 0; @@ -196,8 +197,7 @@ static int bpy_bmloopuv_flag_set(BPy_BMLoopUV *self, PyObject *value, void *flag self->data->flag &= ~flag; return 0; default: - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + /* error is set */ return -1; } } @@ -297,7 +297,7 @@ static int bpy_bmvertskin_flag_set(BPy_BMVertSkin *self, PyObject *value, void * { const int flag = GET_INT_FROM_POINTER(flag_p); - switch (PyLong_AsLong(value)) { + switch (PyC_Long_AsBool(value)) { case true: self->data->flag |= flag; return 0; @@ -305,8 +305,7 @@ static int bpy_bmvertskin_flag_set(BPy_BMVertSkin *self, PyObject *value, void * self->data->flag &= ~flag; return 0; default: - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + /* error is set */ return -1; } } diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 3ea10228ad4..9cf00192db5 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -472,6 +472,49 @@ int BGL_typeSize(int type) return -1; } +static int gl_buffer_type_from_py_format_char(char *typestr) +{ + if (ELEM(typestr[0], '<', '>', '|')) { + typestr += 1; + } + char format = typestr[0]; + char byte_num = typestr[1]; + + switch (format) { + case 't': + case 'b': + case 'h': + if (!byte_num) return GL_BYTE; + ATTR_FALLTHROUGH; + case 'i': + if (!byte_num) return GL_SHORT; + ATTR_FALLTHROUGH; + case 'l': + if (!byte_num || byte_num == '4') return GL_INT; + if (byte_num == '1') return GL_BYTE; + if (byte_num == '2') return GL_SHORT; + break; + case 'f': + if (!byte_num) return GL_FLOAT; + ATTR_FALLTHROUGH; + case 'd': + if (!byte_num || byte_num == '8') return GL_DOUBLE; + if (byte_num == '4') return GL_FLOAT; + break; + } + return -1; /* UNKNOWN */ +} + +static bool compare_dimensions(int ndim, int *dim1, Py_ssize_t *dim2) +{ + for (int i = 0; i < ndim; i++) { + if (dim1[i] != dim2[i]) { + return false; + } + } + return true; +} + /** \} */ @@ -630,6 +673,22 @@ PyTypeObject BGL_bufferType = { NULL /*tp_del*/ }; + +static Buffer *BGL_MakeBuffer_FromData(PyObject *parent, int type, int ndimensions, int *dimensions, void *buf) +{ + Buffer *buffer = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType); + + Py_XINCREF(parent); + buffer->parent = parent; + buffer->ndimensions = ndimensions; + buffer->dimensions = MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions"); + memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int)); + buffer->type = type; + buffer->buf.asvoid = buf; + + return buffer; +} + /** * Create a buffer object * @@ -641,30 +700,21 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf { Buffer *buffer; void *buf = NULL; - int i, size, length; + int i, size = BGL_typeSize(type); - length = 1; for (i = 0; i < ndimensions; i++) { - length *= dimensions[i]; + size *= dimensions[i]; } - size = BGL_typeSize(type); + buf = MEM_mallocN(size, "Buffer buffer"); - buf = MEM_mallocN(length * size, "Buffer buffer"); - - buffer = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType); - buffer->parent = NULL; - buffer->ndimensions = ndimensions; - buffer->dimensions = MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions"); - memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int)); - buffer->type = type; - buffer->buf.asvoid = buf; + buffer = BGL_MakeBuffer_FromData(NULL, type, ndimensions, dimensions, buf); if (initbuffer) { - memcpy(buffer->buf.asvoid, initbuffer, length * size); + memcpy(buffer->buf.asvoid, initbuffer, size); } else { - memset(buffer->buf.asvoid, 0, length * size); + memset(buffer->buf.asvoid, 0, size); } return buffer; } @@ -674,7 +724,7 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) { PyObject *length_ob = NULL, *init = NULL; - Buffer *buffer; + Buffer *buffer = NULL; int dimensions[MAX_DIMENSIONS]; int type; @@ -739,9 +789,32 @@ static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject return NULL; } - buffer = BGL_MakeBuffer(type, ndimensions, dimensions, NULL); - if (init && ndimensions) { - if (Buffer_ass_slice(buffer, 0, dimensions[0], init)) { + if (init && PyObject_CheckBuffer(init)) { + Py_buffer pybuffer; + + if (PyObject_GetBuffer(init, &pybuffer, PyBUF_ND | PyBUF_FORMAT) == -1) { + /* PyObject_GetBuffer raise a PyExc_BufferError */ + return NULL; + } + + if (type != gl_buffer_type_from_py_format_char(pybuffer.format)) { + PyErr_Format(PyExc_TypeError, + "`GL_TYPE` and `typestr` of object with buffer interface do not match. '%s'", pybuffer.format); + } + else if (ndimensions != pybuffer.ndim || + !compare_dimensions(ndimensions, dimensions, pybuffer.shape)) + { + PyErr_Format(PyExc_TypeError, "array size does not match"); + } + else { + buffer = BGL_MakeBuffer_FromData(init, type, pybuffer.ndim, dimensions, pybuffer.buf); + } + + PyBuffer_Release(&pybuffer); + } + else { + buffer = BGL_MakeBuffer(type, ndimensions, dimensions, NULL); + if (init && Buffer_ass_slice(buffer, 0, dimensions[0], init)) { Py_DECREF(buffer); return NULL; } @@ -774,27 +847,17 @@ static PyObject *Buffer_item(Buffer *self, int i) } } else { - Buffer *newbuf; - int j, length, size; + int j, offset = i * BGL_typeSize(self->type); - length = 1; for (j = 1; j < self->ndimensions; j++) { - length *= self->dimensions[j]; + offset *= self->dimensions[j]; } - size = BGL_typeSize(self->type); - - newbuf = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType); - - Py_INCREF(self); - newbuf->parent = (PyObject *)self; - - newbuf->ndimensions = self->ndimensions - 1; - newbuf->type = self->type; - newbuf->buf.asvoid = self->buf.asbyte + i * length * size; - newbuf->dimensions = MEM_mallocN(newbuf->ndimensions * sizeof(int), "Buffer dimensions"); - memcpy(newbuf->dimensions, self->dimensions + 1, newbuf->ndimensions * sizeof(int)); - return (PyObject *)newbuf; + return (PyObject *)BGL_MakeBuffer_FromData( + (PyObject *)self, self->type, + self->ndimensions - 1, + self->dimensions + 1, + self->buf.asbyte + offset); } return NULL; diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c index ed2752d8372..7ab6447d21a 100644 --- a/source/blender/python/generic/bpy_internal_import.c +++ b/source/blender/python/generic/bpy_internal_import.c @@ -248,8 +248,17 @@ PyObject *bpy_text_reimport(PyObject *module, int *found) if ((name = PyModule_GetName(module)) == NULL) return NULL; - if ((filepath = (char *)PyModule_GetFilename(module)) == NULL) - return NULL; + { + PyObject *module_file = PyModule_GetFilenameObject(module); + if (module_file == NULL) { + return NULL; + } + filepath = (char *)_PyUnicode_AsString(module_file); + Py_DECREF(module_file); + if (filepath == NULL) { + return NULL; + } + } /* look up the text object */ text = BLI_findstring(&maggie->text, BLI_path_basename(filepath), offsetof(ID, name) + 2); diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index 5d6a7c578a2..1153e0176df 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -386,7 +386,7 @@ static IDProperty *idp_from_PyFloat(const char *name, PyObject *ob) static IDProperty *idp_from_PyLong(const char *name, PyObject *ob) { IDPropertyTemplate val = {0}; - val.i = _PyLong_AsInt(ob); + val.i = PyC_Long_AsI32(ob); if (val.i == -1 && PyErr_Occurred()) { return NULL; } @@ -499,7 +499,7 @@ static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob) prop_data = IDP_Array(prop); for (i = 0; i < val.array.len; i++) { item = ob_seq_fast_items[i]; - if (((prop_data[i] = _PyLong_AsInt(item)) == -1) && PyErr_Occurred()) { + if (((prop_data[i] = PyC_Long_AsI32(item)) == -1) && PyErr_Occurred()) { return NULL; } } @@ -1337,7 +1337,7 @@ static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value) } case IDP_INT: { - const int i = _PyLong_AsInt(value); + const int i = PyC_Long_AsI32(value); if (i == -1 && PyErr_Occurred()) { return -1; } diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 2e789d6d4b3..d49f9514b8c 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -85,7 +85,7 @@ int PyC_AsArray_FAST( /* could use is_double for 'long int' but no use now */ int *array_int = array; for (i = 0; i < length; i++) { - array_int[i] = PyLong_AsLong(value_fast_items[i]); + array_int[i] = PyC_Long_AsI32(value_fast_items[i]); } } else if (type == &PyBool_Type) { @@ -127,54 +127,52 @@ int PyC_AsArray( return ret; } +/* -------------------------------------------------------------------- */ +/** \name Typed Tuple Packing + * + * \note See #PyC_Tuple_Pack_* macros that take multiple arguments. + * + * \{ */ + /* array utility function */ -PyObject *PyC_FromArray(const void *array, int length, const PyTypeObject *type, - const bool is_double, const char *error_prefix) +PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len) { - PyObject *tuple; - int i; - - tuple = PyTuple_New(length); - - /* for each type */ - if (type == &PyFloat_Type) { - if (is_double) { - const double *array_double = array; - for (i = 0; i < length; ++i) { - PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array_double[i])); - } - } - else { - const float *array_float = array; - for (i = 0; i < length; ++i) { - PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array_float[i])); - } - } - } - else if (type == &PyLong_Type) { - /* could use is_double for 'long int' but no use now */ - const int *array_int = array; - for (i = 0; i < length; ++i) { - PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(array_int[i])); - } + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array[i])); } - else if (type == &PyBool_Type) { - const int *array_bool = array; - for (i = 0; i < length; ++i) { - PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array_bool[i])); - } + return tuple; +} + +PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len) +{ + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(array[i])); } - else { - Py_DECREF(tuple); - PyErr_Format(PyExc_TypeError, - "%s: internal error %s is invalid", - error_prefix, type->tp_name); - return NULL; + return tuple; +} + +PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len) +{ + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array[i])); } + return tuple; +} +PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len) +{ + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array[i])); + } return tuple; } +/** \} */ + /** * Caller needs to ensure tuple is uninitialized. * Handy for filling a tuple with None for eg. @@ -203,6 +201,8 @@ void PyC_List_Fill(PyObject *list, PyObject *value) /** * Use with PyArg_ParseTuple's "O&" formatting. + * + * \see #PyC_Long_AsBool for a similar function to use outside of argument parsing. */ int PyC_ParseBool(PyObject *o, void *p) { @@ -300,7 +300,14 @@ void PyC_FileAndNum(const char **filename, int *lineno) if (mod_name) { PyObject *mod = PyDict_GetItem(PyImport_GetModuleDict(), mod_name); if (mod) { - *filename = PyModule_GetFilename(mod); + PyObject *mod_file = PyModule_GetFilenameObject(mod); + if (mod_file) { + *filename = _PyUnicode_AsString(mod_name); + Py_DECREF(mod_file); + } + else { + PyErr_Clear(); + } } /* unlikely, fallback */ @@ -1108,3 +1115,101 @@ bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_val } #endif /* #ifndef MATH_STANDALONE */ + +/* -------------------------------------------------------------------- */ + +/** \name Int Conversion + * + * \note Python doesn't provide overflow checks for specific bit-widths. + * + * \{ */ + +/* Compiler optimizes out redundant checks. */ +#ifdef __GNUC__ +# pragma warning(push) +# pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +/** + * Don't use `bool` return type, so -1 can be used as an error value. + */ +int PyC_Long_AsBool(PyObject *value) +{ + int test = _PyLong_AsInt(value); + if (UNLIKELY((uint)test > 1)) { + PyErr_SetString(PyExc_TypeError, + "Python number not a bool (0/1)"); + return -1; + } + return test; +} + +int8_t PyC_Long_AsI8(PyObject *value) +{ + int test = _PyLong_AsInt(value); + if (UNLIKELY(test < INT8_MIN || test > INT8_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C int8"); + return -1; + } + return (int8_t)test; +} + +int16_t PyC_Long_AsI16(PyObject *value) +{ + int test = _PyLong_AsInt(value); + if (UNLIKELY(test < INT16_MIN || test > INT16_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C int16"); + return -1; + } + return (int16_t)test; +} + +/* Inlined in header: + * PyC_Long_AsI32 + * PyC_Long_AsI64 + */ + +uint8_t PyC_Long_AsU8(PyObject *value) +{ + ulong test = PyLong_AsUnsignedLong(value); + if (UNLIKELY(test > UINT8_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C uint8"); + return (uint8_t)-1; + } + return (uint8_t)test; +} + +uint16_t PyC_Long_AsU16(PyObject *value) +{ + ulong test = PyLong_AsUnsignedLong(value); + if (UNLIKELY(test > UINT16_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C uint16"); + return (uint16_t)-1; + } + return (uint16_t)test; +} + +uint32_t PyC_Long_AsU32(PyObject *value) +{ + ulong test = PyLong_AsUnsignedLong(value); + if (UNLIKELY(test > UINT32_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C uint32"); + return (uint32_t)-1; + } + return (uint32_t)test; +} + +/* Inlined in header: + * PyC_Long_AsU64 + */ + +#ifdef __GNUC__ +# pragma warning(pop) +#endif + +/** \} */ diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index 3f89e1d82a0..327d4e60954 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -24,10 +24,12 @@ * \ingroup pygen */ - #ifndef __PY_CAPI_UTILS_H__ #define __PY_CAPI_UTILS_H__ +#include "BLI_sys_types.h" +#include "BLI_utildefines_variadic.h" + void PyC_ObSpit(const char *name, PyObject *var); void PyC_LineSpit(void); void PyC_StackSpit(void); @@ -44,8 +46,21 @@ int PyC_AsArray_FAST( int PyC_AsArray( void *array, PyObject *value, const Py_ssize_t length, const PyTypeObject *type, const bool is_double, const char *error_prefix); -PyObject * PyC_FromArray(const void *array, int length, const PyTypeObject *type, - const bool is_double, const char *error_prefix); + +PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len); +PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len); +PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len); +PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len); + +#define PyC_Tuple_Pack_F32(...) \ + PyC_Tuple_PackArray_F32(((const float []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define PyC_Tuple_Pack_I32(...) \ + PyC_Tuple_PackArray_I32(((const int []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define PyC_Tuple_Pack_I32FromBool(...) \ + PyC_Tuple_PackArray_I32FromBool(((const int []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define PyC_Tuple_Pack_Bool(...) \ + PyC_Tuple_PackArray_Bool(((const bool []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) + void PyC_Tuple_Fill(PyObject *tuple, PyObject *value); void PyC_List_Fill(PyObject *list, PyObject *value); @@ -85,4 +100,26 @@ bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_val int PyC_ParseBool(PyObject *o, void *p); + +/* Integer parsing (with overflow checks), -1 on error. */ +int PyC_Long_AsBool(PyObject *value); +int8_t PyC_Long_AsI8(PyObject *value); +int16_t PyC_Long_AsI16(PyObject *value); +#if 0 /* inline */ +int32_t PyC_Long_AsI32(PyObject *value); +int64_t PyC_Long_AsI64(PyObject *value); +#endif + +uint8_t PyC_Long_AsU8(PyObject *value); +uint16_t PyC_Long_AsU16(PyObject *value); +uint32_t PyC_Long_AsU32(PyObject *value); +#if 0 /* inline */ +uint64_t PyC_Long_AsU64(PyObject *value); +#endif + +/* inline so type signatures match as expected */ +Py_LOCAL_INLINE(int32_t) PyC_Long_AsI32(PyObject *value) { return (int32_t)_PyLong_AsInt(value); } +Py_LOCAL_INLINE(int64_t) PyC_Long_AsI64(PyObject *value) { return (int64_t)PyLong_AsLongLong(value); } +Py_LOCAL_INLINE(uint64_t) PyC_Long_AsU64(PyObject *value) { return (uint64_t)PyLong_AsUnsignedLongLong(value); } + #endif /* __PY_CAPI_UTILS_H__ */ diff --git a/source/blender/python/generic/python_utildefines.h b/source/blender/python/generic/python_utildefines.h index f7d3e7a8b4a..2d2d19c05f5 100644 --- a/source/blender/python/generic/python_utildefines.h +++ b/source/blender/python/generic/python_utildefines.h @@ -36,16 +36,16 @@ extern "C" { PyTupleObject *op = (PyTupleObject *)op_arg; \ PyObject **ob_items = op->ob_item; \ CHECK_TYPE_ANY(op_arg, PyObject *, PyTupleObject *); \ - BLI_assert(_VA_NARGS_COUNT(__VA_ARGS__) == PyTuple_GET_SIZE(op)); \ + BLI_assert(VA_NARGS_COUNT(__VA_ARGS__) == PyTuple_GET_SIZE(op)); \ ARRAY_SET_ITEMS(ob_items, __VA_ARGS__); \ } (void)0 /* wrap Py_INCREF & return the result, * use sparingly to avoid comma operator or temp var assignment */ -BLI_INLINE PyObject *Py_INCREF_RET(PyObject *op) { Py_INCREF(op); return op; } +Py_LOCAL_INLINE(PyObject *)Py_INCREF_RET(PyObject *op) { Py_INCREF(op); return op; } /* append & transfer ownership to the list, avoids inline Py_DECREF all over (which is quite a large macro) */ -BLI_INLINE int PyList_APPEND(PyObject *op, PyObject *v) +Py_LOCAL_INLINE(int) PyList_APPEND(PyObject *op, PyObject *v) { int ret = PyList_Append(op, v); Py_DecRef(v); diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index be4db6477fe..dd84ce0ebe1 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -147,10 +147,6 @@ if(WITH_CODEC_FFMPEG) add_definitions(-DWITH_FFMPEG) endif() -if(WITH_CODEC_QUICKTIME) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_CODEC_SNDFILE) add_definitions(-DWITH_SNDFILE) endif() diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index 8b3464173d2..f44401afd7d 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -89,6 +89,7 @@ static PyStructSequence_Field app_info_fields[] = { {(char *)"version_cycle", (char *)"The release status of this build alpha/beta/rc/release"}, {(char *)"binary_path", (char *)"The location of blenders executable, useful for utilities that spawn new instances"}, {(char *)"background", (char *)"Boolean, True when blender is running without a user interface (started with -b)"}, + {(char *)"factory_startup", (char *)"Boolean, True when blender is running with --factory-startup)"}, /* buildinfo */ {(char *)"build_date", (char *)"The date this blender instance was built"}, @@ -156,8 +157,7 @@ static PyObject *make_app_info(void) #define SetObjItem(obj) \ PyStructSequence_SET_ITEM(app_info, pos++, obj) - SetObjItem(Py_BuildValue("(iii)", - BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); + SetObjItem(PyC_Tuple_Pack_I32(BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); SetObjItem(PyUnicode_FromFormat("%d.%02d (sub %d)", BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); @@ -165,6 +165,7 @@ static PyObject *make_app_info(void) SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE)); SetStrItem(BKE_appdir_program_path()); SetObjItem(PyBool_FromLong(G.background)); + SetObjItem(PyBool_FromLong(G.factory_startup)); /* build info, use bytes since we can't assume _any_ encoding: * see patch [#30154] for issue */ @@ -290,7 +291,7 @@ static PyObject *bpy_app_debug_value_get(PyObject *UNUSED(self), void *UNUSED(cl static int bpy_app_debug_value_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure)) { - int param = PyLong_AsLong(value); + int param = PyC_Long_AsI32(value); if (param == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "bpy.app.debug_value can only be set to a whole number"); diff --git a/source/blender/python/intern/bpy_app_alembic.c b/source/blender/python/intern/bpy_app_alembic.c index 90e6a02b418..2a1a031a629 100644 --- a/source/blender/python/intern/bpy_app_alembic.c +++ b/source/blender/python/intern/bpy_app_alembic.c @@ -34,6 +34,8 @@ #include "bpy_app_alembic.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_ALEMBIC # include "ABC_alembic.h" #endif @@ -79,11 +81,11 @@ static PyObject *make_alembic_info(void) const int patch = curversion - ((curversion / 100 ) * 100); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", major, minor, patch)); + SetObjItem(PyC_Tuple_Pack_I32(major, minor, patch)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", major, minor, patch)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c index a6b98567a9a..501e09dd6ad 100644 --- a/source/blender/python/intern/bpy_app_build_options.c +++ b/source/blender/python/intern/bpy_app_build_options.c @@ -37,7 +37,6 @@ static PyStructSequence_Field app_builtopts_info_fields[] = { {(char *)"bullet", NULL}, {(char *)"codec_avi", NULL}, {(char *)"codec_ffmpeg", NULL}, - {(char *)"codec_quicktime", NULL}, {(char *)"codec_sndfile", NULL}, {(char *)"compositor", NULL}, {(char *)"cycles", NULL}, @@ -112,12 +111,6 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif -#ifdef WITH_QUICKTIME - SetObjIncref(Py_True); -#else - SetObjIncref(Py_False); -#endif - #ifdef WITH_SNDFILE SetObjIncref(Py_True); #else diff --git a/source/blender/python/intern/bpy_app_ffmpeg.c b/source/blender/python/intern/bpy_app_ffmpeg.c index fd516e4547f..9f8355db72b 100644 --- a/source/blender/python/intern/bpy_app_ffmpeg.c +++ b/source/blender/python/intern/bpy_app_ffmpeg.c @@ -29,6 +29,8 @@ #include "bpy_app_ffmpeg.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_FFMPEG #include <libavcodec/avcodec.h> #include <libavdevice/avdevice.h> @@ -91,8 +93,7 @@ static PyObject *make_ffmpeg_info(void) #ifdef WITH_FFMPEG # define FFMPEG_LIB_VERSION(lib) { \ curversion = lib ## _version(); \ - SetObjItem(Py_BuildValue("(iii)", \ - curversion >> 16, (curversion >> 8) % 256, curversion % 256)); \ + SetObjItem(PyC_Tuple_Pack_I32(curversion >> 16, (curversion >> 8) % 256, curversion % 256)); \ SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", \ curversion >> 16, (curversion >> 8) % 256, curversion % 256)); \ } (void)0 diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index fdc2371c259..90aa22de5bf 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -59,8 +59,12 @@ static PyStructSequence_Field app_cb_info_fields[] = { {(char *)"load_post", (char *)"on loading a new blend file (after)"}, {(char *)"save_pre", (char *)"on saving a blend file (before)"}, {(char *)"save_post", (char *)"on saving a blend file (after)"}, - {(char *)"scene_update_pre", (char *)"on updating the scenes data (before)"}, - {(char *)"scene_update_post", (char *)"on updating the scenes data (after)"}, + {(char *)"scene_update_pre", (char *)"on every scene data update. Does not imply that anything changed in the " + "scene, just that the dependency graph is about to be reevaluated, and the " + "scene is about to be updated by Blender's animation system."}, + {(char *)"scene_update_post", (char *)"on every scene data update. Does not imply that anything changed in the " + "scene, just that the dependency graph was reevaluated, and the scene was " + "possibly updated by Blender's animation system."}, {(char *)"game_pre", (char *)"on starting the game engine"}, {(char *)"game_post", (char *)"on ending the game engine"}, {(char *)"version_update", (char *)"on ending the versioning code"}, diff --git a/source/blender/python/intern/bpy_app_ocio.c b/source/blender/python/intern/bpy_app_ocio.c index 02e4044219a..9997e6b87f1 100644 --- a/source/blender/python/intern/bpy_app_ocio.c +++ b/source/blender/python/intern/bpy_app_ocio.c @@ -29,6 +29,8 @@ #include "bpy_app_ocio.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_OCIO # include "ocio_capi.h" #endif @@ -74,13 +76,12 @@ static PyObject *make_ocio_info(void) #ifdef WITH_OCIO curversion = OCIO_getVersionHex(); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", - curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); + SetObjItem(PyC_Tuple_Pack_I32(curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_oiio.c b/source/blender/python/intern/bpy_app_oiio.c index 60daf3ddd8b..e14b48ff7cf 100644 --- a/source/blender/python/intern/bpy_app_oiio.c +++ b/source/blender/python/intern/bpy_app_oiio.c @@ -29,6 +29,8 @@ #include "bpy_app_oiio.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_OPENIMAGEIO # include "openimageio_api.h" #endif @@ -74,13 +76,12 @@ static PyObject *make_oiio_info(void) #ifdef WITH_OPENIMAGEIO curversion = OIIO_getVersionHex(); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", - curversion / 10000, (curversion / 100) % 100, curversion % 100)); + SetObjItem(PyC_Tuple_Pack_I32(curversion / 10000, (curversion / 100) % 100, curversion % 100)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", curversion / 10000, (curversion / 100) % 100, curversion % 100)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_opensubdiv.c b/source/blender/python/intern/bpy_app_opensubdiv.c index 7f269baf2b0..096374794c9 100644 --- a/source/blender/python/intern/bpy_app_opensubdiv.c +++ b/source/blender/python/intern/bpy_app_opensubdiv.c @@ -29,6 +29,8 @@ #include "bpy_app_opensubdiv.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_OPENSUBDIV # include "opensubdiv_capi.h" #endif @@ -70,13 +72,12 @@ static PyObject *make_opensubdiv_info(void) #ifdef WITH_OPENSUBDIV int curversion = openSubdiv_getVersionHex(); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", - curversion / 10000, (curversion / 100) % 100, curversion % 100)); + SetObjItem(PyC_Tuple_Pack_I32(curversion / 10000, (curversion / 100) % 100, curversion % 100)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", curversion / 10000, (curversion / 100) % 100, curversion % 100)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_openvdb.c b/source/blender/python/intern/bpy_app_openvdb.c index 8a24aaf0555..0b385206d7b 100644 --- a/source/blender/python/intern/bpy_app_openvdb.c +++ b/source/blender/python/intern/bpy_app_openvdb.c @@ -34,6 +34,8 @@ #include "bpy_app_openvdb.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_OPENVDB # include "openvdb_capi.h" #endif @@ -79,13 +81,12 @@ static PyObject *make_openvdb_info(void) #ifdef WITH_OPENVDB curversion = OpenVDB_getVersionHex(); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", - curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); + SetObjItem(PyC_Tuple_Pack_I32(curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_sdl.c b/source/blender/python/intern/bpy_app_sdl.c index 76dab775953..816ad2833cc 100644 --- a/source/blender/python/intern/bpy_app_sdl.c +++ b/source/blender/python/intern/bpy_app_sdl.c @@ -29,6 +29,8 @@ #include "bpy_app_sdl.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_SDL /* SDL force defines __SSE__ and __SSE2__ flags, which generates warnings * because we pass those defines via command line as well. For until there's @@ -103,7 +105,7 @@ static PyObject *make_sdl_info(void) # endif # endif - SetObjItem(Py_BuildValue("(iii)", version.major, version.minor, version.patch)); + SetObjItem(PyC_Tuple_Pack_I32(version.major, version.minor, version.patch)); if (sdl_available) { SetObjItem(PyUnicode_FromFormat("%d.%d.%d", version.major, version.minor, version.patch)); } @@ -114,7 +116,7 @@ static PyObject *make_sdl_info(void) #else // WITH_SDL=OFF SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); SetObjItem(PyBool_FromLong(0)); #endif diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 7b0daa91523..20cfd364a0c 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -869,6 +869,7 @@ static void bpy_module_delay_init(PyObject *bpy_proxy) BLI_strncpy(filename_abs, filename_rel, sizeof(filename_abs)); BLI_path_cwd(filename_abs, sizeof(filename_abs)); + Py_DECREF(filename_obj); argv[0] = filename_abs; argv[1] = NULL; diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 15f3c665fcf..cb6a7147368 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -73,7 +73,7 @@ typedef struct { } BPy_Library; static PyObject *bpy_lib_load(PyObject *self, PyObject *args, PyObject *kwds); -static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *args); +static PyObject *bpy_lib_enter(BPy_Library *self); static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *args); static PyObject *bpy_lib_dir(BPy_Library *self); @@ -237,7 +237,7 @@ static PyObject *_bpy_names(BPy_Library *self, int blocktype) return list; } -static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args)) +static PyObject *bpy_lib_enter(BPy_Library *self) { PyObject *ret; BPy_Library *self_from; diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 90719905a79..9d57adca946 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -48,10 +48,12 @@ static void operator_properties_init(wmOperatorType *ot) PyTypeObject *py_class = ot->ext.data; RNA_struct_blender_type_set(ot->ext.srna, ot); - /* only call this so pyrna_deferred_register_class gives a useful error - * WM_operatortype_append_ptr will call RNA_def_struct_identifier - * later */ - RNA_def_struct_identifier(ot->srna, ot->idname); + /* Only call this so pyrna_deferred_register_class gives a useful error + * WM_operatortype_append_ptr will call RNA_def_struct_identifier later. + * + * Note the 'no_struct_map' function is used since the actual struct name is already used by the operator. + */ + RNA_def_struct_identifier_no_struct_map(ot->srna, ot->idname); if (pyrna_deferred_register_class(ot->srna, py_class) != 0) { PyErr_Print(); /* failed to register operator props */ diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index c7787ba9682..9ef8f9aa046 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -320,7 +320,7 @@ static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p value = false; } else { - value = PyLong_AsLong(ret); + value = PyC_Long_AsI32(ret); if (value == -1 && PyErr_Occurred()) { printf_func_error(py_func); @@ -530,12 +530,8 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct Propert self = pyrna_struct_as_instance(ptr); PyTuple_SET_ITEM(args, 0, self); - py_values = PyC_FromArray(values, len, &PyBool_Type, false, "BoolVectorProperty set"); - if (!py_values) { - printf_func_error(py_func); - } - else - PyTuple_SET_ITEM(args, 1, py_values); + py_values = PyC_Tuple_PackArray_I32FromBool(values, len); + PyTuple_SET_ITEM(args, 1, py_values); ret = PyObject_CallObject(py_func, args); @@ -599,7 +595,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop) value = 0.0f; } else { - value = PyLong_AsLong(ret); + value = PyC_Long_AsI32(ret); if (value == -1 && PyErr_Occurred()) { printf_func_error(py_func); @@ -764,12 +760,8 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA self = pyrna_struct_as_instance(ptr); PyTuple_SET_ITEM(args, 0, self); - py_values = PyC_FromArray(values, len, &PyLong_Type, false, "IntVectorProperty set"); - if (!py_values) { - printf_func_error(py_func); - } - else - PyTuple_SET_ITEM(args, 1, py_values); + py_values = PyC_Tuple_PackArray_I32(values, len); + PyTuple_SET_ITEM(args, 1, py_values); ret = PyObject_CallObject(py_func, args); @@ -998,12 +990,8 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyR self = pyrna_struct_as_instance(ptr); PyTuple_SET_ITEM(args, 0, self); - py_values = PyC_FromArray(values, len, &PyFloat_Type, false, "FloatVectorProperty set"); - if (!py_values) { - printf_func_error(py_func); - } - else - PyTuple_SET_ITEM(args, 1, py_values); + py_values = PyC_Tuple_PackArray_F32(values, len); + PyTuple_SET_ITEM(args, 1, py_values); ret = PyObject_CallObject(py_func, args); @@ -1249,7 +1237,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop value = RNA_property_enum_get_default(ptr, prop); } else { - value = PyLong_AsLong(ret); + value = PyC_Long_AsI32(ret); if (value == -1 && PyErr_Occurred()) { printf_func_error(py_func); @@ -2697,7 +2685,8 @@ PyDoc_STRVAR(BPy_EnumProperty_doc, " :icon: An icon string identifier or integer icon value\n" " (e.g. returned by :class:`bpy.types.UILayout.icon`)\n" " :number: Unique value used as the identifier for this item (stored in file data).\n" -" Use when the identifier may need to change.\n" +" Use when the identifier may need to change. If the *ENUM_FLAG* option is used,\n" +" the values are bitmasks and should be powers of two.\n" "\n" " When an item only contains 4 items they define ``(identifier, name, description, number)``.\n" "\n" @@ -2891,7 +2880,7 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) PyObject *update_cb = NULL, *poll_cb = NULL; if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#O|ssO!OOO:PointerProperty", + "s#O|ssO!OO:PointerProperty", (char **)kwlist, &id, &id_len, &type, &name, &description, &PySet_Type, &pyopts, diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index eda880d4dce..398d2631f6c 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -70,6 +70,8 @@ #include "BKE_report.h" #include "BKE_idprop.h" +/* only for types */ +#include "BKE_node.h" #include "../generic/idprop_py_api.h" /* for IDprop lookups */ #include "../generic/py_capi_utils.h" @@ -1395,7 +1397,7 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val) } else { EnumPropertyItem *enum_item; - bool free = false; + bool free; /* don't throw error here, can't trust blender 100% to give the * right values, python code should not generate error for that */ @@ -1404,6 +1406,9 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val) ret = PyUnicode_FromString(enum_item->identifier); } else { + if (free) { + MEM_freeN(enum_item); + } RNA_property_enum_items(NULL, ptr, prop, &enum_item, NULL, &free); /* Do not print warning in case of DummyRNA_NULL_items, this one will never match any value... */ @@ -1640,7 +1645,7 @@ static int pyrna_py_to_prop( param = PyObject_IsTrue(value); } else { - param = PyLong_AsLong(value); + param = PyC_Long_AsI32(value); if (UNLIKELY(param & ~1)) { /* only accept 0/1 */ param = -1; /* error out below */ @@ -2076,10 +2081,10 @@ static int pyrna_py_to_prop_array_index(BPy_PropertyArrayRNA *self, int index, P switch (RNA_property_type(prop)) { case PROP_BOOLEAN: { - int param = PyLong_AsLong(value); + int param = PyC_Long_AsBool(value); - if (param < 0 || param > 1) { - PyErr_SetString(PyExc_TypeError, "expected True/False or 0/1"); + if (param == -1) { + /* error is set */ ret = -1; } else { @@ -2089,7 +2094,7 @@ static int pyrna_py_to_prop_array_index(BPy_PropertyArrayRNA *self, int index, P } case PROP_INT: { - int param = PyLong_AsLong(value); + int param = PyC_Long_AsI32(value); if (param == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "expected an int type"); ret = -1; @@ -2709,7 +2714,7 @@ static PyObject *pyrna_prop_array_subscript(BPy_PropertyArrayRNA *self, PyObject Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; - return pyrna_prop_array_subscript_int(self, PyLong_AsLong(key)); + return pyrna_prop_array_subscript_int(self, i); } else if (PySlice_Check(key)) { Py_ssize_t step = 1; @@ -3704,6 +3709,110 @@ static PyObject *pyrna_struct_type_recast(BPy_StructRNA *self) return pyrna_struct_CreatePyObject(&r_ptr); } +/** + * \note Return value is borrowed, caller must incref. + */ +static PyObject *pyrna_struct_bl_rna_find_subclass_recursive(PyObject *cls, const char *id) +{ + PyObject *ret_test = NULL; + PyObject *subclasses = ((PyTypeObject *)cls)->tp_subclasses; + if (subclasses) { + /* Unfortunately we can't use the dict key because Python class names + * don't match the bl_idname used internally. */ + BLI_assert(PyDict_CheckExact(subclasses)); + PyObject *key = NULL; + Py_ssize_t pos = 0; + PyObject *value = NULL; + while (PyDict_Next(subclasses, &pos, &key, &value)) { + BLI_assert(PyWeakref_CheckRef(value)); + PyObject *subcls = PyWeakref_GET_OBJECT(value); + if (subcls != Py_None) { + BPy_StructRNA *py_srna = (BPy_StructRNA *)PyDict_GetItem( + ((PyTypeObject *)subcls)->tp_dict, bpy_intern_str_bl_rna); + if (py_srna) { + StructRNA *srna = py_srna->ptr.data; + if (STREQ(id, RNA_struct_identifier(srna))) { + ret_test = subcls; + break; + } + } + ret_test = pyrna_struct_bl_rna_find_subclass_recursive(subcls, id); + if (ret_test) { + break; + } + } + } + } + return ret_test; +} + +PyDoc_STRVAR(pyrna_struct_bl_rna_get_subclass_py_doc, +".. classmethod:: bl_rna_get_subclass_py(id, default=None)\n" +"\n" +" :arg id: The RNA type identifier.\n" +" :type id: string\n" +" :return: The class or default when not found.\n" +" :rtype: type\n" +); +static PyObject *pyrna_struct_bl_rna_get_subclass_py(PyObject *cls, PyObject *args) +{ + char *id; + PyObject *ret_default = Py_None; + + if (!PyArg_ParseTuple(args, "s|O:bl_rna_get_subclass_py", &id, &ret_default)) { + return NULL; + } + PyObject *ret = pyrna_struct_bl_rna_find_subclass_recursive(cls, id); + if (ret == NULL) { + ret = ret_default; + } + return Py_INCREF_RET(ret); +} + +PyDoc_STRVAR(pyrna_struct_bl_rna_get_subclass_doc, +".. classmethod:: bl_rna_get_subclass(id, default=None)\n" +"\n" +" :arg id: The RNA type identifier.\n" +" :type id: string\n" +" :return: The RNA type or default when not found.\n" +" :rtype: :class:`bpy.types.Struct` subclass\n" +); +static PyObject *pyrna_struct_bl_rna_get_subclass(PyObject *cls, PyObject *args) +{ + char *id; + PyObject *ret_default = Py_None; + + if (!PyArg_ParseTuple(args, "s|O:bl_rna_get_subclass", &id, &ret_default)) { + return NULL; + } + + + const BPy_StructRNA *py_srna = (BPy_StructRNA *)PyDict_GetItem(((PyTypeObject *)cls)->tp_dict, bpy_intern_str_bl_rna); + if (py_srna == NULL) { + PyErr_SetString(PyExc_ValueError, "Not a registered class"); + return NULL; + + } + const StructRNA *srna_base = py_srna->ptr.data; + + PointerRNA ptr; + if (srna_base == &RNA_Node) { + bNodeType *nt = nodeTypeFind(id); + if (nt) { + RNA_pointer_create(NULL, &RNA_Struct, nt->ext.srna, &ptr); + return pyrna_struct_CreatePyObject(&ptr); + } + } + else { + /* TODO, panels, menus etc. */ + PyErr_Format(PyExc_ValueError, "Class type \"%.200s\" not supported", + RNA_struct_identifier(srna_base)); + return NULL; + } + + return Py_INCREF_RET(ret_default); +} + static void pyrna_dir_members_py__add_keys(PyObject *list, PyObject *dict) { PyObject *list_tmp; @@ -5002,6 +5111,8 @@ static struct PyMethodDef pyrna_struct_methods[] = { {"path_resolve", (PyCFunction)pyrna_struct_path_resolve, METH_VARARGS, pyrna_struct_path_resolve_doc}, {"path_from_id", (PyCFunction)pyrna_struct_path_from_id, METH_VARARGS, pyrna_struct_path_from_id_doc}, {"type_recast", (PyCFunction)pyrna_struct_type_recast, METH_NOARGS, pyrna_struct_type_recast_doc}, + {"bl_rna_get_subclass_py", (PyCFunction) pyrna_struct_bl_rna_get_subclass_py, METH_VARARGS | METH_CLASS, pyrna_struct_bl_rna_get_subclass_py_doc}, + {"bl_rna_get_subclass", (PyCFunction) pyrna_struct_bl_rna_get_subclass, METH_VARARGS | METH_CLASS, pyrna_struct_bl_rna_get_subclass_doc}, {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL}, /* experimental */ @@ -6924,15 +7035,7 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self) RNA_PROP_BEGIN (&self->ptr, itemptr, self->prop) { StructRNA *srna = itemptr.data; - StructRNA *srna_base = RNA_struct_base(itemptr.data); - /* skip own operators, these double up [#29666] */ - if (srna_base == &RNA_Operator) { - /* do nothing */ - } - else { - /* add to python list */ - PyList_APPEND(ret, PyUnicode_FromString(RNA_struct_identifier(srna))); - } + PyList_APPEND(ret, PyUnicode_FromString(RNA_struct_identifier(srna))); } RNA_PROP_END; diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c index 38931cd85de..3e147d29c90 100644 --- a/source/blender/python/intern/bpy_rna_array.c +++ b/source/blender/python/intern/bpy_rna_array.c @@ -38,6 +38,8 @@ #include "RNA_access.h" +#include "../generic/py_capi_utils.h" + #define USE_MATHUTILS #ifdef USE_MATHUTILS @@ -550,7 +552,7 @@ static void py_to_float(const struct ItemConvertArgData *arg, PyObject *py, char static void py_to_int(const struct ItemConvertArgData *arg, PyObject *py, char *data) { const int *range = arg->int_data.range; - int value = (int)PyLong_AsLong(py); + int value = PyC_Long_AsI32(py); CLAMP(value, range[0], range[1]); *(int *)data = value; } diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c index b4c0de51c04..1135ba121e3 100644 --- a/source/blender/python/intern/bpy_rna_driver.c +++ b/source/blender/python/intern/bpy_rna_driver.c @@ -63,7 +63,15 @@ PyObject *pyrna_driver_get_variable_value( } else { /* object & property */ - driver_arg = pyrna_prop_to_py(&ptr, prop); + PropertyType type = RNA_property_type(prop); + if (type == PROP_ENUM) { + /* Note that enum's are converted to strings by default, + * we want to avoid that, see: T52213 */ + driver_arg = PyLong_FromLong(RNA_property_enum_get(&ptr, prop)); + } + else { + driver_arg = pyrna_prop_to_py(&ptr, prop); + } } } else { diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c index 7711ce18bd0..3c340d14e3f 100644 --- a/source/blender/python/intern/gpu_offscreen.c +++ b/source/blender/python/intern/gpu_offscreen.c @@ -144,36 +144,6 @@ static PyObject *pygpu_offscreen_unbind(BPy_GPUOffScreen *self, PyObject *args, Py_RETURN_NONE; } -/** - * Use with PyArg_ParseTuple's "O&" formatting. - */ -static int pygpu_offscreen_check_matrix(PyObject *o, void *p) -{ - MatrixObject **pymat_p = p; - MatrixObject *pymat = (MatrixObject *)o; - - if (!MatrixObject_Check(pymat)) { - PyErr_Format(PyExc_TypeError, - "expected a mathutils.Matrix, not a %.200s", - Py_TYPE(o)->tp_name); - return 0; - } - - if (BaseMath_ReadCallback(pymat) == -1) { - return 0; - } - - if ((pymat->num_col != 4) || - (pymat->num_row != 4)) - { - PyErr_SetString(PyExc_ValueError, "matrix must be 4x4"); - return 0; - } - - *pymat_p = pymat; - return 1; -} - PyDoc_STRVAR(pygpu_offscreen_draw_view3d_doc, "draw_view3d(scene, view3d, region, modelview_matrix, projection_matrix)\n" "\n" @@ -209,8 +179,8 @@ static PyObject *pygpu_offscreen_draw_view3d(BPy_GPUOffScreen *self, PyObject *a if (!PyArg_ParseTupleAndKeywords( args, kwds, "OOOO&O&:draw_view3d", (char **)(kwlist), &py_scene, &py_view3d, &py_region, - pygpu_offscreen_check_matrix, &py_mat_projection, - pygpu_offscreen_check_matrix, &py_mat_modelview) || + Matrix_Parse4x4, &py_mat_projection, + Matrix_Parse4x4, &py_mat_modelview) || (!(scene = PyC_RNA_AsPointer(py_scene, "Scene")) || !(v3d = PyC_RNA_AsPointer(py_view3d, "SpaceView3D")) || !(ar = PyC_RNA_AsPointer(py_region, "Region")))) diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 1afb1d7be90..96ae0a9e50f 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -554,8 +554,8 @@ char BaseMathObject_freeze_doc[] = ; PyObject *BaseMathObject_freeze(BaseMathObject *self) { - if (self->flag & BASE_MATH_FLAG_IS_WRAP) { - PyErr_SetString(PyExc_TypeError, "Cannot freeze wrapped data"); + if ((self->flag & BASE_MATH_FLAG_IS_WRAP) || (self->cb_user != NULL)) { + PyErr_SetString(PyExc_TypeError, "Cannot freeze wrapped/owned data"); return NULL; } diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h index 6ac75565c66..d1fb6dcdb82 100644 --- a/source/blender/python/mathutils/mathutils.h +++ b/source/blender/python/mathutils/mathutils.h @@ -41,9 +41,18 @@ extern char BaseMathObject_owner_doc[]; (struct_name *)((base_type ? (base_type)->tp_alloc(base_type, 0) : _PyObject_GC_New(&(root_type)))); -/* BaseMathObject.flag */ +/** BaseMathObject.flag */ enum { + /** + * Do not own the memory used in this vector, + * \note This is error prone if the memory may be freed while this vector is in use. + * Prefer using callbacks where possible, see: #Mathutils_RegisterCallback + */ BASE_MATH_FLAG_IS_WRAP = (1 << 0), + /** + * Prevent changes to the vector so it can be used as a set or dictionary key for example. + * (typical use cases for tuple). + */ BASE_MATH_FLAG_IS_FROZEN = (1 << 1), }; #define BASE_MATH_FLAG_DEFAULT 0 diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index e368e8871f3..2578b19d5ec 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -2914,6 +2914,73 @@ PyObject *Matrix_CreatePyObject_cb(PyObject *cb_user, return (PyObject *) self; } +/** + * Use with PyArg_ParseTuple's "O&" formatting. + */ +static bool Matrix_ParseCheck(MatrixObject *pymat) +{ + if (!MatrixObject_Check(pymat)) { + PyErr_Format(PyExc_TypeError, + "expected a mathutils.Matrix, not a %.200s", + Py_TYPE(pymat)->tp_name); + return 0; + } + /* sets error */ + if (BaseMath_ReadCallback(pymat) == -1) { + return 0; + } + return 1; +} + +int Matrix_ParseAny(PyObject *o, void *p) +{ + MatrixObject **pymat_p = p; + MatrixObject *pymat = (MatrixObject *)o; + + if (!Matrix_ParseCheck(pymat)) { + return 0; + } + *pymat_p = pymat; + return 1; +} + +int Matrix_Parse3x3(PyObject *o, void *p) +{ + MatrixObject **pymat_p = p; + MatrixObject *pymat = (MatrixObject *)o; + + if (!Matrix_ParseCheck(pymat)) { + return 0; + } + if ((pymat->num_col != 3) || + (pymat->num_row != 3)) + { + PyErr_SetString(PyExc_ValueError, "matrix must be 3x3"); + return 0; + } + + *pymat_p = pymat; + return 1; +} + +int Matrix_Parse4x4(PyObject *o, void *p) +{ + MatrixObject **pymat_p = p; + MatrixObject *pymat = (MatrixObject *)o; + + if (!Matrix_ParseCheck(pymat)) { + return 0; + } + if ((pymat->num_col != 4) || + (pymat->num_row != 4)) + { + PyErr_SetString(PyExc_ValueError, "matrix must be 4x4"); + return 0; + } + + *pymat_p = pymat; + return 1; +} /* ---------------------------------------------------------------------------- * special type for alternate access */ diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h index 542a0e349c7..9c84716d307 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.h +++ b/source/blender/python/mathutils/mathutils_Matrix.h @@ -77,6 +77,11 @@ PyObject *Matrix_CreatePyObject_cb( unsigned char cb_type, unsigned char cb_subtype ) ATTR_WARN_UNUSED_RESULT; +/* PyArg_ParseTuple's "O&" formatting helpers. */ +int Matrix_ParseAny(PyObject *o, void *p); +int Matrix_Parse3x3(PyObject *o, void *p); +int Matrix_Parse4x4(PyObject *o, void *p); + extern unsigned char mathutils_matrix_row_cb_index; /* default */ extern unsigned char mathutils_matrix_col_cb_index; extern unsigned char mathutils_matrix_translation_cb_index; diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index afc8a30a6b5..65450505e08 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -32,10 +32,17 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "../generic/py_capi_utils.h" + #ifndef MATH_STANDALONE # include "BLI_dynstr.h" #endif +/** + * Higher dimensions are supported, for many common operations + * (dealing with vector/matrix multiply or handling as 3D locations) + * stack memory is used with a fixed size - defined here. + */ #define MAX_DIMENSIONS 4 /* Swizzle axes get packed into a single value that is used as a closure. Each @@ -50,7 +57,8 @@ static PyObject *Vector_deepcopy(VectorObject *self, PyObject *args); static PyObject *Vector_to_tuple_ext(VectorObject *self, int ndigits); static int row_vector_multiplication(float rvec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat); -/* Supports 2D, 3D, and 4D vector objects both int and float values +/** + * Supports 2D, 3D, and 4D vector objects both int and float values * accepted. Mixed float and int values accepted. Ints are parsed to float */ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds) @@ -403,7 +411,7 @@ static PyObject *Vector_resize(VectorObject *self, PyObject *value) return NULL; } - if ((size = PyLong_AsLong(value)) == -1) { + if ((size = PyC_Long_AsI32(value)) == -1) { PyErr_SetString(PyExc_TypeError, "Vector.resize(size): " "expected size argument to be an integer"); @@ -836,9 +844,11 @@ static PyObject *Vector_orthogonal(VectorObject *self) } -/* - * Vector.reflect(mirror): return a reflected vector on the mirror normal - * vec - ((2 * DotVecs(vec, mirror)) * mirror) +/** + * Vector.reflect(mirror): return a reflected vector on the mirror normal. + * <pre> + * vec - ((2 * dot(vec, mirror)) * mirror) + * </pre> */ PyDoc_STRVAR(Vector_reflect_doc, ".. method:: reflect(mirror)\n" @@ -1644,13 +1654,16 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2) * multiplication */ -/* COLUMN VECTOR Multiplication (Matrix X Vector) +/** + * column vector multiplication (Matrix * Vector) + * <pre> * [1][4][7] [a] * [2][5][8] * [b] * [3][6][9] [c] + * </pre> * - * note: vector/matrix multiplication IS NOT COMMUTATIVE!!!! - * note: assume read callbacks have been done first. + * \note Vector/Matrix multiplication is not commutative. + * \note Assume read callbacks have been done first. */ int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat) { @@ -2199,9 +2212,67 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos return PyFloat_FromDouble(dot_vn_vn(self->vec, self->vec, self->size)); } -/* Get a new Vector according to the provided swizzle. This function has little - * error checking, as we are in control of the inputs: the closure is set by us - * in Vector_createSwizzleGetSeter. */ + +/** + * Python script used to make swizzle array: + * + * \code{.py} + * SWIZZLE_BITS_PER_AXIS = 3 + * SWIZZLE_VALID_AXIS = 0x4 + * + * axis_dict = {} + * axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3} + * axises = 'xyzw' + * while len(axises) >= 2: + * for axis_0 in axises: + * axis_0_pos = axis_pos[axis_0] + * for axis_1 in axises: + * axis_1_pos = axis_pos[axis_1] + * axis_dict[axis_0 + axis_1] = ( + * '((%s | SWIZZLE_VALID_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' % + * (axis_0_pos, axis_1_pos)) + * if len(axises) > 2: + * for axis_2 in axises: + * axis_2_pos = axis_pos[axis_2] + * axis_dict[axis_0 + axis_1 + axis_2] = ( + * '((%s | SWIZZLE_VALID_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' % + * (axis_0_pos, axis_1_pos, axis_2_pos)) + * if len(axises) > 3: + * for axis_3 in axises: + * axis_3_pos = axis_pos[axis_3] + * axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = ( + * '((%s | SWIZZLE_VALID_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ' + * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) ' % + * (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos)) + * + * axises = axises[:-1] + * + * + * items = list(axis_dict.items()) + * items.sort(key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3')) + * + * unique = set() + * for key, val in items: + * num = eval(val) + * set_str = 'Vector_swizzle_set' if (len(set(key)) == len(key)) else 'NULL' + * key_args = ', '.join(["'%s'" % c for c in key.upper()]) + * print('\t{(char *)"%s", %s(getter)Vector_swizzle_get, (setter)%s, NULL, SWIZZLE%d(%s)},' % + * (key, (' ' * (4 - len(key))), set_str, len(key), key_args)) + * unique.add(num) + * + * if len(unique) != len(items): + * print("ERROR, duplicate values found") + * \endcode + */ + +/** + * Get a new Vector according to the provided swizzle bits. + */ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure) { size_t axis_to; @@ -2232,7 +2303,8 @@ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure) return Vector_CreatePyObject(vec, axis_to, Py_TYPE(self)); } -/* Set the items of this vector using a swizzle. +/** + * Set the items of this vector using a swizzle. * - If value is a vector or list this operates like an array copy, except that * the destination is effectively re-ordered as defined by the swizzle. At * most min(len(source), len(dest)) values will be copied. @@ -2240,8 +2312,8 @@ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure) * - If an axis appears more than once in the swizzle, the final occurrence is * the one that determines its value. * - * Returns 0 on success and -1 on failure. On failure, the vector will be - * unchanged. */ + * \return 0 on success and -1 on failure. On failure, the vector will be unchanged. + */ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure) { size_t size_from; @@ -2324,19 +2396,14 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure return 0; } -/* XYZW -> 0123 */ -#define AXIS_FROM_CHAR(a) (((a) != 'W') ? ((a) - 'X') : 3) - -#define _VA_SWIZZLE_1(a) ( \ - ((AXIS_FROM_CHAR(a) | SWIZZLE_VALID_AXIS))) -#define _VA_SWIZZLE_2(a, b) (_VA_SWIZZLE_1(a) | \ - ((AXIS_FROM_CHAR(b) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS))) -#define _VA_SWIZZLE_3(a, b, c) (_VA_SWIZZLE_2(a, b) | \ - ((AXIS_FROM_CHAR(c) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))) -#define _VA_SWIZZLE_4(a, b, c, d) (_VA_SWIZZLE_3(a, b, c) | \ - ((AXIS_FROM_CHAR(d) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) +#define _SWIZZLE1(a) ((a) | SWIZZLE_VALID_AXIS) +#define _SWIZZLE2(a, b) (_SWIZZLE1(a) | (((b) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS))) +#define _SWIZZLE3(a, b, c) (_SWIZZLE2(a, b) | (((c) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))) +#define _SWIZZLE4(a, b, c, d) (_SWIZZLE3(a, b, c) | (((d) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) -#define SWIZZLE(...) SET_INT_IN_POINTER(VA_NARGS_CALL_OVERLOAD(_VA_SWIZZLE_, __VA_ARGS__)) +#define SWIZZLE2(a, b) SET_INT_IN_POINTER(_SWIZZLE2(a, b)) +#define SWIZZLE3(a, b, c) SET_INT_IN_POINTER(_SWIZZLE3(a, b, c)) +#define SWIZZLE4(a, b, c, d) SET_INT_IN_POINTER(_SWIZZLE4(a, b, c, d)) /*****************************************************************************/ /* Python attributes get/set structure: */ @@ -2353,416 +2420,366 @@ static PyGetSetDef Vector_getseters[] = { {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL}, {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL}, - /* autogenerated swizzle attrs, see python script below */ - {(char *)"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X')}, - {(char *)"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X')}, - {(char *)"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'X')}, - {(char *)"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'Y')}, - {(char *)"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'Z')}, - {(char *)"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'W')}, - {(char *)"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y')}, - {(char *)"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'X')}, - {(char *)"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'Y')}, - {(char *)"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'Z')}, - {(char *)"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'W')}, - {(char *)"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z')}, - {(char *)"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'X')}, - {(char *)"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'Y')}, - {(char *)"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'Z')}, - {(char *)"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'W')}, - {(char *)"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W')}, - {(char *)"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'X')}, - {(char *)"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'Y')}, - {(char *)"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'Z')}, - {(char *)"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'W')}, - {(char *)"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y')}, - {(char *)"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X')}, - {(char *)"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'X')}, - {(char *)"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'Y')}, - {(char *)"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'Z')}, - {(char *)"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'W')}, - {(char *)"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y')}, - {(char *)"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'X')}, - {(char *)"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'Y')}, - {(char *)"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'Z')}, - {(char *)"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'W')}, - {(char *)"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'Z')}, - {(char *)"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'X')}, - {(char *)"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'Y')}, - {(char *)"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'Z')}, - {(char *)"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'Z', 'W')}, - {(char *)"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'W')}, - {(char *)"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'X')}, - {(char *)"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'Y')}, - {(char *)"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'W', 'Z')}, - {(char *)"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'W')}, - {(char *)"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z')}, - {(char *)"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X')}, - {(char *)"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'X')}, - {(char *)"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'Y')}, - {(char *)"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'Z')}, - {(char *)"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'W')}, - {(char *)"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'Y')}, - {(char *)"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'X')}, - {(char *)"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'Y')}, - {(char *)"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'Z')}, - {(char *)"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'Y', 'W')}, - {(char *)"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z')}, - {(char *)"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'X')}, - {(char *)"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'Y')}, - {(char *)"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'Z')}, - {(char *)"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'W')}, - {(char *)"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'W')}, - {(char *)"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'X')}, - {(char *)"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'W', 'Y')}, - {(char *)"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'Z')}, - {(char *)"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'W')}, - {(char *)"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W')}, - {(char *)"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X')}, - {(char *)"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'X')}, - {(char *)"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'Y')}, - {(char *)"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'Z')}, - {(char *)"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'W')}, - {(char *)"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Y')}, - {(char *)"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'X')}, - {(char *)"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'Y')}, - {(char *)"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Y', 'Z')}, - {(char *)"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'W')}, - {(char *)"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Z')}, - {(char *)"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'X')}, - {(char *)"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Z', 'Y')}, - {(char *)"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'Z')}, - {(char *)"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'W')}, - {(char *)"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W')}, - {(char *)"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'X')}, - {(char *)"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'Y')}, - {(char *)"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'Z')}, - {(char *)"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'W')}, - {(char *)"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X')}, - {(char *)"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X')}, - {(char *)"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'X')}, - {(char *)"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'Y')}, - {(char *)"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'Z')}, - {(char *)"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'W')}, - {(char *)"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y')}, - {(char *)"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'X')}, - {(char *)"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'Y')}, - {(char *)"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'Z')}, - {(char *)"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'W')}, - {(char *)"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'Z')}, - {(char *)"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'X')}, - {(char *)"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'Y')}, - {(char *)"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'Z')}, - {(char *)"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'Z', 'W')}, - {(char *)"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'W')}, - {(char *)"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'X')}, - {(char *)"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'Y')}, - {(char *)"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'W', 'Z')}, - {(char *)"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'W')}, - {(char *)"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y')}, - {(char *)"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X')}, - {(char *)"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'X')}, - {(char *)"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'Y')}, - {(char *)"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'Z')}, - {(char *)"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'W')}, - {(char *)"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y')}, - {(char *)"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'X')}, - {(char *)"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'Y')}, - {(char *)"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'Z')}, - {(char *)"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'W')}, - {(char *)"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z')}, - {(char *)"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'X')}, - {(char *)"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'Y')}, - {(char *)"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'Z')}, - {(char *)"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'W')}, - {(char *)"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W')}, - {(char *)"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'X')}, - {(char *)"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'Y')}, - {(char *)"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'Z')}, - {(char *)"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'W')}, - {(char *)"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z')}, - {(char *)"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'X')}, - {(char *)"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'X')}, - {(char *)"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'Y')}, - {(char *)"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'Z')}, - {(char *)"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'X', 'W')}, - {(char *)"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y')}, - {(char *)"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'X')}, - {(char *)"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'Y')}, - {(char *)"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'Z')}, - {(char *)"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'W')}, - {(char *)"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z')}, - {(char *)"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'X')}, - {(char *)"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'Y')}, - {(char *)"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'Z')}, - {(char *)"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'W')}, - {(char *)"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'W')}, - {(char *)"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'W', 'X')}, - {(char *)"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'Y')}, - {(char *)"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'Z')}, - {(char *)"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'W')}, - {(char *)"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W')}, - {(char *)"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'X')}, - {(char *)"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'X')}, - {(char *)"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'Y')}, - {(char *)"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'X', 'Z')}, - {(char *)"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'W')}, - {(char *)"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y')}, - {(char *)"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'X')}, - {(char *)"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'Y')}, - {(char *)"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'Z')}, - {(char *)"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'W')}, - {(char *)"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'Z')}, - {(char *)"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'Z', 'X')}, - {(char *)"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'Y')}, - {(char *)"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'Z')}, - {(char *)"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'W')}, - {(char *)"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W')}, - {(char *)"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'X')}, - {(char *)"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'Y')}, - {(char *)"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'Z')}, - {(char *)"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'W')}, - {(char *)"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X')}, - {(char *)"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X')}, - {(char *)"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'X')}, - {(char *)"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'Y')}, - {(char *)"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'Z')}, - {(char *)"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'W')}, - {(char *)"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'Y')}, - {(char *)"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'X')}, - {(char *)"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'Y')}, - {(char *)"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'Z')}, - {(char *)"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'Y', 'W')}, - {(char *)"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z')}, - {(char *)"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'X')}, - {(char *)"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'Y')}, - {(char *)"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'Z')}, - {(char *)"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'W')}, - {(char *)"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'W')}, - {(char *)"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'X')}, - {(char *)"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'W', 'Y')}, - {(char *)"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'Z')}, - {(char *)"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'W')}, - {(char *)"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y')}, - {(char *)"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'X')}, - {(char *)"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'X')}, - {(char *)"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'Y')}, - {(char *)"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'Z')}, - {(char *)"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'X', 'W')}, - {(char *)"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y')}, - {(char *)"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'X')}, - {(char *)"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'Y')}, - {(char *)"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'Z')}, - {(char *)"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'W')}, - {(char *)"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z')}, - {(char *)"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'X')}, - {(char *)"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'Y')}, - {(char *)"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'Z')}, - {(char *)"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'W')}, - {(char *)"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'W')}, - {(char *)"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'W', 'X')}, - {(char *)"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'Y')}, - {(char *)"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'Z')}, - {(char *)"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'W')}, - {(char *)"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z')}, - {(char *)"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X')}, - {(char *)"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'X')}, - {(char *)"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'Y')}, - {(char *)"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'Z')}, - {(char *)"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'W')}, - {(char *)"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y')}, - {(char *)"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'X')}, - {(char *)"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'Y')}, - {(char *)"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'Z')}, - {(char *)"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'W')}, - {(char *)"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z')}, - {(char *)"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'X')}, - {(char *)"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'Y')}, - {(char *)"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'Z')}, - {(char *)"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'W')}, - {(char *)"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W')}, - {(char *)"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'X')}, - {(char *)"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'Y')}, - {(char *)"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'Z')}, - {(char *)"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'W')}, - {(char *)"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W')}, - {(char *)"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'X')}, - {(char *)"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'X')}, - {(char *)"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'X', 'Y')}, - {(char *)"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'Z')}, - {(char *)"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'W')}, - {(char *)"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'Y')}, - {(char *)"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'Y', 'X')}, - {(char *)"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'Y')}, - {(char *)"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'Z')}, - {(char *)"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'W')}, - {(char *)"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z')}, - {(char *)"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'X')}, - {(char *)"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'Y')}, - {(char *)"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'Z')}, - {(char *)"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'W')}, - {(char *)"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W')}, - {(char *)"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'X')}, - {(char *)"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'Y')}, - {(char *)"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'Z')}, - {(char *)"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'W')}, - {(char *)"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X')}, - {(char *)"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X')}, - {(char *)"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'X')}, - {(char *)"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'Y')}, - {(char *)"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'Z')}, - {(char *)"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'W')}, - {(char *)"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Y')}, - {(char *)"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'X')}, - {(char *)"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'Y')}, - {(char *)"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Y', 'Z')}, - {(char *)"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'W')}, - {(char *)"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Z')}, - {(char *)"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'X')}, - {(char *)"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Z', 'Y')}, - {(char *)"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'Z')}, - {(char *)"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'W')}, - {(char *)"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W')}, - {(char *)"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'X')}, - {(char *)"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'Y')}, - {(char *)"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'Z')}, - {(char *)"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'W')}, - {(char *)"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y')}, - {(char *)"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'X')}, - {(char *)"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'X')}, - {(char *)"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'Y')}, - {(char *)"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'X', 'Z')}, - {(char *)"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'W')}, - {(char *)"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y')}, - {(char *)"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'X')}, - {(char *)"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'Y')}, - {(char *)"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'Z')}, - {(char *)"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'W')}, - {(char *)"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'Z')}, - {(char *)"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'Z', 'X')}, - {(char *)"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'Y')}, - {(char *)"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'Z')}, - {(char *)"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'W')}, - {(char *)"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W')}, - {(char *)"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'X')}, - {(char *)"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'Y')}, - {(char *)"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'Z')}, - {(char *)"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'W')}, - {(char *)"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z')}, - {(char *)"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'X')}, - {(char *)"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'X')}, - {(char *)"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'X', 'Y')}, - {(char *)"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'Z')}, - {(char *)"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'W')}, - {(char *)"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'Y')}, - {(char *)"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'Y', 'X')}, - {(char *)"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'Y')}, - {(char *)"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'Z')}, - {(char *)"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'W')}, - {(char *)"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z')}, - {(char *)"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'X')}, - {(char *)"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'Y')}, - {(char *)"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'Z')}, - {(char *)"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'W')}, - {(char *)"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W')}, - {(char *)"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'X')}, - {(char *)"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'Y')}, - {(char *)"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'Z')}, - {(char *)"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'W')}, - {(char *)"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W')}, - {(char *)"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X')}, - {(char *)"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'X')}, - {(char *)"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'Y')}, - {(char *)"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'Z')}, - {(char *)"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'W')}, - {(char *)"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y')}, - {(char *)"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'X')}, - {(char *)"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'Y')}, - {(char *)"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'Z')}, - {(char *)"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'W')}, - {(char *)"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z')}, - {(char *)"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'X')}, - {(char *)"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'Y')}, - {(char *)"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'Z')}, - {(char *)"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'W')}, - {(char *)"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W')}, - {(char *)"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'X')}, - {(char *)"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'Y')}, - {(char *)"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'Z')}, - {(char *)"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'W')}, + /* autogenerated swizzle attrs, see Python script above */ + {(char *)"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(0, 0)}, + {(char *)"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 0)}, + {(char *)"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 0)}, + {(char *)"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 1)}, + {(char *)"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 2)}, + {(char *)"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 3)}, + {(char *)"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 1)}, + {(char *)"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 0)}, + {(char *)"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 1)}, + {(char *)"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 2)}, + {(char *)"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 3)}, + {(char *)"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 2)}, + {(char *)"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 0)}, + {(char *)"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 1)}, + {(char *)"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 2)}, + {(char *)"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 3)}, + {(char *)"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 3)}, + {(char *)"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 0)}, + {(char *)"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 1)}, + {(char *)"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 2)}, + {(char *)"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 3)}, + {(char *)"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 1)}, + {(char *)"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 1, 0)}, + {(char *)"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 0)}, + {(char *)"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 1)}, + {(char *)"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 2)}, + {(char *)"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 3)}, + {(char *)"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 1, 1)}, + {(char *)"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 0)}, + {(char *)"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 1)}, + {(char *)"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 2)}, + {(char *)"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 3)}, + {(char *)"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 1, 2)}, + {(char *)"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 0)}, + {(char *)"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 1)}, + {(char *)"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 2)}, + {(char *)"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 1, 2, 3)}, + {(char *)"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 1, 3)}, + {(char *)"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 0)}, + {(char *)"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 1)}, + {(char *)"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 1, 3, 2)}, + {(char *)"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 3)}, + {(char *)"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 2)}, + {(char *)"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 2, 0)}, + {(char *)"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 0)}, + {(char *)"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 1)}, + {(char *)"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 2)}, + {(char *)"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 3)}, + {(char *)"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 2, 1)}, + {(char *)"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 0)}, + {(char *)"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 1)}, + {(char *)"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 2)}, + {(char *)"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 2, 1, 3)}, + {(char *)"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 2, 2)}, + {(char *)"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 0)}, + {(char *)"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 1)}, + {(char *)"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 2)}, + {(char *)"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 3)}, + {(char *)"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 2, 3)}, + {(char *)"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 0)}, + {(char *)"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 2, 3, 1)}, + {(char *)"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 2)}, + {(char *)"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 3)}, + {(char *)"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 3)}, + {(char *)"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 3, 0)}, + {(char *)"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 0)}, + {(char *)"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 1)}, + {(char *)"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 2)}, + {(char *)"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 3)}, + {(char *)"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 3, 1)}, + {(char *)"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 0)}, + {(char *)"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 1)}, + {(char *)"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 3, 1, 2)}, + {(char *)"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 3)}, + {(char *)"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 3, 2)}, + {(char *)"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 0)}, + {(char *)"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 3, 2, 1)}, + {(char *)"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 2)}, + {(char *)"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 3)}, + {(char *)"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 3, 3)}, + {(char *)"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 0)}, + {(char *)"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 1)}, + {(char *)"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 2)}, + {(char *)"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 3)}, + {(char *)"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 0)}, + {(char *)"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 0, 0)}, + {(char *)"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 0)}, + {(char *)"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 1)}, + {(char *)"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 2)}, + {(char *)"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 3)}, + {(char *)"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 0, 1)}, + {(char *)"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 0)}, + {(char *)"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 1)}, + {(char *)"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 2)}, + {(char *)"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 3)}, + {(char *)"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 0, 2)}, + {(char *)"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 0)}, + {(char *)"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 1)}, + {(char *)"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 2)}, + {(char *)"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 0, 2, 3)}, + {(char *)"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 0, 3)}, + {(char *)"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 0)}, + {(char *)"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 1)}, + {(char *)"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 0, 3, 2)}, + {(char *)"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 3)}, + {(char *)"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(1, 1)}, + {(char *)"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 0)}, + {(char *)"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 0)}, + {(char *)"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 1)}, + {(char *)"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 2)}, + {(char *)"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 3)}, + {(char *)"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 1)}, + {(char *)"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 0)}, + {(char *)"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 1)}, + {(char *)"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 2)}, + {(char *)"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 3)}, + {(char *)"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 2)}, + {(char *)"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 0)}, + {(char *)"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 1)}, + {(char *)"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 2)}, + {(char *)"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 3)}, + {(char *)"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 3)}, + {(char *)"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 0)}, + {(char *)"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 1)}, + {(char *)"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 2)}, + {(char *)"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 3)}, + {(char *)"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 2)}, + {(char *)"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 2, 0)}, + {(char *)"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 0)}, + {(char *)"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 1)}, + {(char *)"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 2)}, + {(char *)"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 2, 0, 3)}, + {(char *)"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 2, 1)}, + {(char *)"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 0)}, + {(char *)"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 1)}, + {(char *)"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 2)}, + {(char *)"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 3)}, + {(char *)"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 2, 2)}, + {(char *)"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 0)}, + {(char *)"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 1)}, + {(char *)"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 2)}, + {(char *)"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 3)}, + {(char *)"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 2, 3)}, + {(char *)"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 2, 3, 0)}, + {(char *)"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 1)}, + {(char *)"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 2)}, + {(char *)"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 3)}, + {(char *)"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 3)}, + {(char *)"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 3, 0)}, + {(char *)"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 0)}, + {(char *)"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 1)}, + {(char *)"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 3, 0, 2)}, + {(char *)"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 3)}, + {(char *)"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 3, 1)}, + {(char *)"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 0)}, + {(char *)"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 1)}, + {(char *)"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 2)}, + {(char *)"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 3)}, + {(char *)"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 3, 2)}, + {(char *)"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 3, 2, 0)}, + {(char *)"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 1)}, + {(char *)"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 2)}, + {(char *)"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 3)}, + {(char *)"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 3, 3)}, + {(char *)"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 0)}, + {(char *)"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 1)}, + {(char *)"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 2)}, + {(char *)"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 3)}, + {(char *)"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 0)}, + {(char *)"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 0, 0)}, + {(char *)"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 0)}, + {(char *)"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 1)}, + {(char *)"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 2)}, + {(char *)"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 3)}, + {(char *)"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 0, 1)}, + {(char *)"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 0)}, + {(char *)"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 1)}, + {(char *)"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 2)}, + {(char *)"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 0, 1, 3)}, + {(char *)"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 0, 2)}, + {(char *)"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 0)}, + {(char *)"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 1)}, + {(char *)"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 2)}, + {(char *)"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 3)}, + {(char *)"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 0, 3)}, + {(char *)"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 0)}, + {(char *)"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 0, 3, 1)}, + {(char *)"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 2)}, + {(char *)"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 3)}, + {(char *)"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 1)}, + {(char *)"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 1, 0)}, + {(char *)"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 0)}, + {(char *)"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 1)}, + {(char *)"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 2)}, + {(char *)"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 1, 0, 3)}, + {(char *)"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 1, 1)}, + {(char *)"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 0)}, + {(char *)"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 1)}, + {(char *)"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 2)}, + {(char *)"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 3)}, + {(char *)"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 1, 2)}, + {(char *)"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 0)}, + {(char *)"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 1)}, + {(char *)"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 2)}, + {(char *)"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 3)}, + {(char *)"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 1, 3)}, + {(char *)"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 1, 3, 0)}, + {(char *)"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 1)}, + {(char *)"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 2)}, + {(char *)"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 3)}, + {(char *)"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(2, 2)}, + {(char *)"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 0)}, + {(char *)"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 0)}, + {(char *)"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 1)}, + {(char *)"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 2)}, + {(char *)"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 3)}, + {(char *)"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 1)}, + {(char *)"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 0)}, + {(char *)"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 1)}, + {(char *)"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 2)}, + {(char *)"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 3)}, + {(char *)"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 2)}, + {(char *)"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 0)}, + {(char *)"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 1)}, + {(char *)"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 2)}, + {(char *)"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 3)}, + {(char *)"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 3)}, + {(char *)"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 0)}, + {(char *)"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 1)}, + {(char *)"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 2)}, + {(char *)"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 3)}, + {(char *)"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 3)}, + {(char *)"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 3, 0)}, + {(char *)"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 0)}, + {(char *)"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 3, 0, 1)}, + {(char *)"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 2)}, + {(char *)"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 3)}, + {(char *)"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 3, 1)}, + {(char *)"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 3, 1, 0)}, + {(char *)"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 1)}, + {(char *)"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 2)}, + {(char *)"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 3)}, + {(char *)"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 3, 2)}, + {(char *)"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 0)}, + {(char *)"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 1)}, + {(char *)"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 2)}, + {(char *)"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 3)}, + {(char *)"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 3, 3)}, + {(char *)"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 0)}, + {(char *)"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 1)}, + {(char *)"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 2)}, + {(char *)"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 3)}, + {(char *)"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 0)}, + {(char *)"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 0, 0)}, + {(char *)"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 0)}, + {(char *)"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 1)}, + {(char *)"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 2)}, + {(char *)"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 3)}, + {(char *)"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 0, 1)}, + {(char *)"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 0)}, + {(char *)"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 1)}, + {(char *)"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 0, 1, 2)}, + {(char *)"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 3)}, + {(char *)"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 0, 2)}, + {(char *)"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 0)}, + {(char *)"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 0, 2, 1)}, + {(char *)"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 2)}, + {(char *)"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 3)}, + {(char *)"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 0, 3)}, + {(char *)"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 0)}, + {(char *)"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 1)}, + {(char *)"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 2)}, + {(char *)"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 3)}, + {(char *)"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 1)}, + {(char *)"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 1, 0)}, + {(char *)"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 0)}, + {(char *)"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 1)}, + {(char *)"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 1, 0, 2)}, + {(char *)"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 3)}, + {(char *)"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 1, 1)}, + {(char *)"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 0)}, + {(char *)"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 1)}, + {(char *)"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 2)}, + {(char *)"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 3)}, + {(char *)"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 1, 2)}, + {(char *)"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 1, 2, 0)}, + {(char *)"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 1)}, + {(char *)"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 2)}, + {(char *)"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 3)}, + {(char *)"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 1, 3)}, + {(char *)"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 0)}, + {(char *)"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 1)}, + {(char *)"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 2)}, + {(char *)"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 3)}, + {(char *)"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 2)}, + {(char *)"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 2, 0)}, + {(char *)"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 0)}, + {(char *)"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 2, 0, 1)}, + {(char *)"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 2)}, + {(char *)"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 3)}, + {(char *)"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 2, 1)}, + {(char *)"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 2, 1, 0)}, + {(char *)"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 1)}, + {(char *)"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 2)}, + {(char *)"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 3)}, + {(char *)"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 2, 2)}, + {(char *)"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 0)}, + {(char *)"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 1)}, + {(char *)"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 2)}, + {(char *)"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 3)}, + {(char *)"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 2, 3)}, + {(char *)"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 0)}, + {(char *)"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 1)}, + {(char *)"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 2)}, + {(char *)"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 3)}, + {(char *)"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(3, 3)}, + {(char *)"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 0)}, + {(char *)"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 0)}, + {(char *)"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 1)}, + {(char *)"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 2)}, + {(char *)"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 3)}, + {(char *)"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 1)}, + {(char *)"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 0)}, + {(char *)"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 1)}, + {(char *)"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 2)}, + {(char *)"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 3)}, + {(char *)"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 2)}, + {(char *)"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 0)}, + {(char *)"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 1)}, + {(char *)"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 2)}, + {(char *)"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 3)}, + {(char *)"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 3)}, + {(char *)"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 0)}, + {(char *)"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 1)}, + {(char *)"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 2)}, + {(char *)"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 3)}, #undef AXIS_FROM_CHAR -#undef SWIZZLE -#undef _VA_SWIZZLE_1 -#undef _VA_SWIZZLE_2 -#undef _VA_SWIZZLE_3 -#undef _VA_SWIZZLE_4 +#undef SWIZZLE1 +#undef SWIZZLE2 +#undef SWIZZLE3 +#undef SWIZZLE4 +#undef _SWIZZLE1 +#undef _SWIZZLE2 +#undef _SWIZZLE3 +#undef _SWIZZLE4 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; /** - * Python script used to make swizzle array: - * - * \code{.py} - * SWIZZLE_BITS_PER_AXIS = 3 - * SWIZZLE_VALID_AXIS = 0x4 - * - * axis_dict = {} - * axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3} - * axises = 'xyzw' - * while len(axises) >= 2: - * for axis_0 in axises: - * axis_0_pos = axis_pos[axis_0] - * for axis_1 in axises: - * axis_1_pos = axis_pos[axis_1] - * axis_dict[axis_0 + axis_1] = ( - * '((%s | SWIZZLE_VALID_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' % - * (axis_0_pos, axis_1_pos)) - * if len(axises) > 2: - * for axis_2 in axises: - * axis_2_pos = axis_pos[axis_2] - * axis_dict[axis_0 + axis_1 + axis_2] = ( - * '((%s | SWIZZLE_VALID_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' % - * (axis_0_pos, axis_1_pos, axis_2_pos)) - * if len(axises) > 3: - * for axis_3 in axises: - * axis_3_pos = axis_pos[axis_3] - * axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = ( - * '((%s | SWIZZLE_VALID_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ' - * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) ' % - * (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos)) - * - * axises = axises[:-1] - * - * - * items = list(axis_dict.items()) - * items.sort(key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3')) - * - * unique = set() - * for key, val in items: - * num = eval(val) - * set_str = 'Vector_swizzle_set' if (len(set(key)) == len(key)) else 'NULL' - * key_args = ', '.join(["'%s'" % c for c in key.upper()]) - * print('\t{(char *)"%s", %s(getter)Vector_swizzle_get, (setter)%s, NULL, SWIZZLE(%s)},' % - * (key, (' ' * (4 - len(key))), set_str, key_args)) - * unique.add(num) - * - * if len(unique) != len(items): - * print("ERROR, duplicate values found") - * \endcode - */ - -/* ROW VECTOR Multiplication - Vector X Matrix + * Row vector multiplication - (Vector * Matrix) + * <pre> * [x][y][z] * [1][4][7] * [2][5][8] * [3][6][9] - * vector/matrix multiplication IS NOT COMMUTATIVE!!!! */ + * </pre> + * \note vector/matrix multiplication is not commutative. + */ static int row_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat) { float vec_cpy[MAX_DIMENSIONS]; @@ -2863,10 +2880,11 @@ static struct PyMethodDef Vector_methods[] = { }; -/* Note - * Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing - * but this means for eg that - * (vec * mat) and (mat * vec) both get sent to Vector_mul and it needs to sort out the order +/** + * Note: + * #Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing + * but this means for eg that (vec * mat) and (mat * vec) + * both get sent to Vector_mul and it needs to sort out the order */ PyDoc_STRVAR(vector_doc, @@ -3010,6 +3028,11 @@ PyObject *Vector_CreatePyObject( return (PyObject *)self; } +/** + * Create a vector that wraps existing memory. + * + * \param vec: Use this vector in-place. + */ PyObject *Vector_CreatePyObject_wrap( float *vec, const int size, PyTypeObject *base_type) @@ -3036,6 +3059,10 @@ PyObject *Vector_CreatePyObject_wrap( return (PyObject *) self; } +/** + * Create a vector where the value is defined by registered callbacks, + * see: #Mathutils_RegisterCallback + */ PyObject *Vector_CreatePyObject_cb( PyObject *cb_user, int size, unsigned char cb_type, unsigned char cb_subtype) @@ -3052,6 +3079,9 @@ PyObject *Vector_CreatePyObject_cb( return (PyObject *)self; } +/** + * \param vec: Initialized vector value to use in-place, allocated with: PyMem_Malloc + */ PyObject *Vector_CreatePyObject_alloc( float *vec, const int size, PyTypeObject *base_type) diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c index 1eb8644a9a6..42771d93b4e 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.c +++ b/source/blender/python/mathutils/mathutils_bvhtree.c @@ -761,7 +761,7 @@ static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, P py_tricoords_fast_items = PySequence_Fast_ITEMS(py_tricoords_fast); for (j = 0; j < 3; j++) { - tri[j] = (unsigned int)_PyLong_AsInt(py_tricoords_fast_items[j]); + tri[j] = PyC_Long_AsU32(py_tricoords_fast_items[j]); if (UNLIKELY(tri[j] >= (unsigned int)coords_len)) { PyErr_Format(PyExc_ValueError, "%s: index %d must be less than %d", @@ -812,7 +812,7 @@ static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, P p_plink_prev = &plink->next; for (j = 0; j < py_tricoords_len; j++) { - plink->poly[j] = (unsigned int)_PyLong_AsInt(py_tricoords_fast_items[j]); + plink->poly[j] = PyC_Long_AsU32(py_tricoords_fast_items[j]); if (UNLIKELY(plink->poly[j] >= (unsigned int)coords_len)) { PyErr_Format(PyExc_ValueError, "%s: index %d must be less than %d", @@ -1156,7 +1156,6 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO /* Get data for tessellation */ { - DM_ensure_looptri(dm); lt = dm->getLoopTriArray(dm); tris_len = (unsigned int)dm->getNumLoopTri(dm); diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 868e4b38408..1dc18dbe509 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -1279,7 +1279,7 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject index = 0; dl_face = dl->index; while (index < dl->parts) { - PyList_SET_ITEM(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2])); + PyList_SET_ITEM(tri_list, index, PyC_Tuple_Pack_I32(dl_face[0], dl_face[1], dl_face[2])); dl_face += 3; index++; } diff --git a/source/blender/quicktime/apple/qtkit_export.m b/source/blender/quicktime/apple/qtkit_export.m deleted file mode 100644 index 1ac3c58f888..00000000000 --- a/source/blender/quicktime/apple/qtkit_export.m +++ /dev/null @@ -1,884 +0,0 @@ -/* - * Code to create QuickTime Movies with Blender - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * - * The Original Code is written by Rob Haarsma (phase) - * - * Contributor(s): Stefan Gartner (sgefant) - * Damien Plisson 11/2009 - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifdef WITH_QUICKTIME -#if defined(_WIN32) || defined(__APPLE__) - -#include <stdio.h> -#include <string.h> - -#include "DNA_scene_types.h" -#include "DNA_userdef_types.h" - -#ifdef WITH_AUDASPACE -# include AUD_DEVICE_H -#endif - -#include "BLI_utildefines.h" -#include "BKE_global.h" -#include "BKE_main.h" -#include "BKE_scene.h" -#include "BKE_report.h" - -#include "BLI_blenlib.h" - -#include "BLI_sys_types.h" - -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -#include "MEM_guardedalloc.h" - -#ifdef __APPLE__ -/* evil */ -#ifndef __AIFF__ -#define __AIFF__ -#endif -#import <Cocoa/Cocoa.h> -#import <QTKit/QTKit.h> -#include <AudioToolbox/AudioToolbox.h> - -#include "quicktime_import.h" -#include "quicktime_export.h" - -#endif /* __APPLE__ */ - -typedef struct QuicktimeExport { - QTMovie *movie; - - NSString *filename; - - QTTime frameDuration; - NSDictionary *frameAttributes; - - NSString *videoTempFileName; - /* Audio section */ - AUD_Device *audioInputDevice; - AudioFileID audioFile; - NSString *audioFileName; - AudioConverterRef audioConverter; - AudioBufferList audioBufferList; - AudioStreamBasicDescription audioInputFormat, audioOutputFormat; - AudioStreamPacketDescription *audioOutputPktDesc; - SInt64 audioFilePos; - char *audioInputBuffer; - char *audioOutputBuffer; - UInt32 audioCodecMaxOutputPacketSize; - UInt64 audioTotalExportedFrames, audioTotalSavedFrames; - UInt64 audioLastFrame; - SInt64 audioOutputPktPos; - -} QuicktimeExport; - -#define AUDIOOUTPUTBUFFERSIZE 65536 - -#pragma mark rna helper functions - -/* Video codec */ -static QuicktimeCodecTypeDesc qtVideoCodecList[] = { - {kRawCodecType, 1, "Uncompressed"}, - {k422YpCbCr8CodecType, 2, "Uncompressed 8-bit 4:2:2"}, - {k422YpCbCr10CodecType, 3, "Uncompressed 10-bit 4:2:2"}, - {kComponentVideoCodecType, 4, "Component Video"}, - {kPixletCodecType, 5, "Pixlet"}, - {kPNGCodecType, 6, "PNG"}, - {kJPEGCodecType, 7, "JPEG"}, - {kMotionJPEGACodecType, 8, "M-JPEG A"}, - {kMotionJPEGBCodecType, 9, "M-JPEG B"}, - {kDVCPALCodecType, 10, "DV PAL"}, - {kDVCNTSCCodecType, 11, "DV/DVCPRO NTSC"}, - {kDVCPROHD720pCodecType, 12, "DVCPRO HD 720p"}, - {kDVCPROHD1080i50CodecType, 13, "DVCPRO HD 1080i50"}, - {kDVCPROHD1080i60CodecType, 14, "DVCPRO HD 1080i60"}, - {kMPEG4VisualCodecType, 15, "MPEG4"}, - {kH263CodecType, 16, "H.263"}, - {kH264CodecType, 17, "H.264"}, - {kAnimationCodecType, 18, "Animation"}, - {0,0,NULL}}; - -static int qtVideoCodecCount = 18; - -int quicktime_get_num_videocodecs() -{ - return qtVideoCodecCount; -} - -QuicktimeCodecTypeDesc* quicktime_get_videocodecType_desc(int indexValue) -{ - if ((indexValue>=0) && (indexValue < qtVideoCodecCount)) - return &qtVideoCodecList[indexValue]; - else - return NULL; -} - -int quicktime_rnatmpvalue_from_videocodectype(int codecType) -{ - int i; - for (i = 0; i < qtVideoCodecCount; i++) { - if (qtVideoCodecList[i].codecType == codecType) - return qtVideoCodecList[i].rnatmpvalue; - } - - return 0; -} - -int quicktime_videocodecType_from_rnatmpvalue(int rnatmpvalue) -{ - int i; - for (i = 0; i < qtVideoCodecCount; i++) { - if (qtVideoCodecList[i].rnatmpvalue == rnatmpvalue) - return qtVideoCodecList[i].codecType; - } - - return 0; -} - -/* Audio codec */ -static QuicktimeCodecTypeDesc qtAudioCodecList[] = { - {0, 0, "No audio"}, - {kAudioFormatLinearPCM, 1, "LPCM"}, - {kAudioFormatAppleLossless, 2, "Apple Lossless"}, - {kAudioFormatMPEG4AAC, 3, "AAC"}, - {0,0,NULL}}; - -static int qtAudioCodecCount = 4; - -int quicktime_get_num_audiocodecs() -{ - return qtAudioCodecCount; -} - -QuicktimeCodecTypeDesc* quicktime_get_audiocodecType_desc(int indexValue) -{ - if ((indexValue>=0) && (indexValue < qtAudioCodecCount)) - return &qtAudioCodecList[indexValue]; - else - return NULL; -} - -int quicktime_rnatmpvalue_from_audiocodectype(int codecType) -{ - int i; - for (i = 0; i < qtAudioCodecCount; i++) { - if (qtAudioCodecList[i].codecType == codecType) - return qtAudioCodecList[i].rnatmpvalue; - } - - return 0; -} - -int quicktime_audiocodecType_from_rnatmpvalue(int rnatmpvalue) -{ - int i; - for (i = 0; i < qtAudioCodecCount; i++) { - if (qtAudioCodecList[i].rnatmpvalue == rnatmpvalue) - return qtAudioCodecList[i].codecType; - } - - return 0; -} - - -static NSString *stringWithCodecType(int codecType) -{ - char str[5]; - - *((int *)str) = EndianU32_NtoB(codecType); - str[4] = 0; - - return [NSString stringWithCString:str encoding:NSASCIIStringEncoding]; -} - -void makeqtstring(RenderData *rd, char *string, bool preview) -{ - int sfra, efra; - - char txt[64]; - - if (preview) { - sfra = rd->psfra; - efra = rd->pefra; - } - else { - sfra = rd->sfra; - efra = rd->efra; - } - - strcpy(string, rd->pic); - BLI_path_abs(string, G.main->name); - - BLI_make_existing_file(string); - - if (BLI_strcasecmp(string + strlen(string) - 4, ".mov")) { - sprintf(txt, "%04d-%04d.mov", (rd->sfra) , (rd->efra) ); - strcat(string, txt); - } -} - -void filepath_qt(char *string, RenderData *rd, bool preview, const char *suffix) -{ - int sfra, efra; - - if (string == NULL) return; - - if (preview) { - sfra = rd->psfra; - efra = rd->pefra; - } - else { - sfra = rd->sfra; - efra = rd->efra; - } - - strcpy(string, rd->pic); - BLI_path_abs(string, G.main->name); - - BLI_make_existing_file(string); - - if (rd->scemode & R_EXTENSION) { - if (!BLI_testextensie(string, ".mov")) { - BLI_path_frame_range(string, sfra, efra, 4); - strcat(string, ".mov"); - } - } - else { - if (BLI_path_frame_check_chars(string)) { - BLI_path_frame_range(string, sfra, efra, 4); - } - } - - BLI_path_suffix(string, FILE_MAX, suffix, ""); -} - -void *context_create_qt(void) -{ - QuicktimeExport *qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport"); - return qtexport; -} - -void context_free_qt(void *context_v) -{ - QuicktimeExport *qtexport = context_v; - if (qtexport) { - MEM_freeN(qtexport); - } -} - -#pragma mark audio export functions - -static OSStatus write_cookie(AudioConverterRef converter, AudioFileID outfile) -{ - // grab the cookie from the converter and write it to the file - UInt32 cookieSize = 0; - OSStatus err = AudioConverterGetPropertyInfo(converter, kAudioConverterCompressionMagicCookie, &cookieSize, NULL); - // if there is an error here, then the format doesn't have a cookie, so on we go - if (!err && cookieSize) { - char* cookie = malloc(cookieSize); - - err = AudioConverterGetProperty(converter, kAudioConverterCompressionMagicCookie, &cookieSize, cookie); - - if (!err) - err = AudioFileSetProperty (outfile, kAudioFilePropertyMagicCookieData, cookieSize, cookie); - // even though some formats have cookies, some files don't take them - - free(cookie); - } - return err; -} - -/* AudioConverter input stream callback */ -static OSStatus AudioConverterInputCallback(AudioConverterRef inAudioConverter, - UInt32* ioNumberDataPackets, - AudioBufferList* ioData, - AudioStreamPacketDescription** outDataPacketDescription, - void* inUserData) -{ - QuicktimeExport *qtexport = inUserData; - if (qtexport->audioTotalExportedFrames >= qtexport->audioLastFrame) { /* EOF */ - *ioNumberDataPackets = 0; - return noErr; - } - - if (qtexport->audioInputFormat.mBytesPerPacket * *ioNumberDataPackets > AUDIOOUTPUTBUFFERSIZE) - *ioNumberDataPackets = AUDIOOUTPUTBUFFERSIZE / qtexport->audioInputFormat.mBytesPerPacket; - - if ((qtexport->audioTotalExportedFrames + *ioNumberDataPackets) > qtexport->audioLastFrame) - *ioNumberDataPackets = (qtexport->audioLastFrame - qtexport->audioTotalExportedFrames) / qtexport->audioInputFormat.mFramesPerPacket; - - qtexport->audioTotalExportedFrames += *ioNumberDataPackets; - - AUD_Device_read(qtexport->audioInputDevice, (UInt8 *)qtexport->audioInputBuffer, - qtexport->audioInputFormat.mFramesPerPacket * *ioNumberDataPackets); - - ioData->mBuffers[0].mDataByteSize = qtexport->audioInputFormat.mBytesPerPacket * *ioNumberDataPackets; - ioData->mBuffers[0].mData = qtexport->audioInputBuffer; - ioData->mBuffers[0].mNumberChannels = qtexport->audioInputFormat.mChannelsPerFrame; - - return noErr; -} - - -#pragma mark export functions - -int start_qt( - void *context_v, struct Scene *scene, struct RenderData *rd, int UNUSED(rectx), int UNUSED(recty), - ReportList *reports, bool preview, const char *UNUSED(suffix)) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSError *error; - char name[1024]; - int success = 1; - OSStatus err = noErr; - int sfra, efra; - QuicktimeExport *qtexport = context_v; - - if (preview) { - sfra = rd->psfra; - efra = rd->pefra; - } - else { - sfra = rd->sfra; - efra = rd->efra; - } - - [QTMovie enterQTKitOnThread]; - - /* Check first if the QuickTime 7.2.1 initToWritableFile: method is available */ - if ([[[[QTMovie alloc] init] autorelease] respondsToSelector:@selector(initToWritableFile:error:)] != YES) { - BKE_report(reports, RPT_ERROR, "\nUnable to create quicktime movie, need Quicktime rev 7.2.1 or later"); - success = 0; - } - else { - makeqtstring(rd, name, preview); - qtexport->filename = [[NSString alloc] initWithUTF8String:name]; - qtexport->movie = nil; - qtexport->audioFile = NULL; - - if (rd->qtcodecsettings.audiocodecType) { - // generate a name for our video & audio files - /* Init audio file */ - CFURLRef outputFileURL; - char extension[32]; - AudioFileTypeID audioFileType; - - switch (rd->qtcodecsettings.audiocodecType) { - case kAudioFormatLinearPCM: - audioFileType = kAudioFileWAVEType; - strcpy(extension,".wav"); - break; - case kAudioFormatMPEG4AAC: - case kAudioFormatAppleLossless: - audioFileType = kAudioFileM4AType; - strcpy(extension, ".m4a"); - break; - default: - audioFileType = kAudioFileAIFFType; - strcpy(extension,".aiff"); - break; - } - - tmpnam(name); - strcat(name, extension); - outputFileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,(UInt8 *)name, strlen(name), false); - - if (outputFileURL) { - - qtexport->audioFileName = [[NSString alloc] initWithCString:name - encoding:[NSString defaultCStringEncoding]]; - - qtexport->audioInputFormat.mSampleRate = U.audiorate; - qtexport->audioInputFormat.mFormatID = kAudioFormatLinearPCM; - qtexport->audioInputFormat.mChannelsPerFrame = U.audiochannels; - switch (U.audioformat) { - case AUD_FORMAT_U8: - qtexport->audioInputFormat.mBitsPerChannel = 8; - qtexport->audioInputFormat.mFormatFlags = 0; - break; - case AUD_FORMAT_S24: - qtexport->audioInputFormat.mBitsPerChannel = 24; - qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - break; - case AUD_FORMAT_S32: - qtexport->audioInputFormat.mBitsPerChannel = 32; - qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - break; - case AUD_FORMAT_FLOAT32: - qtexport->audioInputFormat.mBitsPerChannel = 32; - qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; - break; - case AUD_FORMAT_FLOAT64: - qtexport->audioInputFormat.mBitsPerChannel = 64; - qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; - break; - case AUD_FORMAT_S16: - default: - qtexport->audioInputFormat.mBitsPerChannel = 16; - qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - break; - } - qtexport->audioInputFormat.mBytesPerFrame = qtexport->audioInputFormat.mChannelsPerFrame * qtexport->audioInputFormat.mBitsPerChannel / 8; - qtexport->audioInputFormat.mFramesPerPacket = 1; /*If not ==1, then need to check input callback for "rounding" issues"*/ - qtexport->audioInputFormat.mBytesPerPacket = qtexport->audioInputFormat.mBytesPerFrame; - qtexport->audioInputFormat.mFormatFlags |= kLinearPCMFormatFlagIsPacked; - - - /*Output format*/ - qtexport->audioOutputFormat.mFormatID = rd->qtcodecsettings.audiocodecType; - //TODO: set audio channels - qtexport->audioOutputFormat.mChannelsPerFrame = 2; - qtexport->audioOutputFormat.mSampleRate = rd->qtcodecsettings.audioSampleRate; - - /* Default value for compressed formats, overridden after if not the case */ - qtexport->audioOutputFormat.mFramesPerPacket = 0; - qtexport->audioOutputFormat.mBytesPerFrame = 0; - qtexport->audioOutputFormat.mBytesPerPacket = 0; - qtexport->audioOutputFormat.mBitsPerChannel = 0; - - switch (rd->qtcodecsettings.audiocodecType) { - case kAudioFormatMPEG4AAC: - qtexport->audioOutputFormat.mFormatFlags = kMPEG4Object_AAC_Main; - /* AAC codec does not handle sample rates above 48kHz, force this limit instead of getting an error afterwards */ - if (qtexport->audioOutputFormat.mSampleRate > 48000) qtexport->audioOutputFormat.mSampleRate = 48000; - break; - case kAudioFormatAppleLossless: - switch (U.audioformat) { - case AUD_FORMAT_S16: - qtexport->audioOutputFormat.mFormatFlags = kAppleLosslessFormatFlag_16BitSourceData; - break; - case AUD_FORMAT_S24: - qtexport->audioOutputFormat.mFormatFlags = kAppleLosslessFormatFlag_24BitSourceData; - break; - case AUD_FORMAT_S32: - qtexport->audioOutputFormat.mFormatFlags = kAppleLosslessFormatFlag_32BitSourceData; - break; - case AUD_FORMAT_U8: - case AUD_FORMAT_FLOAT32: - case AUD_FORMAT_FLOAT64: - default: - break; - } - break; - case kAudioFormatLinearPCM: - default: - switch (rd->qtcodecsettings.audioBitDepth) { - case AUD_FORMAT_U8: - qtexport->audioOutputFormat.mBitsPerChannel = 8; - qtexport->audioOutputFormat.mFormatFlags = 0; - break; - case AUD_FORMAT_S24: - qtexport->audioOutputFormat.mBitsPerChannel = 24; - qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - break; - case AUD_FORMAT_S32: - qtexport->audioOutputFormat.mBitsPerChannel = 32; - qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - break; - case AUD_FORMAT_FLOAT32: - qtexport->audioOutputFormat.mBitsPerChannel = 32; - qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; - break; - case AUD_FORMAT_FLOAT64: - qtexport->audioOutputFormat.mBitsPerChannel = 64; - qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; - break; - case AUD_FORMAT_S16: - default: - qtexport->audioOutputFormat.mBitsPerChannel = 16; - qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - break; - } - qtexport->audioOutputFormat.mFormatFlags |= kLinearPCMFormatFlagIsPacked; - qtexport->audioOutputFormat.mBytesPerPacket = qtexport->audioOutputFormat.mChannelsPerFrame * (qtexport->audioOutputFormat.mBitsPerChannel / 8); - qtexport->audioOutputFormat.mFramesPerPacket = 1; - qtexport->audioOutputFormat.mBytesPerFrame = qtexport->audioOutputFormat.mBytesPerPacket; - break; - } - - err = AudioFileCreateWithURL(outputFileURL, audioFileType, &qtexport->audioOutputFormat, kAudioFileFlags_EraseFile, &qtexport->audioFile); - CFRelease(outputFileURL); - - if (err) - BKE_report(reports, RPT_ERROR, "\nQuicktime: unable to create temporary audio file. Format error ?"); - else { - err = AudioConverterNew(&qtexport->audioInputFormat, &qtexport->audioOutputFormat, &qtexport->audioConverter); - if (err) { - BKE_report(reports, RPT_ERROR, "\nQuicktime: unable to initialize audio codec converter. Format error ?"); - AudioFileClose(qtexport->audioFile); - qtexport->audioFile = NULL; - [qtexport->audioFileName release]; - qtexport->audioFileName = nil; - } - else { - UInt32 prop,propSize; - /* Set up codec properties */ - if (rd->qtcodecsettings.audiocodecType == kAudioFormatMPEG4AAC) { /* Lossy compressed format */ - prop = rd->qtcodecsettings.audioBitRate; - AudioConverterSetProperty(qtexport->audioConverter, kAudioConverterEncodeBitRate, - sizeof(prop), &prop); - - if (rd->qtcodecsettings.audioCodecFlags & QTAUDIO_FLAG_CODEC_ISCBR) - prop = kAudioCodecBitRateControlMode_Constant; - else - prop = kAudioCodecBitRateControlMode_LongTermAverage; - AudioConverterSetProperty(qtexport->audioConverter, kAudioCodecPropertyBitRateControlMode, - sizeof(prop), &prop); - } - /* Conversion quality : if performance impact then offer degraded option */ - if ((rd->qtcodecsettings.audioCodecFlags & QTAUDIO_FLAG_RESAMPLE_NOHQ) == 0) { - prop = kAudioConverterSampleRateConverterComplexity_Mastering; - AudioConverterSetProperty(qtexport->audioConverter, kAudioConverterSampleRateConverterComplexity, - sizeof(prop), &prop); - - prop = kAudioConverterQuality_Max; - AudioConverterSetProperty(qtexport->audioConverter, kAudioConverterSampleRateConverterQuality, - sizeof(prop), &prop); - } - - write_cookie(qtexport->audioConverter, qtexport->audioFile); - - /* Allocate output buffer */ - if (qtexport->audioOutputFormat.mBytesPerPacket ==0) /* VBR */ - AudioConverterGetProperty(qtexport->audioConverter, kAudioConverterPropertyMaximumOutputPacketSize, - &propSize, &qtexport->audioCodecMaxOutputPacketSize); - else - qtexport->audioCodecMaxOutputPacketSize = qtexport->audioOutputFormat.mBytesPerPacket; - - qtexport->audioInputBuffer = MEM_mallocN(AUDIOOUTPUTBUFFERSIZE, "qt_audio_inputPacket"); - qtexport->audioOutputBuffer = MEM_mallocN(AUDIOOUTPUTBUFFERSIZE, "qt_audio_outputPacket"); - qtexport->audioOutputPktDesc = MEM_mallocN(sizeof(AudioStreamPacketDescription) * AUDIOOUTPUTBUFFERSIZE / qtexport->audioCodecMaxOutputPacketSize, - "qt_audio_pktdesc"); - } - } - } - - if (err == noErr) { - qtexport->videoTempFileName = [[NSString alloc] initWithCString:tmpnam(nil) - encoding:[NSString defaultCStringEncoding]]; - if (qtexport->videoTempFileName) { - qtexport->movie = [[QTMovie alloc] initToWritableFile:qtexport->videoTempFileName error:&error]; - } - - } - } - else - qtexport->movie = [[QTMovie alloc] initToWritableFile:qtexport->filename error:&error]; - - if (qtexport->movie == nil) { - BKE_report(reports, RPT_ERROR, "Unable to create quicktime movie."); - success = 0; - if (qtexport->filename) [qtexport->filename release]; - qtexport->filename = nil; - if (qtexport->audioFileName) [qtexport->audioFileName release]; - qtexport->audioFileName = nil; - if (qtexport->videoTempFileName) [qtexport->videoTempFileName release]; - qtexport->videoTempFileName = nil; - [QTMovie exitQTKitOnThread]; - } - else { - [qtexport->movie retain]; - [qtexport->movie setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute]; - [qtexport->movie setAttribute:@"Made with Blender" forKey:QTMovieCopyrightAttribute]; - - qtexport->frameDuration = QTMakeTime(rd->frs_sec_base * 1000, rd->frs_sec * 1000); - - /* specifying the codec attributes : try to retrieve them from render data first*/ - if (rd->qtcodecsettings.codecType) { - qtexport->frameAttributes = [ - NSDictionary dictionaryWithObjectsAndKeys: - stringWithCodecType(rd->qtcodecsettings.codecType), - QTAddImageCodecType, - [NSNumber numberWithLong:((rd->qtcodecsettings.codecSpatialQuality)*codecLosslessQuality)/100], - QTAddImageCodecQuality, - nil]; - } - else { - qtexport->frameAttributes = [ - NSDictionary dictionaryWithObjectsAndKeys:@"jpeg", - QTAddImageCodecType, - [NSNumber numberWithLong:codecHighQuality], - QTAddImageCodecQuality, - nil]; - } - [qtexport->frameAttributes retain]; - - if (qtexport->audioFile) { - /* Init audio input stream */ - AUD_DeviceSpecs specs; - - specs.channels = U.audiochannels; - specs.format = U.audioformat; - specs.rate = U.audiorate; - qtexport->audioInputDevice = AUD_openReadDevice(specs); - AUD_playDevice(qtexport->audioInputDevice, scene->sound_scene, sfra * rd->frs_sec_base / rd->frs_sec); - - qtexport->audioOutputPktPos = 0; - qtexport->audioTotalExportedFrames = 0; - qtexport->audioTotalSavedFrames = 0; - - qtexport->audioLastFrame = (efra - sfra) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec; - } - } - } - - [pool drain]; - - return success; -} - -int append_qt( - void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, - const char *UNUSED(suffix), ReportList *reports) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSBitmapImageRep *blBitmapFormatImage; - NSImage *frameImage; - OSStatus err = noErr; - unsigned char *from_Ptr,*to_Ptr; - int y,from_i,to_i; - QuicktimeExport *qtexport = context_v; - - /* Create bitmap image rep in blender format (32bit RGBA) */ - blBitmapFormatImage = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:rectx - pixelsHigh:recty - bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO - colorSpaceName:NSCalibratedRGBColorSpace - bitmapFormat:NSAlphaNonpremultipliedBitmapFormat - bytesPerRow:rectx*4 - bitsPerPixel:32]; - if (!blBitmapFormatImage) { - [pool drain]; - return 0; - } - - from_Ptr = (unsigned char *)pixels; - to_Ptr = (unsigned char *)[blBitmapFormatImage bitmapData]; - for (y = 0; y < recty; y++) { - to_i = (recty-y-1)*rectx; - from_i = y*rectx; - memcpy(to_Ptr+4*to_i, from_Ptr+4*from_i, 4*rectx); - } - - frameImage = [[NSImage alloc] initWithSize:NSMakeSize(rectx, recty)]; - [frameImage addRepresentation:blBitmapFormatImage]; - - /* Add the image to the movie clip */ - [qtexport->movie addImage:frameImage - forDuration:qtexport->frameDuration - withAttributes:qtexport->frameAttributes]; - - [blBitmapFormatImage release]; - [frameImage release]; - - - if (qtexport->audioFile) { - UInt32 audioPacketsConverted; - - // Upper limit on total exported audio frames for this particular video frame - const UInt64 exportedAudioFrameLimit = (frame - start_frame) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec; - - /* Append audio */ - while (qtexport->audioTotalExportedFrames < exportedAudioFrameLimit) { - - qtexport->audioBufferList.mNumberBuffers = 1; - qtexport->audioBufferList.mBuffers[0].mNumberChannels = qtexport->audioOutputFormat.mChannelsPerFrame; - qtexport->audioBufferList.mBuffers[0].mDataByteSize = AUDIOOUTPUTBUFFERSIZE; - qtexport->audioBufferList.mBuffers[0].mData = qtexport->audioOutputBuffer; - - // Convert one audio packet at a time so that enclosing while loop can - // keep audio processing in sync with video frames. - // Previously, this was set to (AUDIOOUTPUTBUFFERSIZE / qtexport->audioCodecMaxOutputPacketSize), - // however this may cause AudioConverterFillComplexBuffer to convert audio spanning multiple - // video frames, which breaks animation of audio parameters such as volume for fade-in/out. - audioPacketsConverted = 1; - - err = AudioConverterFillComplexBuffer(qtexport->audioConverter, AudioConverterInputCallback, - qtexport, &audioPacketsConverted, &qtexport->audioBufferList, qtexport->audioOutputPktDesc); - if (audioPacketsConverted) { - AudioFileWritePackets(qtexport->audioFile, false, qtexport->audioBufferList.mBuffers[0].mDataByteSize, - qtexport->audioOutputPktDesc, qtexport->audioOutputPktPos, &audioPacketsConverted, qtexport->audioOutputBuffer); - qtexport->audioOutputPktPos += audioPacketsConverted; - - if (qtexport->audioOutputFormat.mFramesPerPacket) { - // this is the common case: format has constant frames per packet - qtexport->audioTotalSavedFrames += (audioPacketsConverted * qtexport->audioOutputFormat.mFramesPerPacket); - } - else { - unsigned int i; - // if there are variable frames per packet, then we have to do this for each packeet - for (i = 0; i < audioPacketsConverted; ++i) - qtexport->audioTotalSavedFrames += qtexport->audioOutputPktDesc[i].mVariableFramesInPacket; - } - - - } - else { - //Error getting audio packets - BKE_reportf(reports, RPT_ERROR, "Unable to get further audio packets from frame %i, error = 0x%x",(int)qtexport->audioTotalExportedFrames,err); - break; - } - - } - } - [pool drain]; - - return 1; -} - - -void end_qt(void *context_v) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - QuicktimeExport *qtexport = context_v; - - if (qtexport->movie) { - - if (qtexport->audioFile) - { - NSDictionary *dict = nil; - QTMovie *audioTmpMovie = nil; - NSError *error; - NSFileManager *fileManager; - - /* Mux video and audio then save file */ - - /* Write last frames for VBR files */ - if (qtexport->audioOutputFormat.mBitsPerChannel == 0) { - OSStatus err = noErr; - AudioConverterPrimeInfo primeInfo; - UInt32 primeSize = sizeof(primeInfo); - - err = AudioConverterGetProperty(qtexport->audioConverter, kAudioConverterPrimeInfo, &primeSize, &primeInfo); - if (err == noErr) { - // there's priming to write out to the file - AudioFilePacketTableInfo pti; - pti.mPrimingFrames = primeInfo.leadingFrames; - pti.mRemainderFrames = primeInfo.trailingFrames; - pti.mNumberValidFrames = qtexport->audioTotalSavedFrames - pti.mPrimingFrames - pti.mRemainderFrames; - AudioFileSetProperty(qtexport->audioFile, kAudioFilePropertyPacketTableInfo, sizeof(pti), &pti); - } - - } - - write_cookie(qtexport->audioConverter, qtexport->audioFile); - AudioConverterDispose(qtexport->audioConverter); - AudioFileClose(qtexport->audioFile); - AUD_Device_free(qtexport->audioInputDevice); - qtexport->audioFile = NULL; - qtexport->audioInputDevice = NULL; - MEM_freeN(qtexport->audioInputBuffer); - MEM_freeN(qtexport->audioOutputBuffer); - MEM_freeN(qtexport->audioOutputPktDesc); - - /* Reopen audio file and merge it */ - audioTmpMovie = [QTMovie movieWithFile:qtexport->audioFileName error:&error]; - if (audioTmpMovie) { - NSArray *audioTracks = [audioTmpMovie tracksOfMediaType:QTMediaTypeSound]; - QTTrack *audioTrack = nil; - if ( [audioTracks count] > 0 ) { - audioTrack = [audioTracks objectAtIndex:0]; - } - - if (audioTrack) { - QTTimeRange totalRange; - totalRange.time = QTZeroTime; - totalRange.duration = [[audioTmpMovie attributeForKey:QTMovieDurationAttribute] QTTimeValue]; - - [qtexport->movie insertSegmentOfTrack:audioTrack timeRange:totalRange atTime:QTZeroTime]; - } - } - - /* Save file */ - dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] - forKey:QTMovieFlatten]; - - if (dict) { - [qtexport->movie writeToFile:qtexport->filename withAttributes:dict]; - } - - /* Delete temp files */ - fileManager = [[NSFileManager alloc] init]; - [fileManager removeItemAtPath:qtexport->audioFileName error:&error]; - [fileManager removeItemAtPath:qtexport->videoTempFileName error:&error]; - [fileManager release]; - } - else { - /* Flush update of the movie file */ - [qtexport->movie updateMovieFile]; - - [qtexport->movie invalidate]; - } - - /* Clean up movie structure */ - if (qtexport->filename) [qtexport->filename release]; - qtexport->filename = nil; - if (qtexport->audioFileName) [qtexport->audioFileName release]; - qtexport->audioFileName = nil; - if (qtexport->videoTempFileName) [qtexport->videoTempFileName release]; - qtexport->videoTempFileName = nil; - [qtexport->frameAttributes release]; - [qtexport->movie release]; - } - - [QTMovie exitQTKitOnThread]; - [pool drain]; -} - - -void free_qtcomponentdata(void) -{ -} - -void quicktime_verify_image_type(RenderData *rd, ImageFormatData *imf) -{ - if (imf->imtype == R_IMF_IMTYPE_QUICKTIME) { - if ((rd->qtcodecsettings.codecType <= 0) || - (rd->qtcodecsettings.codecSpatialQuality < 0) || - (rd->qtcodecsettings.codecSpatialQuality > 100)) - { - rd->qtcodecsettings.codecType = kJPEGCodecType; - rd->qtcodecsettings.codecSpatialQuality = (codecHighQuality * 100) / codecLosslessQuality; - } - if ((rd->qtcodecsettings.audioSampleRate < 21000) || - (rd->qtcodecsettings.audioSampleRate > 193000)) - { - rd->qtcodecsettings.audioSampleRate = 48000; - } - - if (rd->qtcodecsettings.audioBitDepth == 0) { - rd->qtcodecsettings.audioBitDepth = AUD_FORMAT_S16; - } - - if (rd->qtcodecsettings.audioBitRate == 0) { - rd->qtcodecsettings.audioBitRate = 256000; - } - } -} - -#endif /* _WIN32 || __APPLE__ */ -#endif /* WITH_QUICKTIME */ - diff --git a/source/blender/quicktime/apple/qtkit_import.m b/source/blender/quicktime/apple/qtkit_import.m deleted file mode 100644 index ba7ee0a8936..00000000000 --- a/source/blender/quicktime/apple/qtkit_import.m +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Code to use Quicktime to load images/movies as texture. - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * - * The Original Code is written by Rob Haarsma (phase) - * - * Contributor(s): Stefan Gartner (sgefant) - * Damien Plisson 11/2009 - * - * ***** END GPL LICENSE BLOCK ***** - */ -#ifdef WITH_QUICKTIME - -#include "MEM_guardedalloc.h" - -#include "IMB_anim.h" -#include "BLI_sys_types.h" -#include "BLI_utildefines.h" -#include "BKE_global.h" - -#include "BLI_dynstr.h" -#include "BLI_path_util.h" - -#import <Cocoa/Cocoa.h> -#import <QTKit/QTKit.h> - -#include "quicktime_import.h" -#include "quicktime_export.h" - -// quicktime structure definition -// this structure is part of the anim struct - -typedef struct _QuicktimeMovie { - QTMovie *movie; - QTMedia *media; - - long durationTime; - long durationScale; - long framecount; - - - ImBuf *ibuf; - - long previousPosition; - -} QuicktimeMovie; - - -#define QTIME_DEBUG 0 - - -void quicktime_init(void) -{ - G.have_quicktime = true; -} - -void quicktime_exit(void) -{ - if (G.have_quicktime) { - free_qtcomponentdata(); - } -} - - -int anim_is_quicktime(const char *name) -{ - NSAutoreleasePool *pool; - - // don't let quicktime movie import handle these - - if (BLI_testextensie_n( - name, - ".swf", - ".txt", - ".mpg", - ".vob", /* disabled, vob is essential .mpg, don't handle */ - ".avi", /* wouldn't be appropriate ;) */ - ".mov", /* disabled, suboptimal decoding speed */ - ".mp4", /* disabled, suboptimal decoding speed */ - ".m4v", /* disabled, suboptimal decoding speed */ - ".tga", - ".png", - ".bmp", - ".jpg", - ".tif", - ".exr", - ".wav", - ".zip", - ".mp3", - NULL)) - { - return 0; - } - - if (QTIME_DEBUG) printf("qt: checking as movie: %s\n", name); - - pool = [[NSAutoreleasePool alloc] init]; - - if ([QTMovie canInitWithFile:[NSString stringWithCString:name - encoding:[NSString defaultCStringEncoding]]]) - { - [pool drain]; - return true; - } - else - { - [pool drain]; - return false; - } -} - - -void free_anim_quicktime(struct anim *anim) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - if (anim == NULL) return; - if (anim->qtime == NULL) return; - - if (anim->qtime->ibuf) - IMB_freeImBuf(anim->qtime->ibuf); - - [anim->qtime->media release]; - [anim->qtime->movie release]; - - [QTMovie exitQTKitOnThread]; - - if (anim->qtime) MEM_freeN (anim->qtime); - - anim->qtime = NULL; - - anim->duration = 0; - - [pool drain]; -} - -static ImBuf *nsImageToiBuf(NSImage *sourceImage, int width, int height) -{ - ImBuf *ibuf = NULL; - uchar *rasterRGB = NULL; - uchar *rasterRGBA = NULL; - uchar *toIBuf = NULL; - int x, y, to_i, from_i; - NSSize bitmapSize; - NSBitmapImageRep *blBitmapFormatImageRGB,*blBitmapFormatImageRGBA, *bitmapImage = nil; - NSEnumerator *enumerator; - NSImageRep *representation; - - ibuf = IMB_allocImBuf(width, height, 32, IB_rect); - if (!ibuf) { - if (QTIME_DEBUG) { - printf("quicktime_import: could not allocate memory for the image.\n"); - } - return NULL; - } - - /*Get the bitmap of the image*/ - enumerator = [[sourceImage representations] objectEnumerator]; - while ((representation = [enumerator nextObject])) { - if ([representation isKindOfClass:[NSBitmapImageRep class]]) { - bitmapImage = (NSBitmapImageRep *)representation; - break; - } - } - if (bitmapImage == nil) return NULL; - - if (([bitmapImage bitsPerPixel] == 32) && (([bitmapImage bitmapFormat] & 0x5) == 0) - && ![bitmapImage isPlanar]) { - /* Try a fast copy if the image is a meshed RGBA 32bit bitmap*/ - toIBuf = (uchar *)ibuf->rect; - rasterRGB = (uchar *)[bitmapImage bitmapData]; - for (y = 0; y < height; y++) { - to_i = (height-y-1)*width; - from_i = y*width; - memcpy(toIBuf+4*to_i, rasterRGB+4*from_i, 4*width); - } - } - else { - - bitmapSize.width = width; - bitmapSize.height = height; - - /* Tell cocoa image resolution is same as current system one */ - [bitmapImage setSize:bitmapSize]; - - /* Convert the image in a RGBA 32bit format */ - /* As Core Graphics does not support contextes with non premutliplied alpha, - * we need to get alpha key values in a separate batch */ - - /* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */ - blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:width - pixelsHigh:height - bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bitmapFormat:0 - bytesPerRow:4*width - bitsPerPixel:32/*RGB format padded to 32bits*/]; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]]; - [bitmapImage draw]; - [NSGraphicsContext restoreGraphicsState]; - - rasterRGB = (uchar *)[blBitmapFormatImageRGB bitmapData]; - if (rasterRGB == NULL) { - [blBitmapFormatImageRGB release]; - return NULL; - } - - /* Then get Alpha values by getting the RGBA image (that is premultiplied btw) */ - blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:width - pixelsHigh:height - bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bitmapFormat:0 - bytesPerRow:4*width - bitsPerPixel:32/* RGBA */]; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]]; - [bitmapImage draw]; - [NSGraphicsContext restoreGraphicsState]; - - rasterRGBA = (uchar *)[blBitmapFormatImageRGBA bitmapData]; - if (rasterRGBA == NULL) { - [blBitmapFormatImageRGB release]; - [blBitmapFormatImageRGBA release]; - return NULL; - } - - /*Copy the image to ibuf, flipping it vertically*/ - toIBuf = (uchar *)ibuf->rect; - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - to_i = (height-y-1)*width + x; - from_i = y*width + x; - - toIBuf[4*to_i] = rasterRGB[4*from_i]; /* R */ - toIBuf[4*to_i+1] = rasterRGB[4*from_i+1]; /* G */ - toIBuf[4*to_i+2] = rasterRGB[4*from_i+2]; /* B */ - toIBuf[4*to_i+3] = rasterRGBA[4*from_i+3]; /* A */ - } - } - - [blBitmapFormatImageRGB release]; - [blBitmapFormatImageRGBA release]; - } - - return ibuf; -} - -ImBuf *qtime_fetchibuf (struct anim *anim, int position) -{ - NSImage *frameImage; - QTTime time; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - ImBuf *ibuf; - - if (anim == NULL) { - return (NULL); - } - - if (position == anim->qtime->previousPosition+1) { //Optimize sequential read - [anim->qtime->movie stepForward]; - frameImage = [anim->qtime->movie currentFrameImage]; - anim->qtime->previousPosition++; - } - else { - time.timeScale = anim->qtime->durationScale; - time.timeValue = (anim->qtime->durationTime * position) / anim->qtime->framecount; - - [anim->qtime->movie setCurrentTime:time]; - frameImage = [anim->qtime->movie currentFrameImage]; - - anim->qtime->previousPosition = position; - } - - if (frameImage == nil) { - if (QTIME_DEBUG) printf ("Error reading frame from Quicktime"); - [pool drain]; - return NULL; - } - - ibuf = nsImageToiBuf(frameImage,anim->x, anim->y); - [pool drain]; - - return ibuf; -} - - -int startquicktime(struct anim *anim) -{ - NSAutoreleasePool *pool; - NSArray* videoTracks; - NSSize frameSize; - QTTime qtTimeDuration; - NSDictionary *attributes; - - anim->qtime = MEM_callocN(sizeof(QuicktimeMovie),"animqt"); - - if (anim->qtime == NULL) { - if (QTIME_DEBUG) printf("Can't alloc qtime: %s\n", anim->name); - return -1; - } - - pool = [[NSAutoreleasePool alloc] init]; - - [QTMovie enterQTKitOnThread]; - - attributes = [NSDictionary dictionaryWithObjectsAndKeys: - [NSString stringWithCString:anim->name - encoding:[NSString defaultCStringEncoding]], QTMovieFileNameAttribute, - [NSNumber numberWithBool:NO], QTMovieEditableAttribute, - nil]; - - anim->qtime->movie = [QTMovie movieWithAttributes:attributes error:NULL]; - - if (!anim->qtime->movie) { - if (QTIME_DEBUG) printf("qt: bad movie %s\n", anim->name); - MEM_freeN(anim->qtime); - if (QTIME_DEBUG) printf("qt: can't load %s\n", anim->name); - [QTMovie exitQTKitOnThread]; - [pool drain]; - return -1; - } - [anim->qtime->movie retain]; - - // sets Media and Track! - - videoTracks = [anim->qtime->movie tracksOfMediaType:QTMediaTypeVideo]; - - if ([videoTracks count] == 0) { - if (QTIME_DEBUG) printf("qt: no video tracks for movie %s\n", anim->name); - [anim->qtime->movie release]; - MEM_freeN(anim->qtime); - if (QTIME_DEBUG) printf("qt: can't load %s\n", anim->name); - [QTMovie exitQTKitOnThread]; - [pool drain]; - return -1; - } - - anim->qtime->media = [[videoTracks objectAtIndex:0] media]; - [anim->qtime->media retain]; - - - frameSize = [[anim->qtime->movie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]; - anim->x = frameSize.width; - anim->y = frameSize.height; - - if (anim->x == 0 && anim->y == 0) { - if (QTIME_DEBUG) printf("qt: error, no dimensions\n"); - free_anim_quicktime(anim); - [pool drain]; - return -1; - } - - anim->qtime->ibuf = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect); - - qtTimeDuration = [[anim->qtime->media attributeForKey:QTMediaDurationAttribute] QTTimeValue]; - anim->qtime->durationTime = qtTimeDuration.timeValue; - anim->qtime->durationScale = qtTimeDuration.timeScale; - - anim->qtime->framecount = [[anim->qtime->media attributeForKey:QTMediaSampleCountAttribute] longValue]; - anim->qtime->previousPosition = -2; //Force seeking for first read - - //fill blender's anim struct - - anim->duration = anim->qtime->framecount; - anim->params = 0; - - anim->interlacing = 0; - anim->orientation = 0; - anim->framesize = anim->x * anim->y * 4; - - anim->curposition = 0; - - [pool drain]; - - return 0; -} - -#endif /* WITH_QUICKTIME */ - diff --git a/source/blender/quicktime/quicktime_export.h b/source/blender/quicktime/quicktime_export.h deleted file mode 100644 index aaa3f5c9070..00000000000 --- a/source/blender/quicktime/quicktime_export.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/quicktime/quicktime_export.h - * \ingroup quicktime - */ - - -#ifndef __QUICKTIME_EXPORT_H__ -#define __QUICKTIME_EXPORT_H__ - -#if defined (_WIN32) || (__APPLE__) - -#define __AIFF__ - - -#define QTAUDIO_FLAG_RESAMPLE_NOHQ 1 -#define QTAUDIO_FLAG_CODEC_ISCBR 2 - - -/*Codec list*/ -typedef struct QuicktimeCodecTypeDesc { - int codecType; - int rnatmpvalue; - const char *codecName; -} QuicktimeCodecTypeDesc; - -// quicktime movie output functions -struct ImageFormatData; -struct RenderData; -struct ReportList; -struct Scene; - -int start_qt(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview, const char *suffix); //for movie handle (BKE writeavi.c now) -int append_qt(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, const char *suffix, struct ReportList *reports); -void end_qt(void *context_v); -void filepath_qt(char *string, struct RenderData *rd, bool preview, const char *suffix); -void *context_create_qt(void); -void context_free_qt(void *context_v); - -/*RNA helper functions */ -void quicktime_verify_image_type(struct RenderData *rd, struct ImageFormatData *imf); //used by RNA for defaults values init, if needed -/*Video codec type*/ -int quicktime_get_num_videocodecs(void); -QuicktimeCodecTypeDesc *quicktime_get_videocodecType_desc(int indexValue); -int quicktime_rnatmpvalue_from_videocodectype(int codecType); -int quicktime_videocodecType_from_rnatmpvalue(int rnatmpvalue); - -/*Audio codec type*/ -int quicktime_get_num_audiocodecs(void); -QuicktimeCodecTypeDesc *quicktime_get_audiocodecType_desc(int indexValue); -int quicktime_rnatmpvalue_from_audiocodectype(int codecType); -int quicktime_audiocodecType_from_rnatmpvalue(int rnatmpvalue); - -void free_qtcomponentdata(void); -void makeqtstring(struct RenderData *rd, char *string, bool preview); //for playanim.c - - -#ifdef __APPLE__ -//Include the quicktime codec types constants that are missing in QTKitDefines.h -enum { - kRawCodecType = 'raw ', - kCinepakCodecType = 'cvid', - kGraphicsCodecType = 'smc ', - kAnimationCodecType = 'rle ', - kVideoCodecType = 'rpza', - kComponentVideoCodecType = 'yuv2', - kJPEGCodecType = 'jpeg', - kMotionJPEGACodecType = 'mjpa', - kMotionJPEGBCodecType = 'mjpb', - kSGICodecType = '.SGI', - kPlanarRGBCodecType = '8BPS', - kMacPaintCodecType = 'PNTG', - kGIFCodecType = 'gif ', - kPhotoCDCodecType = 'kpcd', - kQuickDrawGXCodecType = 'qdgx', - kAVRJPEGCodecType = 'avr ', - kOpenDMLJPEGCodecType = 'dmb1', - kBMPCodecType = 'WRLE', - kWindowsRawCodecType = 'WRAW', - kVectorCodecType = 'path', - kQuickDrawCodecType = 'qdrw', - kWaterRippleCodecType = 'ripl', - kFireCodecType = 'fire', - kCloudCodecType = 'clou', - kH261CodecType = 'h261', - kH263CodecType = 'h263', - kDVCNTSCCodecType = 'dvc ', /* DV - NTSC and DVCPRO NTSC (available in QuickTime 6.0 or later)*/ - /* NOTE: kDVCProNTSCCodecType is deprecated. */ - /* Use kDVCNTSCCodecType instead -- as far as the codecs are concerned, */ - /* the two data formats are identical.*/ - kDVCPALCodecType = 'dvcp', - kDVCProPALCodecType = 'dvpp', /* available in QuickTime 6.0 or later*/ - kDVCPro50NTSCCodecType = 'dv5n', - kDVCPro50PALCodecType = 'dv5p', - kDVCPro100NTSCCodecType = 'dv1n', - kDVCPro100PALCodecType = 'dv1p', - kDVCPROHD720pCodecType = 'dvhp', - kDVCPROHD1080i60CodecType = 'dvh6', - kDVCPROHD1080i50CodecType = 'dvh5', - kBaseCodecType = 'base', - kFLCCodecType = 'flic', - kTargaCodecType = 'tga ', - kPNGCodecType = 'png ', - kTIFFCodecType = 'tiff', /* NOTE: despite what might seem obvious from the two constants*/ - /* below and their names, they really are correct. 'yuvu' really */ - /* does mean signed, and 'yuvs' really does mean unsigned. Really. */ - kComponentVideoSigned = 'yuvu', - kComponentVideoUnsigned = 'yuvs', - kCMYKCodecType = 'cmyk', - kMicrosoftVideo1CodecType = 'msvc', - kSorensonCodecType = 'SVQ1', - kSorenson3CodecType = 'SVQ3', /* available in QuickTime 5 and later*/ - kIndeo4CodecType = 'IV41', - kMPEG4VisualCodecType = 'mp4v', - k64ARGBCodecType = 'b64a', - k48RGBCodecType = 'b48r', - k32AlphaGrayCodecType = 'b32a', - k16GrayCodecType = 'b16g', - kMpegYUV420CodecType = 'myuv', - kYUV420CodecType = 'y420', - kSorensonYUV9CodecType = 'syv9', - k422YpCbCr8CodecType = '2vuy', /* Component Y'CbCr 8-bit 4:2:2 */ - k444YpCbCr8CodecType = 'v308', /* Component Y'CbCr 8-bit 4:4:4 */ - k4444YpCbCrA8CodecType = 'v408', /* Component Y'CbCrA 8-bit 4:4:4:4 */ - k422YpCbCr16CodecType = 'v216', /* Component Y'CbCr 10,12,14,16-bit 4:2:2*/ - k422YpCbCr10CodecType = 'v210', /* Component Y'CbCr 10-bit 4:2:2 */ - k444YpCbCr10CodecType = 'v410', /* Component Y'CbCr 10-bit 4:4:4 */ - k4444YpCbCrA8RCodecType = 'r408', /* Component Y'CbCrA 8-bit 4:4:4:4, rendering format. full range alpha, zero biased yuv*/ - kJPEG2000CodecType = 'mjp2', - kPixletCodecType = 'pxlt', - kH264CodecType = 'avc1' -}; -#endif - -#endif /* (_WIN32) || (__APPLE__) */ - -#endif /* __QUICKTIME_IMP_H__ */ diff --git a/source/blender/quicktime/quicktime_import.h b/source/blender/quicktime/quicktime_import.h deleted file mode 100644 index 3c6b2028031..00000000000 --- a/source/blender/quicktime/quicktime_import.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Quicktime_import.h - * - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2002-2003 by TNCCI Inc. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/quicktime/quicktime_import.h - * \ingroup quicktime - */ - - - -#ifndef __QUICKTIME_IMPORT_H__ -#define __QUICKTIME_IMPORT_H__ - -#define __AIFF__ - -#include "../imbuf/IMB_imbuf.h" -#include "../imbuf/IMB_imbuf_types.h" - -#ifdef _WIN32 -# ifndef __FIXMATH__ -# include <FixMath.h> -# endif /* __FIXMATH__ */ -#endif /* _WIN32 _ */ - -/* init/exit */ - -void quicktime_init(void); -void quicktime_exit(void); - -/* quicktime movie import functions */ - -int anim_is_quicktime(const char *name); -int startquicktime(struct anim *anim); -void free_anim_quicktime(struct anim *anim); -ImBuf *qtime_fetchibuf(struct anim *anim, int position); - -#endif /* __QUICKTIME_IMPORT_H__ */ diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index a12bdd910c3..27ec6bf8ba6 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -148,16 +148,6 @@ if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() -if(WITH_CODEC_QUICKTIME) - list(APPEND INC - ../quicktime - ) - list(APPEND INC_SYS - ${QUICKTIME_INCLUDE_DIRS} - ) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_GAMEENGINE) add_definitions(-DWITH_GAMEENGINE) endif() diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 0d2e29ba4c8..cf9298bdb9e 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -194,6 +194,10 @@ typedef struct RenderStats { struct Render *RE_NewRender(const char *name); struct Render *RE_GetRender(const char *name); +struct Scene; +struct Render *RE_NewSceneRender(const struct Scene *scene); +struct Render *RE_GetSceneRender(const struct Scene *scene); + /* assign default dummy callbacks */ void RE_InitRenderCB(struct Render *re); diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h index 13f16ce0bd7..3ef6e9d7476 100644 --- a/source/blender/render/intern/include/shading.h +++ b/source/blender/render/intern/include/shading.h @@ -57,7 +57,7 @@ typedef struct ShadeSample { void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr); void shade_input_set_triangle_i(struct ShadeInput *shi, struct ObjectInstanceRen *obi, struct VlakRen *vlr, short i1, short i2, short i3); -void shade_input_set_triangle(struct ShadeInput *shi, volatile int obi, volatile int facenr, int normal_flip); +void shade_input_set_triangle(struct ShadeInput *shi, int obi, int facenr, int normal_flip); void shade_input_copy_triangle(struct ShadeInput *shi, struct ShadeInput *from); void shade_input_calc_viewco(struct ShadeInput *shi, float x, float y, float z, float view[3], float dxyview[2], float co[3], float dxco[3], float dyco[3]); void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float sx, float sy, float z); diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp index 81e41a20f2e..103fa3e6034 100644 --- a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp +++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp @@ -59,6 +59,7 @@ static void rtbuild_init(RTBuilder *b) b->primitives.begin = NULL; b->primitives.end = NULL; b->primitives.maxsize = 0; + b->depth = 0; for (int i = 0; i < RTBUILD_MAX_CHILDS; i++) b->child_offset[i] = 0; @@ -178,6 +179,8 @@ RTBuilder *rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp) { rtbuild_init(tmp); + tmp->depth = b->depth + 1; + for (int i = 0; i < 3; i++) if (b->sorted_begin[i]) { tmp->sorted_begin[i] = b->sorted_begin[i] + b->child_offset[child]; @@ -336,6 +339,15 @@ int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds) int baxis = -1, boffset = 0; if (size > nchilds) { + if (b->depth > RTBUILD_MAX_SAH_DEPTH) { + // for degenerate cases we avoid running out of stack space + // by simply splitting the children in the middle + b->child_offset[0] = 0; + b->child_offset[1] = (size+1)/2; + b->child_offset[2] = size; + return 2; + } + float bcost = FLT_MAX; baxis = -1; boffset = size / 2; diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.h b/source/blender/render/intern/raytrace/rayobject_rtbuild.h index 9e296da144b..83042ef3d7e 100644 --- a/source/blender/render/intern/raytrace/rayobject_rtbuild.h +++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.h @@ -49,7 +49,8 @@ extern "C" { * generate with simple calls, and then convert to the theirs * specific structure on the fly. */ -#define RTBUILD_MAX_CHILDS 32 +#define RTBUILD_MAX_CHILDS 32 +#define RTBUILD_MAX_SAH_DEPTH 256 typedef struct RTBuilder { @@ -79,6 +80,8 @@ typedef struct RTBuilder { float bb[6]; + /* current depth */ + int depth; } RTBuilder; /* used during creation */ diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index 04010522c12..ae02cf56b88 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -1172,7 +1172,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex a = max_ff(a, 1.0f); b = max_ff(b, 1.0f); fProbes = 2.f*(a / b) - 1.f; - AFD.iProbes = iroundf(fProbes); + AFD.iProbes = round_fl_to_int(fProbes); AFD.iProbes = MIN2(AFD.iProbes, tex->afmax); if (AFD.iProbes < fProbes) b = 2.f*a / (float)(AFD.iProbes + 1); @@ -1277,7 +1277,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex b = max_ff(b, 1.0f); fProbes = 2.f*(a / b) - 1.f; /* no limit to number of Probes here */ - AFD.iProbes = iroundf(fProbes); + AFD.iProbes = round_fl_to_int(fProbes); if (AFD.iProbes < fProbes) b = 2.f*a / (float)(AFD.iProbes + 1); AFD.majrad = a/ff; AFD.minrad = b/ff; diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index 970a3937657..fbf18405093 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -48,10 +48,6 @@ #include "BKE_camera.h" -#ifdef WITH_QUICKTIME -#include "quicktime_export.h" -#endif - /* this module */ #include "renderpipeline.h" #include "render_types.h" diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index e078365e1ed..a0ebe241569 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -307,7 +307,6 @@ Render *RE_GetRender(const char *name) return re; } - /* if you want to know exactly what has been done */ RenderResult *RE_AcquireResultRead(Render *re) { @@ -514,6 +513,36 @@ Render *RE_NewRender(const char *name) return re; } +/* MAX_ID_NAME + sizeof(Library->name) + space + null-terminator. */ +#define MAX_SCENE_RENDER_NAME (MAX_ID_NAME + 1024 + 2) + +static void scene_render_name_get(const Scene *scene, + const size_t max_size, + char *render_name) +{ + if (ID_IS_LINKED_DATABLOCK(scene)) { + BLI_snprintf(render_name, max_size, "%s %s", + scene->id.lib->id.name, scene->id.name); + } + else { + BLI_snprintf(render_name, max_size, "%s", scene->id.name); + } +} + +Render *RE_GetSceneRender(const Scene *scene) +{ + char render_name[MAX_SCENE_RENDER_NAME]; + scene_render_name_get(scene, sizeof(render_name), render_name); + return RE_GetRender(render_name); +} + +Render *RE_NewSceneRender(const Scene *scene) +{ + char render_name[MAX_SCENE_RENDER_NAME]; + scene_render_name_get(scene, sizeof(render_name), render_name); + return RE_NewRender(render_name); +} + /* called for new renders and when finishing rendering so * we always have valid callbacks on a render */ void RE_InitRenderCB(Render *re) @@ -1913,7 +1942,7 @@ static void do_render_fields_blur_3d(Render *re) */ static void render_scene(Render *re, Scene *sce, int cfra) { - Render *resc = RE_NewRender(sce->id.name); + Render *resc = RE_NewSceneRender(sce); int winx = re->winx, winy = re->winy; sce->r.cfra = cfra; @@ -2348,7 +2377,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) tag_scenes_for_render(re); for (sce = re->main->scene.first; sce; sce = sce->id.next) { if (sce->id.tag & LIB_TAG_DOIT) { - re1 = RE_GetRender(sce->id.name); + re1 = RE_GetSceneRender(sce); if (re1 && (re1->r.scemode & R_FULL_SAMPLE)) { if (sample) { @@ -3858,9 +3887,9 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode) scene = scenode; /* get render: it can be called from UI with draw callbacks */ - re = RE_GetRender(scene->id.name); + re = RE_GetSceneRender(scene); if (re == NULL) - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); RE_InitState(re, NULL, &scene->r, NULL, winx, winy, &disprect); re->scene = scene; re->scene_color_manage = BKE_scene_check_color_management_enabled(scene); diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index 20602314526..b4ff5f52fcf 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -292,12 +292,8 @@ void shade_input_set_triangle_i(ShadeInput *shi, ObjectInstanceRen *obi, VlakRen } } -/* note, facenr declared volatile due to over-eager -O2 optimization's - * on cygwin (particularly -frerun-cse-after-loop) - */ - /* copy data from face to ShadeInput, scanline case */ -void shade_input_set_triangle(ShadeInput *shi, volatile int obi, volatile int facenr, int UNUSED(normal_flip)) +void shade_input_set_triangle(ShadeInput *shi, int obi, int facenr, int UNUSED(normal_flip)) { if (facenr > 0) { shi->obi = &R.objectinstance[obi]; diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index 68707f163af..1481e7a8059 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -393,7 +393,7 @@ static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr, zverg-= zspan->polygon_offset; while (x>=0) { - intzverg= (int)CLAMPIS(zverg, INT_MIN, INT_MAX); + intzverg = round_db_to_int_clamp(zverg); if ( intzverg < *rz) { if (!zspan->rectmask || intzverg > *rm) { @@ -1137,7 +1137,7 @@ static void zbuffillGLinv4(ZSpan *zspan, int obi, int zvlnr, x= sn2-sn1; while (x>=0) { - intzverg= (int)CLAMPIS(zverg, INT_MIN, INT_MAX); + intzverg = round_db_to_int_clamp(zverg); if ( intzverg > *rz || *rz==0x7FFFFFFF) { /* UNIQUE LINE: see comment above */ if (!zspan->rectmask || intzverg > *rm) { @@ -1260,7 +1260,7 @@ static void zbuffillGL4(ZSpan *zspan, int obi, int zvlnr, x= sn2-sn1; while (x>=0) { - intzverg= (int)CLAMPIS(zverg, INT_MIN, INT_MAX); + intzverg = round_db_to_int_clamp(zverg); if (intzverg < *rz) { /* ONLY UNIQUE LINE: see comment above */ if (!zspan->rectmask || intzverg > *rm) { @@ -1383,7 +1383,7 @@ static void zbuffillGL_onlyZ(ZSpan *zspan, int UNUSED(obi), int UNUSED(zvlnr), x= sn2-sn1; while (x>=0) { - int zvergi= (int)CLAMPIS(zverg, INT_MIN, INT_MAX); + int zvergi = round_db_to_int_clamp(zverg); /* option: maintain two depth values, closest and 2nd closest */ if (zvergi < *rz) { @@ -1564,20 +1564,13 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float * vy0= ((double)my2)*vyd + (double)xx1; /* correct span */ - sn1= (my0 + my2)/2; - if (zspan->span1[sn1] < zspan->span2[sn1]) { - span1= zspan->span1+my2; - span2= zspan->span2+my2; - } - else { - span1= zspan->span2+my2; - span2= zspan->span1+my2; - } + span1= zspan->span1+my2; + span2= zspan->span2+my2; for (i = 0, y = my2; y >= my0; i++, y--, span1--, span2--) { - sn1= floor(*span1); - sn2= floor(*span2); + sn1= floor(min_ff(*span1, *span2)); + sn2= floor(max_ff(*span1, *span2)); sn1++; if (sn2>=rectx) sn2= rectx-1; diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 925563a0777..f22ed34ca2e 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -100,16 +100,6 @@ if(WITH_OPENCOLLADA) add_definitions(-DWITH_COLLADA) endif() -if(WITH_CODEC_QUICKTIME) - list(APPEND INC - ../quicktime - ) - list(APPEND INC_SYS - ${QUICKTIME_INCLUDE_DIRS} - ) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_CODEC_FFMPEG) list(APPEND INC_SYS ${FFMPEG_INCLUDE_DIRS} diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 60a39b24208..7c1c388bcba 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -187,8 +187,9 @@ struct wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase /* mouse */ void WM_event_add_mousemove(struct bContext *C); -bool WM_modal_tweak_exit(const struct wmEvent *event, int tweak_event); +bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event); bool WM_event_is_absolute(const struct wmEvent *event); +bool WM_event_is_last_mousemove(const struct wmEvent *event); #ifdef WITH_INPUT_NDOF /* 3D mouse */ @@ -353,6 +354,7 @@ bool WM_operator_pystring_abbreviate(char *str, int str_len_max); char *WM_prop_pystring_assign(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, int index); void WM_operator_bl_idname(char *to, const char *from); void WM_operator_py_idname(char *to, const char *from); +bool WM_operator_py_idname_ok_or_report(struct ReportList *reports, const char *classname, const char *idname); /* *************** uilist types ******************** */ void WM_uilisttype_init(void); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 67e961b9cd0..a09cc4aeb31 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -430,7 +430,7 @@ void wm_clear_default_size(bContext *C) /* on startup, it adds all data, for matching */ void wm_add_default(bContext *C) { - wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan"); + wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan", 0); wmWindow *win; bScreen *screen = CTX_wm_screen(C); /* XXX from file read hrmf */ @@ -495,6 +495,10 @@ void wm_close_and_free_all(bContext *C, ListBase *wmlist) void WM_main(bContext *C) { + /* Single refresh before handling events. + * This ensures we don't run operators before the depsgraph has been evaluated. */ + wm_event_do_refresh_wm_and_depsgraph(C); + while (1) { /* get events from ghost, handle window events, add to window queues */ diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 25c6980f58e..2b695c95258 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -867,25 +867,13 @@ static bool wm_draw_update_test_window(wmWindow *win) static int wm_automatic_draw_method(wmWindow *win) { - /* Ideally all cards would work well with triple buffer, since if it works - * well gives the least redraws and is considerably faster at partial redraw - * for sculpting or drawing overlapping menus. For typically lower end cards - * copy to texture is slow though and so we use overlap instead there. */ - + /* We assume all supported GPUs now support triple buffer well. */ if (win->drawmethod == USER_DRAW_AUTOMATIC) { - /* Windows software driver darkens color on each redraw */ - if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE)) - return USER_DRAW_OVERLAP_FLIP; - else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_UNIX, GPU_DRIVER_SOFTWARE)) - return USER_DRAW_OVERLAP; - /* drawing lower color depth again degrades colors each time */ - else if (GPU_color_depth() < 24) - return USER_DRAW_OVERLAP; - else - return USER_DRAW_TRIPLE; + return USER_DRAW_TRIPLE; } - else + else { return win->drawmethod; + } } bool WM_is_draw_triple(wmWindow *win) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index f26ee0e73ec..7e7314cc0c8 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -263,13 +263,56 @@ static void wm_notifier_clear(wmNotifier *note) memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link)); } +/** + * Was part of #wm_event_do_notifiers, split out so it can be called once before entering the #WM_main loop. + * This ensures operators don't run before the UI and depsgraph are initialized. + */ +void wm_event_do_refresh_wm_and_depsgraph(bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + uint64_t win_combine_v3d_datamask = 0; + + /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */ + for (wmWindow *win = wm->windows.first; win; win = win->next) { + win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen); + } + + /* cached: editor refresh callbacks now, they get context */ + for (wmWindow *win = wm->windows.first; win; win = win->next) { + ScrArea *sa; + + CTX_wm_window_set(C, win); + for (sa = win->screen->areabase.first; sa; sa = sa->next) { + if (sa->do_refresh) { + CTX_wm_area_set(C, sa); + ED_area_do_refresh(C, sa); + } + } + + /* XXX make lock in future, or separated derivedmesh users in scene */ + if (G.is_rendering == false) { + /* depsgraph & animation: update tagged datablocks */ + Main *bmain = CTX_data_main(C); + + /* copied to set's in scene_update_tagged_recursive() */ + win->screen->scene->customdata_mask = win_combine_v3d_datamask; + + /* XXX, hack so operators can enforce datamasks [#26482], gl render */ + win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal; + + BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene); + } + } + + CTX_wm_window_set(C, NULL); +} + /* called in mainloop */ void wm_event_do_notifiers(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); wmNotifier *note, *next; wmWindow *win; - uint64_t win_combine_v3d_datamask = 0; if (wm == NULL) return; @@ -373,39 +416,7 @@ void wm_event_do_notifiers(bContext *C) MEM_freeN(note); } - /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */ - for (win = wm->windows.first; win; win = win->next) { - win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen); - } - - /* cached: editor refresh callbacks now, they get context */ - for (win = wm->windows.first; win; win = win->next) { - ScrArea *sa; - - CTX_wm_window_set(C, win); - for (sa = win->screen->areabase.first; sa; sa = sa->next) { - if (sa->do_refresh) { - CTX_wm_area_set(C, sa); - ED_area_do_refresh(C, sa); - } - } - - /* XXX make lock in future, or separated derivedmesh users in scene */ - if (G.is_rendering == false) { - /* depsgraph & animation: update tagged datablocks */ - Main *bmain = CTX_data_main(C); - - /* copied to set's in scene_update_tagged_recursive() */ - win->screen->scene->customdata_mask = win_combine_v3d_datamask; - - /* XXX, hack so operators can enforce datamasks [#26482], gl render */ - win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal; - - BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene); - } - } - - CTX_wm_window_set(C, NULL); + wm_event_do_refresh_wm_and_depsgraph(C); } static int wm_event_always_pass(const wmEvent *event) @@ -615,6 +626,16 @@ bool WM_event_is_absolute(const wmEvent *event) return (event->tablet_data != NULL); } +bool WM_event_is_last_mousemove(const wmEvent *event) +{ + while ((event = event->next)) { + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + return false; + } + } + return true; +} + #ifdef WITH_INPUT_NDOF void WM_ndof_deadzone_set(float deadzone) { @@ -1079,6 +1100,9 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op)) #endif +/** + * Also used for exec when 'event' is NULL. + */ static int wm_operator_invoke( bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports, const bool poll_only) @@ -1094,7 +1118,9 @@ static int wm_operator_invoke( wmOperator *op = wm_operator_create(wm, ot, properties, reports); /* if reports == NULL, they'll be initialized */ const bool is_nested_call = (wm->op_undo_depth != 0); - op->flag |= OP_IS_INVOKE; + if (event != NULL) { + op->flag |= OP_IS_INVOKE; + } /* initialize setting from previous run */ if (!is_nested_call) { /* not called by py script */ @@ -2852,7 +2878,7 @@ void WM_event_add_mousemove(bContext *C) /* for modal callbacks, check configuration for how to interpret exit with tweaks */ -bool WM_modal_tweak_exit(const wmEvent *event, int tweak_event) +bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event) { /* if the release-confirm userpref setting is enabled, * tweak events can be canceled when mouse is released diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index b4a6366fb4e..637ace9cd82 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -449,7 +449,7 @@ void wm_file_read_report(bContext *C) * Logic shared between #WM_file_read & #wm_homefile_read, * updates to make after reading a file. */ -static void wm_file_read_post(bContext *C, bool is_startup_file) +static void wm_file_read_post(bContext *C, const bool is_startup_file, const bool use_userdef) { bool addons_loaded = false; wmWindowManager *wm = CTX_wm_manager(C); @@ -468,13 +468,14 @@ static void wm_file_read_post(bContext *C, bool is_startup_file) if (is_startup_file) { /* possible python hasn't been initialized */ if (CTX_py_init_get(C)) { - /* Only run when we have a template path found. */ - if (BKE_appdir_app_template_any()) { - BPY_execute_string(C, "__import__('bl_app_template_utils').reset()"); + if (use_userdef) { + /* Only run when we have a template path found. */ + if (BKE_appdir_app_template_any()) { + BPY_execute_string(C, "__import__('bl_app_template_utils').reset()"); + } + /* sync addons, these may have changed from the defaults */ + BPY_execute_string(C, "__import__('addon_utils').reset_all()"); } - /* sync addons, these may have changed from the defaults */ - BPY_execute_string(C, "__import__('addon_utils').reset_all()"); - BPY_python_reset(C); addons_loaded = true; } @@ -588,7 +589,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) } } - wm_file_read_post(C, false); + wm_file_read_post(C, false, false); success = true; } @@ -636,13 +637,15 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) * * \param use_factory_settings: Ignore on-disk startup file, use bundled ``datatoc_startup_blend`` instead. * Used for "Restore Factory Settings". + * \param use_userdef: Load factory settings as well as startup file. + * Disabled for "File New" we don't want to reload preferences. * \param filepath_startup_override: Optional path pointing to an alternative blend file (may be NULL). * \param app_template_override: Template to use instead of the template defined in user-preferences. * When not-null, this is written into the user preferences. */ int wm_homefile_read( bContext *C, ReportList *reports, - bool use_factory_settings, bool use_empty_data, + bool use_factory_settings, bool use_empty_data, bool use_userdef, const char *filepath_startup_override, const char *app_template_override) { ListBase wmbase; @@ -666,7 +669,7 @@ int wm_homefile_read( * And in this case versioning code is to be run. */ bool read_userdef_from_memory = false; - eBLOReadSkip skip_flags = 0; + eBLOReadSkip skip_flags = use_userdef ? 0 : BLO_READ_SKIP_USERDEF; /* options exclude eachother */ BLI_assert((use_factory_settings && filepath_startup_override) == 0); @@ -693,7 +696,9 @@ int wm_homefile_read( if (!use_factory_settings) { if (cfgdir) { BLI_path_join(filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE, NULL); - BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL); + if (use_userdef) { + BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL); + } } else { use_factory_settings = true; @@ -705,14 +710,16 @@ int wm_homefile_read( } /* load preferences before startup.blend */ - if (!use_factory_settings && BLI_exists(filepath_userdef)) { - UserDef *userdef = BKE_blendfile_userdef_read(filepath_userdef, NULL); - if (userdef != NULL) { - BKE_blender_userdef_set_data(userdef); - MEM_freeN(userdef); - - skip_flags |= BLO_READ_SKIP_USERDEF; - printf("Read prefs: %s\n", filepath_userdef); + if (use_userdef) { + if (!use_factory_settings && BLI_exists(filepath_userdef)) { + UserDef *userdef = BKE_blendfile_userdef_read(filepath_userdef, NULL); + if (userdef != NULL) { + BKE_blender_userdef_set_data(userdef); + MEM_freeN(userdef); + + skip_flags |= BLO_READ_SKIP_USERDEF; + printf("Read prefs: %s\n", filepath_userdef); + } } } @@ -721,23 +728,23 @@ int wm_homefile_read( if (filepath_startup_override != NULL) { /* pass */ } - else if (app_template_override && app_template_override[0]) { + else if (app_template_override) { + /* This may be clearing the current template by setting to an empty string. */ app_template = app_template_override; } else if (!use_factory_settings && U.app_template[0]) { app_template = U.app_template; } - if (app_template != NULL) { + if ((app_template != NULL) && (app_template[0] != '\0')) { BKE_appdir_app_template_id_search(app_template, app_template_system, sizeof(app_template_system)); - BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL); - } - /* insert template name into startup file */ - if (app_template != NULL) { + /* Insert template name into startup file. */ + /* note that the path is being set even when 'use_factory_settings == true' * this is done so we can load a templates factory-settings */ if (!use_factory_settings) { + BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL); BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_config, BLENDER_STARTUP_FILE, NULL); if (BLI_access(filepath_startup, R_OK) != 0) { filepath_startup[0] = '\0'; @@ -772,8 +779,12 @@ int wm_homefile_read( success = BKE_blendfile_read_from_memory( C, datatoc_startup_blend, datatoc_startup_blend_size, NULL, skip_flags, true); - if (success && !(skip_flags & BLO_READ_SKIP_USERDEF)) { - read_userdef_from_memory = true; + if (success) { + if (use_userdef) { + if ((skip_flags & BLO_READ_SKIP_USERDEF) == 0) { + read_userdef_from_memory = true; + } + } } if (BLI_listbase_is_empty(&wmbase)) { wm_clear_default_size(C); @@ -801,21 +812,23 @@ int wm_homefile_read( BLI_path_join(temp_path, sizeof(temp_path), app_template_system, BLENDER_USERPREF_FILE, NULL); } - UserDef *userdef_template = NULL; - /* just avoids missing file warning */ - if (BLI_exists(temp_path)) { - userdef_template = BKE_blendfile_userdef_read(temp_path, NULL); - } - if (userdef_template == NULL) { - /* we need to have preferences load to overwrite preferences from previous template */ - userdef_template = BKE_blendfile_userdef_read_from_memory( - datatoc_startup_blend, datatoc_startup_blend_size, NULL); - read_userdef_from_memory = true; - } - if (userdef_template) { - BKE_blender_userdef_set_app_template(userdef_template); - BKE_blender_userdef_free_data(userdef_template); - MEM_freeN(userdef_template); + if (use_userdef) { + UserDef *userdef_template = NULL; + /* just avoids missing file warning */ + if (BLI_exists(temp_path)) { + userdef_template = BKE_blendfile_userdef_read(temp_path, NULL); + } + if (userdef_template == NULL) { + /* we need to have preferences load to overwrite preferences from previous template */ + userdef_template = BKE_blendfile_userdef_read_from_memory( + datatoc_startup_blend, datatoc_startup_blend_size, NULL); + read_userdef_from_memory = true; + } + if (userdef_template) { + BKE_blender_userdef_set_app_template(userdef_template); + BKE_blender_userdef_free_data(userdef_template); + MEM_freeN(userdef_template); + } } } @@ -827,8 +840,10 @@ int wm_homefile_read( * can remove this eventually, only in a 2.53 and older, now its not written */ G.fileflags &= ~G_FILE_RELATIVE_REMAP; - /* check userdef before open window, keymaps etc */ - wm_init_userdef(C, read_userdef_from_memory); + if (use_userdef) { + /* check userdef before open window, keymaps etc */ + wm_init_userdef(C, read_userdef_from_memory); + } /* match the read WM with current WM */ wm_window_match_do(C, &wmbase); @@ -836,9 +851,11 @@ int wm_homefile_read( G.main->name[0] = '\0'; - /* When loading factory settings, the reset solid OpenGL lights need to be applied. */ - if (!G.background) { - GPU_default_lights(); + if (use_userdef) { + /* When loading factory settings, the reset solid OpenGL lights need to be applied. */ + if (!G.background) { + GPU_default_lights(); + } } /* start with save preference untitled.blend */ @@ -846,7 +863,7 @@ int wm_homefile_read( /* disable auto-play in startup.blend... */ G.fileflags &= ~G_FILE_AUTOPLAY; - wm_file_read_post(C, true); + wm_file_read_post(C, true, use_userdef); return true; } @@ -1528,6 +1545,7 @@ void WM_OT_read_history(wmOperatorType *ot) static int wm_homefile_read_exec(bContext *C, wmOperator *op) { const bool use_factory_settings = (STREQ(op->type->idname, "WM_OT_read_factory_settings")); + bool use_userdef = false; char filepath_buf[FILE_MAX]; const char *filepath = NULL; @@ -1551,6 +1569,8 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) else { /* always load UI for factory settings (prefs will re-init) */ G.fileflags &= ~G_FILE_NO_UI; + /* Always load preferences with factory settings. */ + use_userdef = true; } char app_template_buf[sizeof(U.app_template)]; @@ -1562,17 +1582,15 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) if (prop_app_template && RNA_property_is_set(op->ptr, prop_app_template)) { RNA_property_string_get(op->ptr, prop_app_template, app_template_buf); app_template = app_template_buf; - } - else if (!use_factory_settings) { - /* TODO: dont reset prefs on 'New File' */ - BLI_strncpy(app_template_buf, U.app_template, sizeof(app_template_buf)); - app_template = app_template_buf; + + /* Always load preferences when switching templates. */ + use_userdef = true; } else { app_template = NULL; } - if (wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, filepath, app_template)) { + if (wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, use_userdef, filepath, app_template)) { if (use_splash) { WM_init_splash(C); } diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 46203333eb5..e04571fe572 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -137,7 +137,7 @@ int wm_gesture_evaluate(wmGesture *gesture) int dx = BLI_rcti_size_x(rect); int dy = BLI_rcti_size_y(rect); if (abs(dx) + abs(dy) > U.tweak_threshold) { - int theta = iroundf(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI); + int theta = round_fl_to_int(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI); int val = EVT_GESTURE_W; if (theta == 0) val = EVT_GESTURE_E; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 00a9976e8be..e73ec2b081a 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -184,15 +184,12 @@ void WM_init(bContext *C, int argc, const char **argv) BLF_init(); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */ BLT_lang_init(); - /* Enforce loading the UI for the initial homefile */ - G.fileflags &= ~G_FILE_NO_UI; - /* reports cant be initialized before the wm, * but keep before file reading, since that may report errors */ wm_init_reports(C); /* get the default database, plus a wm */ - wm_homefile_read(C, NULL, G.factory_startup, false, NULL, NULL); + wm_homefile_read(C, NULL, G.factory_startup, false, true, NULL, NULL); BLT_lang_set(NULL); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index d3ebd3e4d2c..51c551cd9a5 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -177,7 +177,7 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *)) /* XXX All ops should have a description but for now allow them not to. */ RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP); - RNA_def_struct_identifier(ot->srna, ot->idname); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); } @@ -193,7 +193,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void * ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT; opfunc(ot, userdata); RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP); - RNA_def_struct_identifier(ot->srna, ot->idname); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); } @@ -398,7 +398,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam ot->description = UNDOCUMENTED_OPERATOR_TIP; RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); - RNA_def_struct_identifier(ot->srna, ot->idname); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); /* Use i18n context from ext.srna if possible (py operators). */ i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLT_I18NCONTEXT_OPERATOR_DEFAULT; RNA_def_struct_translation_context(ot->srna, i18n_context); @@ -432,7 +432,7 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *), opfunc(ot, userdata); RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); - RNA_def_struct_identifier(ot->srna, ot->idname); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); } @@ -573,6 +573,46 @@ void WM_operator_bl_idname(char *to, const char *from) } /** + * Sanity check to ensure #WM_operator_bl_idname won't fail. + * \returns true when there are no problems with \a idname, otherwise report an error. + */ +bool WM_operator_py_idname_ok_or_report(ReportList *reports, const char *classname, const char *idname) +{ + const char *ch = idname; + int dot = 0; + int i; + for (i = 0; *ch; i++, ch++) { + if ((*ch >= 'a' && *ch <= 'z') || (*ch >= '0' && *ch <= '9') || *ch == '_') { + /* pass */ + } + else if (*ch == '.') { + dot++; + } + else { + BKE_reportf(reports, RPT_ERROR, + "Registering operator class: '%s', invalid bl_idname '%s', at position %d", + classname, idname, i); + return false; + } + } + + if (i > (MAX_NAME - 3)) { + BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', " + "is too long, maximum length is %d", classname, idname, + MAX_NAME - 3); + return false; + } + + if (dot != 1) { + BKE_reportf(reports, RPT_ERROR, + "Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character", + classname, idname); + return false; + } + return true; +} + +/** * Print a string representation of the operator, with the args that it runs so python can run it again. * * When calling from an existing wmOperator, better to use simple version: @@ -806,9 +846,19 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert } \ } (void)0 +#define CTX_TEST_SPACE_TYPE(space_data_type, member_full, dataptr_cmp) \ + { \ + const char *ctx_member_full = member_full; \ + if (space_data->spacetype == space_data_type && ptr->data == dataptr_cmp) { \ + member_id = ctx_member_full; \ + break; \ + } \ + } (void)0 + switch (GS(((ID *)ptr->id.data)->name)) { case ID_SCE: { + CTX_TEST_PTR_DATA_TYPE(C, "active_gpencil_brush", RNA_GPencilBrush, ptr, CTX_data_active_gpencil_brush(C)); CTX_TEST_PTR_ID(C, "scene", ptr->id.data); break; } @@ -843,12 +893,22 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert { CTX_TEST_PTR_ID(C, "screen", ptr->id.data); - CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, CTX_wm_space_data(C)); + SpaceLink *space_data = CTX_wm_space_data(C); + + CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, space_data); CTX_TEST_PTR_DATA_TYPE(C, "area", RNA_Area, ptr, CTX_wm_area(C)); CTX_TEST_PTR_DATA_TYPE(C, "region", RNA_Region, ptr, CTX_wm_region(C)); + CTX_TEST_SPACE_TYPE(SPACE_IMAGE, "space_data.uv_editor", space_data); + CTX_TEST_SPACE_TYPE(SPACE_VIEW3D, "space_data.fx_settings", &(CTX_wm_view3d(C)->fx_settings)); + CTX_TEST_SPACE_TYPE(SPACE_NLA, "space_data.dopesheet", CTX_wm_space_nla(C)->ads); + CTX_TEST_SPACE_TYPE(SPACE_IPO, "space_data.dopesheet", CTX_wm_space_graph(C)->ads); + CTX_TEST_SPACE_TYPE(SPACE_ACTION, "space_data.dopesheet", &(CTX_wm_space_action(C)->ads)); + CTX_TEST_SPACE_TYPE(SPACE_FILE, "space_data.params", CTX_wm_space_file(C)->params); break; } + default: + break; } if (member_id) { @@ -860,6 +920,7 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert } #undef CTX_TEST_PTR_ID #undef CTX_TEST_PTR_ID_CAST +#undef CTX_TEST_SPACE_TYPE } return ret; diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 8afeb8e7b3d..9fe215f7712 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -377,7 +377,12 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win) void WM_window_set_dpi(wmWindow *win) { - int auto_dpi = GHOST_GetDPIHint(win->ghostwin); + float auto_dpi = GHOST_GetDPIHint(win->ghostwin); + + /* Clamp auto DPI to 96, since our font/interface drawing does not work well + * with lower sizes. The main case we are interested in supporting is higher + * DPI. If a smaller UI is desired it is still possible to adjust UI scale. */ + auto_dpi = max_ff(auto_dpi, 96.0f); /* Lazily init UI scale size, preserving backwards compatibility by * computing UI scale from ratio of previous DPI and auto DPI */ @@ -397,13 +402,16 @@ void WM_window_set_dpi(wmWindow *win) /* Blender's UI drawing assumes DPI 72 as a good default following macOS * while Windows and Linux use DPI 96. GHOST assumes a default 96 so we * remap the DPI to Blender's convention. */ + auto_dpi *= GHOST_GetNativePixelSize(win->ghostwin); int dpi = auto_dpi * U.ui_scale * (72.0 / 96.0f); /* Automatically set larger pixel size for high DPI. */ - int pixelsize = MAX2(1, dpi / 54); + int pixelsize = max_ii(1, (int)(dpi / 64)); + /* User adjustment for pixel size. */ + pixelsize = max_ii(1, pixelsize + U.ui_line_width); /* Set user preferences globals for drawing, and for forward compatibility. */ - U.pixelsize = GHOST_GetNativePixelSize(win->ghostwin) * pixelsize; + U.pixelsize = pixelsize; U.dpi = dpi / pixelsize; U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE; U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72; diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index efc01b1f8a8..3fb9cd617bf 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -87,7 +87,8 @@ void wm_event_do_handlers (bContext *C); void wm_event_add_ghostevent (wmWindowManager *wm, wmWindow *win, int type, int time, void *customdata); -void wm_event_do_notifiers (bContext *C); +void wm_event_do_refresh_wm_and_depsgraph(bContext *C); +void wm_event_do_notifiers(bContext *C); /* wm_keymap.c */ diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index 9a1518e15b0..b102b6c7cc7 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -37,7 +37,7 @@ struct wmOperatorType; void wm_history_file_read(void); int wm_homefile_read( struct bContext *C, struct ReportList *reports, - bool use_factory_settings, bool use_empty_data, + bool use_factory_settings, bool use_empty_data, bool use_userdef, const char *filepath_startup_override, const char *app_template_override); void wm_file_read_report(bContext *C); diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index 66c72be3d5d..e5a5ff828dd 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -27,10 +27,6 @@ setup_libdirs() -if(WITH_CODEC_QUICKTIME) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WIN32 AND NOT UNIX) string(SUBSTRING ${BLENDER_VERSION} 0 1 bver1) string(SUBSTRING ${BLENDER_VERSION} 2 1 bver2) @@ -200,10 +196,6 @@ endif() list(APPEND BLENDER_SORTED_LIBS extern_xdnd) endif() - if(WITH_CODEC_QUICKTIME) - list(APPEND BLENDER_SORTED_LIBS bf_quicktime) - endif() - if(WITH_CXX_GUARDEDALLOC) list(APPEND BLENDER_SORTED_LIBS bf_intern_guardedalloc_cpp) endif() diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 7ee0e75b2f7..6afb6c103e0 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -271,6 +271,7 @@ void RE_sample_material_color( int tri_index, struct DerivedMesh *orcoDm, struct Object *ob) RET_NONE /* nodes */ struct Render *RE_GetRender(const char *name) RET_NULL +struct Render *RE_GetSceneRender(const struct Scene *scene) RET_NULL struct Object *RE_GetCamera(struct Render *re) RET_NULL float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]) RET_ZERO const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4] RET_NULL @@ -296,6 +297,7 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype) RET_NONE double elbeemEstimateMemreq(int res, float sx, float sy, float sz, int refine, char *retstr) RET_ZERO struct Render *RE_NewRender(const char *name) RET_NULL +struct Render *RE_NewSceneRender(const struct Scene *scene) RET_NULL void RE_SwapResult(struct Render *re, struct RenderResult **rr) RET_NONE void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene, struct SceneRenderLayer *srl, struct Object *camera_override, unsigned int lay_override, int frame, const bool write_still) RET_NONE bool RE_WriteEnvmapResult(struct ReportList *reports, struct Scene *scene, struct EnvMap *env, const char *relpath, const char imtype, float layout[12]) RET_ZERO @@ -355,7 +357,7 @@ int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struc void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference) RET_NONE void WM_main_add_notifier(unsigned int type, void *reference) RET_NONE void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep) RET_NONE -void ED_armature_transform(struct bArmature *arm, float mat[4][4]) RET_NONE +void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props) RET_NONE struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op) RET_NULL struct wmTimer *WM_event_add_timer(struct wmWindowManager *wm, struct wmWindow *win, int event_type, double timestep) RET_NULL void WM_event_remove_timer(struct wmWindowManager *wm, struct wmWindow *win, struct wmTimer *timer) RET_NONE @@ -699,6 +701,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(struct wmOperatorType *, void *), void WM_operatortype_append_macro_ptr(void (*opfunc)(struct wmOperatorType *, void *), void *userdata) RET_NONE void WM_operator_bl_idname(char *to, const char *from) RET_NONE void WM_operator_py_idname(char *to, const char *from) RET_NONE +bool WM_operator_py_idname_ok_or_report(struct ReportList *reports, const char *classname, const char *idname) RET_ZERO int WM_operator_ui_popup(struct bContext *C, struct wmOperator *op, int width, int height) RET_ZERO void update_autoflags_fcurve(struct FCurve *fcu, struct bContext *C, struct ReportList *reports, struct PointerRNA *ptr) RET_NONE short insert_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, char keytype, short flag) RET_ZERO diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 8f26e248424..54a212f805b 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -607,7 +607,7 @@ if(UNIX AND NOT APPLE) PATTERN "*.pyo" EXCLUDE # * any cache * ) # On some platforms requests does have extra dependencies. - set(_requests_deps "chardet" "urllib3") + set(_requests_deps "certifi" "chardet" "idna" "urllib3") foreach(_requests_dep ${_requests_deps}) if(EXISTS ${PYTHON_REQUESTS_PATH}/${_requests_dep}) install( @@ -701,7 +701,7 @@ elseif(WIN32) ) if(WITH_PYTHON_INSTALL_NUMPY) - set(PYTHON_NUMPY_VERSION 1.10) + set(PYTHON_NUMPY_VERSION 1.13) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages) @@ -845,6 +845,13 @@ elseif(APPLE) PATTERN "__MACOSX" EXCLUDE PATTERN ".DS_Store" EXCLUDE PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib + PATTERN "lib2to3" EXCLUDE # ./lib2to3 + PATTERN "tkinter" EXCLUDE # ./tkinter + PATTERN "lib-dynload/_tkinter.*" EXCLUDE # ./lib-dynload/_tkinter.co + PATTERN "idlelib" EXCLUDE # ./idlelib + PATTERN "test" EXCLUDE # ./test + PATTERN "turtledemo" EXCLUDE # ./turtledemo + PATTERN "turtle.py" EXCLUDE # ./turtle.py ) endmacro() @@ -908,40 +915,10 @@ elseif(APPLE) # python if(WITH_PYTHON AND NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK) - # the python zip is first extracted as part of the build process, - # and then later installed as part of make install. this is much - # quicker, and means we can easily exclude files on copy - # Not needed for PYTHON_MODULE or WEB_PLUGIN due uses Pyhon framework - # use a hash of the .zip path to handle switching between different - # lib directories without needing a clean build - string(SHA1 PYTHON_ZIP_HASH ${LIBDIR}/release/${PYTHON_ZIP}) - set(PYTHON_EXTRACT_DIR ${CMAKE_CURRENT_BINARY_DIR}/${PYTHON_ZIP_HASH}/python) - - add_custom_target( - extractpyzip - DEPENDS ${PYTHON_EXTRACT_DIR}) - - set(PYTHON_ZIP "python_${CMAKE_OSX_ARCHITECTURES}.zip") - - add_custom_command( - OUTPUT ${PYTHON_EXTRACT_DIR} - COMMAND ${CMAKE_COMMAND} -E remove_directory "${PYTHON_EXTRACT_DIR}/" - COMMAND ${CMAKE_COMMAND} -E make_directory "${PYTHON_EXTRACT_DIR}/" - COMMAND ${CMAKE_COMMAND} -E chdir "${PYTHON_EXTRACT_DIR}/" - ${CMAKE_COMMAND} -E tar xzfv "${LIBDIR}/release/${PYTHON_ZIP}" - DEPENDS ${LIBDIR}/release/${PYTHON_ZIP}) - - add_dependencies(blender extractpyzip) - - # copy extracted python files + # Copy the python libs into the install directory install_dir( - ${PYTHON_EXTRACT_DIR} - \${TARGETDIR_VER} - ) - # copy site-packages files - install_dir( - ${LIBDIR}/release/site-packages - \${TARGETDIR_VER}/python/lib/python${PYTHON_VERSION} + ${PYTHON_LIBPATH} + ${TARGETDIR_VER}/python/lib ) install(DIRECTORY ${LIBDIR}/python/bin @@ -997,18 +974,10 @@ elseif(APPLE) # python if(WITH_PYTHON AND NOT WITH_PYTHON_FRAMEWORK) - add_custom_command( - OUTPUT ${PYTHON_EXTRACT_DIR} - COMMAND ${CMAKE_COMMAND} -E remove_directory "${PYTHON_EXTRACT_DIR}/" - COMMAND ${CMAKE_COMMAND} -E make_directory "${PYTHON_EXTRACT_DIR}/" - COMMAND ${CMAKE_COMMAND} -E chdir "${PYTHON_EXTRACT_DIR}/" - ${CMAKE_COMMAND} -E tar xzfv "${LIBDIR}/release/${PYTHON_ZIP}" - DEPENDS ${LIBDIR}/release/${PYTHON_ZIP}) - - # copy extracted python files + # Copy the python libs into the install directory install_dir( - ${PYTHON_EXTRACT_DIR} - \${PLAYER_TARGETDIR_VER} + ${PYTHON_LIBPATH} + ${PLAYER_TARGETDIR_VER}/python/lib ) endif() diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 658a0b2db08..83e8bbb9ef3 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -1129,7 +1129,7 @@ static const char arg_handle_image_type_set_doc[] = "\t\tTGA RAWTGA JPEG IRIS IRIZ\n" "\t\tAVIRAW AVIJPEG PNG BMP\n" "\t(formats that can be compiled into blender, not available on all systems)\n" -"\t\tHDR TIFF EXR MULTILAYER MPEG FRAMESERVER QUICKTIME CINEON DPX DDS JP2" +"\t\tHDR TIFF EXR MULTILAYER MPEG FRAMESERVER CINEON DPX DDS JP2" ; static int arg_handle_image_type_set(int argc, const char **argv, void *data) { @@ -1362,7 +1362,7 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data) return 1; } - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); BLI_begin_threaded_malloc(); BKE_reports_init(&reports, RPT_STORE); @@ -1404,7 +1404,7 @@ static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(arg Scene *scene = CTX_data_scene(C); if (scene) { Main *bmain = CTX_data_main(C); - Render *re = RE_NewRender(scene->id.name); + Render *re = RE_NewSceneRender(scene); ReportList reports; BLI_begin_threaded_malloc(); BKE_reports_init(&reports, RPT_STORE); diff --git a/source/gameengine/GameLogic/CMakeLists.txt b/source/gameengine/GameLogic/CMakeLists.txt index 05071f59707..b9eec74f6f4 100644 --- a/source/gameengine/GameLogic/CMakeLists.txt +++ b/source/gameengine/GameLogic/CMakeLists.txt @@ -139,6 +139,9 @@ if(WITH_SDL) if(WITH_GHOST_SDL) add_definitions(-DWITH_GHOST_SDL) endif() + if(WITH_SDL_DYNLOAD) + add_definitions(-DWITH_SDL_DYNLOAD) + endif() endif() blender_add_lib(ge_logic "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp index 1a66b2aee52..9f532527a80 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp @@ -38,7 +38,11 @@ #include "BLI_path_util.h" #ifdef WITH_SDL -# define SDL_CHECK(x) ((x) != (void *)0) +# ifdef WITH_SDL_DYNLOAD +# define SDL_CHECK(x) ((x) != (void *)0) +# else +# define SDL_CHECK(x) true +# endif #endif SCA_Joystick::SCA_Joystick(short int index) diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp index fd3d713b3d2..1dee1de9de2 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp @@ -82,9 +82,11 @@ void SCA_Joystick::HandleEvents(void) { SDL_Event sdl_event; +#ifdef WITH_SDL_DYNLOAD if (SDL_PollEvent == (void*)0) { return; } +#endif int i; for (i=0; i<m_joynum; i++) { /* could use JOYINDEX_MAX but no reason to */ diff --git a/source/gameengine/Ketsji/KX_FontObject.cpp b/source/gameengine/Ketsji/KX_FontObject.cpp index 364f8d4bfc6..91e8e4fd42b 100644 --- a/source/gameengine/Ketsji/KX_FontObject.cpp +++ b/source/gameengine/Ketsji/KX_FontObject.cpp @@ -281,7 +281,7 @@ int KX_FontObject::pyattr_set_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrd KX_FontObject* self = static_cast<KX_FontObject*>(self_v); if (!PyUnicode_Check(value)) return PY_SET_ATTR_FAIL; - char* chars = _PyUnicode_AsString(value); + const char *chars = _PyUnicode_AsString(value); /* Allow for some logic brick control */ CValue* tprop = self->GetProperty("Text"); diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 97a7e161e9f..5540aad7a3f 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -40,11 +40,6 @@ # ifdef _XOPEN_SOURCE # undef _XOPEN_SOURCE # endif -# if defined(__sun) || defined(sun) -# if defined(_XPG4) -# undef _XPG4 -# endif -# endif # include <Python.h> extern "C" { diff --git a/source/gameengine/VideoTexture/FilterBase.cpp b/source/gameengine/VideoTexture/FilterBase.cpp index 5717a1edbcb..b41a2095890 100644 --- a/source/gameengine/VideoTexture/FilterBase.cpp +++ b/source/gameengine/VideoTexture/FilterBase.cpp @@ -114,6 +114,7 @@ void Filter_dealloc(PyFilter *self) delete self->m_filter; self->m_filter = NULL; } + Py_TYPE((PyObject *)self)->tp_free((PyObject *)self); } diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp index b91a312a5d7..a547d2a7a85 100644 --- a/source/gameengine/VideoTexture/ImageBase.cpp +++ b/source/gameengine/VideoTexture/ImageBase.cpp @@ -427,6 +427,7 @@ void Image_dealloc(PyImage *self) delete self->m_image; self->m_image = NULL; } + Py_TYPE((PyObject *)self)->tp_free((PyObject *)self); } // get image data diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fa0b86a2637..64326f34377 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,8 @@ # Python CTests -add_subdirectory(python) +if(WITH_BLENDER) + add_subdirectory(python) +endif() # GTest add_subdirectory(gtests) - diff --git a/tests/check_deprecated.py b/tests/check_deprecated.py index cf8f8e0cc35..6e07f8fdb31 100644 --- a/tests/check_deprecated.py +++ b/tests/check_deprecated.py @@ -53,10 +53,8 @@ def is_source_any(filename): def source_list(path, filename_check=None): for dirpath, dirnames, filenames in os.walk(path): - - # skip '.svn' - if dirpath.startswith("."): - continue + # skip '.git' + dirnames[:] = [d for d in dirnames if not d.startswith(".")] for filename in filenames: if filename_check is None or filename_check(filename): diff --git a/tests/gtests/blenlib/BLI_array_utils_test.cc b/tests/gtests/blenlib/BLI_array_utils_test.cc index 518cd097326..c4601e00fbd 100644 --- a/tests/gtests/blenlib/BLI_array_utils_test.cc +++ b/tests/gtests/blenlib/BLI_array_utils_test.cc @@ -5,7 +5,7 @@ extern "C" { #include "BLI_utildefines.h" #include "BLI_array_utils.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" } /* -------------------------------------------------------------------- */ diff --git a/tests/gtests/blenlib/BLI_kdopbvh_test.cc b/tests/gtests/blenlib/BLI_kdopbvh_test.cc index e713ddc1695..74db7cf20a0 100644 --- a/tests/gtests/blenlib/BLI_kdopbvh_test.cc +++ b/tests/gtests/blenlib/BLI_kdopbvh_test.cc @@ -12,6 +12,8 @@ extern "C" { #include "MEM_guardedalloc.h" } +#include "stubs/bf_intern_eigen_stubs.h" + /* -------------------------------------------------------------------- */ /* Helper Functions */ diff --git a/tests/gtests/blenlib/BLI_math_geom_test.cc b/tests/gtests/blenlib/BLI_math_geom_test.cc index cd15a4eb8ff..92e2532392e 100644 --- a/tests/gtests/blenlib/BLI_math_geom_test.cc +++ b/tests/gtests/blenlib/BLI_math_geom_test.cc @@ -4,6 +4,8 @@ #include "BLI_math.h" +#include "stubs/bf_intern_eigen_stubs.h" + TEST(math_geom, DistToLine2DSimple) { float p[2] = {5.0f, 1.0f}, diff --git a/tests/gtests/blenlib/BLI_polyfill2d_test.cc b/tests/gtests/blenlib/BLI_polyfill2d_test.cc index 5d112751fa0..df98ead4cb9 100644 --- a/tests/gtests/blenlib/BLI_polyfill2d_test.cc +++ b/tests/gtests/blenlib/BLI_polyfill2d_test.cc @@ -27,6 +27,8 @@ extern "C" { #endif } +#include "stubs/bf_intern_eigen_stubs.h" + static void polyfill_to_obj( const char *id, const float poly[][2], const unsigned int poly_tot, @@ -208,6 +210,26 @@ static void test_polyfill_template( #endif } +static void test_polyfill_template_flip_sign( + const char *id, bool is_degenerate, + const float poly[][2], const unsigned int poly_tot, + unsigned int tris[][3], const unsigned int tris_tot) +{ + float (*poly_copy)[2] = (float (*)[2])MEM_mallocN(sizeof(float[2]) * poly_tot, id); + for (int flip_x = 0; flip_x < 2; flip_x++) { + for (int flip_y = 0; flip_y < 2; flip_y++) { + float sign_x = flip_x ? -1.0f : 1.0f; + float sign_y = flip_y ? -1.0f : 1.0f; + for (int i = 0; i < poly_tot; i++) { + poly_copy[i][0] = poly[i][0] * sign_x; + poly_copy[i][1] = poly[i][1] * sign_y; + } + test_polyfill_template(id, is_degenerate, poly_copy, poly_tot, tris, tris_tot); + } + } + MEM_freeN(poly_copy); +} + #ifdef USE_COMBINATIONS_ALL static void test_polyfill_template_main( const char *id, bool is_degenerate, @@ -230,7 +252,7 @@ static void test_polyfill_template_main( for (poly_cycle = 0; poly_cycle < poly_tot; poly_cycle++) { // printf("polytest %s ofs=%d, reverse=%d\n", id, poly_cycle, poly_reverse); - test_polyfill_template(id, is_degenerate, poly, poly_tot, tris, tris_tot); + test_polyfill_template_flip_sign(id, is_degenerate, poly, poly_tot, tris, tris_tot); /* cycle */ copy_v2_v2(tmp, poly_copy[0]); @@ -247,7 +269,7 @@ static void test_polyfill_template_main( const float poly[][2], const unsigned int poly_tot, unsigned int tris[][3], const unsigned int tris_tot) { - test_polyfill_template(id, is_degenerate, poly, poly_tot, tris, tris_tot); + test_polyfill_template_flip_sign(id, is_degenerate, poly, poly_tot, tris, tris_tot); } #endif /* USE_COMBINATIONS_ALL */ @@ -307,6 +329,43 @@ static void polyfill_to_obj( /* -------------------------------------------------------------------- */ /* tests */ +/** + * Script to generate the data below: + * + * \code{.py} + * # This example assumes we have a mesh object in edit-mode + * + * import bpy + * import bmesh + * + * obj = bpy.context.edit_object + * me = obj.data + * bm = bmesh.from_edit_mesh(me) + * + * def clean_float(num): + * if int(num) == num: + * return str(int(num)) + * prec = 1 + * while True: + * text = f"{num:.{prec}f}" + * if float(text) == num: + * return text + * prec += 1 + * + * for f in bm.faces: + * if f.select: + * print(f"\t// data for face: {f.index}") + * print("\tconst float poly[][2] = {", end="") + * coords = [[clean_float(num) for num in l.vert.co[0:2]] for l in f.loops] + * print("\t ", end="") + * for i, (x, y) in enumerate(coords): + * if (i % 2) == 0: + * print("\n\t ", end="") + * print(f"{{{x}, {y}}}", end=",") + * print("\n\t};") + * \endcode + */ + #define POLY_TRI_COUNT(len) ((len) - 2) @@ -517,3 +576,17 @@ TEST(polyfill2d, IssueT41986_axis_align) TEST_POLYFILL_TEMPLATE_STATIC(poly, false); } + +/* Blender bug T52834 */ +TEST(polyfill2d, IssueT52834_axis_align_co_linear) +{ + const float poly[][2] = { + {40, 0}, {36, 0}, {36, 5}, {35, 5}, {35, 0}, {30, 0}, {30, 5}, {29, 5}, {29, 0}, {24, 0}, {24, 3}, + {23, 4}, {23, 0}, {18, 0}, {18, 5}, {17, 5}, {17, 0}, {12, 0}, {12, 5}, {11, 5}, {11, 0}, {6, 0}, + {6, 5}, {5, 5}, {5, 0}, {0, 0}, {0, 5}, {-1, 5}, {-1, 0}, {-6, 0}, {-9, -3}, {-6, -3}, {-6, -2}, + {-1, -2}, {0, -2}, {5, -2}, {6, -2}, {11, -2}, {12, -2}, {17, -2}, {18, -2}, {23, -2}, {24, -2}, + {29, -2}, {30, -2}, {35, -2}, {36, -2}, {40, -2}, + }; + + TEST_POLYFILL_TEMPLATE_STATIC(poly, false); +} diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt index 8b013e7a7a6..ffdb8d08d31 100644 --- a/tests/gtests/blenlib/CMakeLists.txt +++ b/tests/gtests/blenlib/CMakeLists.txt @@ -34,24 +34,27 @@ include_directories(${INC}) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}") +if(WIN32) + set(BLI_path_util_extra_libs "bf_blenlib;bf_intern_utfconv;extern_wcwidth;${ZLIB_LIBRARIES}") +else() + set(BLI_path_util_extra_libs "bf_blenlib;extern_wcwidth;${ZLIB_LIBRARIES}") +endif() BLENDER_TEST(BLI_array_store "bf_blenlib") BLENDER_TEST(BLI_array_utils "bf_blenlib") -BLENDER_TEST(BLI_kdopbvh "bf_blenlib;bf_intern_eigen") -BLENDER_TEST(BLI_stack "bf_blenlib") -BLENDER_TEST(BLI_math_color "bf_blenlib") -BLENDER_TEST(BLI_math_geom "bf_blenlib;bf_intern_eigen") +BLENDER_TEST(BLI_ghash "bf_blenlib") +BLENDER_TEST(BLI_hash_mm2a "bf_blenlib") +BLENDER_TEST(BLI_kdopbvh "bf_blenlib") +BLENDER_TEST(BLI_listbase "bf_blenlib") BLENDER_TEST(BLI_math_base "bf_blenlib") +BLENDER_TEST(BLI_math_color "bf_blenlib") +BLENDER_TEST(BLI_math_geom "bf_blenlib") +BLENDER_TEST(BLI_path_util "${BLI_path_util_extra_libs}") +BLENDER_TEST(BLI_polyfill2d "bf_blenlib") +BLENDER_TEST(BLI_stack "bf_blenlib") BLENDER_TEST(BLI_string "bf_blenlib") BLENDER_TEST(BLI_string_utf8 "bf_blenlib") -if(WIN32) - BLENDER_TEST(BLI_path_util "bf_blenlib;bf_intern_utfconv;extern_wcwidth;${ZLIB_LIBRARIES}") -else() - BLENDER_TEST(BLI_path_util "bf_blenlib;extern_wcwidth;${ZLIB_LIBRARIES}") -endif() -BLENDER_TEST(BLI_polyfill2d "bf_blenlib;bf_intern_eigen") -BLENDER_TEST(BLI_listbase "bf_blenlib") -BLENDER_TEST(BLI_hash_mm2a "bf_blenlib") -BLENDER_TEST(BLI_ghash "bf_blenlib") BLENDER_TEST_PERFORMANCE(BLI_ghash_performance "bf_blenlib") + +unset(BLI_path_util_extra_libs) diff --git a/tests/gtests/blenlib/stubs/bf_intern_eigen_stubs.h b/tests/gtests/blenlib/stubs/bf_intern_eigen_stubs.h new file mode 100644 index 00000000000..dad77a257d5 --- /dev/null +++ b/tests/gtests/blenlib/stubs/bf_intern_eigen_stubs.h @@ -0,0 +1,18 @@ +/* Apache License, Version 2.0 */ + +extern "C" { + +bool EIG_self_adjoint_eigen_solve(const int size, const float *matrix, float *r_eigen_values, float *r_eigen_vectors) +{ + BLI_assert(0); + UNUSED_VARS(size, matrix, r_eigen_values, r_eigen_vectors); + return false; +} + +void EIG_svd_square_matrix(const int size, const float *matrix, float *r_U, float *r_S, float *r_V) +{ + BLI_assert(0); + UNUSED_VARS(size, matrix, r_U, r_S, r_V); +} + +} diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index 9e1ebcbe669..7e42f36c6e4 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -39,78 +39,101 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_OUT_DIR}) # all calls to blender use this if(APPLE) if(${CMAKE_GENERATOR} MATCHES "Xcode") - set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/Debug/blender.app/Contents/MacOS/blender) + set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup) else() - set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/blender.app/Contents/MacOS/blender) + set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) endif() else() - set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/blender) + set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) endif() # for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no -set(TEST_BLENDER_EXE_BARE ${TEST_BLENDER_EXE}) -set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) -set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} ${TEST_BLENDER_EXE_PARAMS} ) +# set(TEST_BLENDER_EXE_BARE ${TEST_BLENDER_EXE}) +# set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} ${TEST_BLENDER_EXE_PARAMS} ) # ------------------------------------------------------------------------------ # GENERAL PYTHON CORRECTNESS TESTS -add_test(script_load_keymap ${TEST_BLENDER_EXE} +add_test( + NAME script_load_keymap + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_keymap_completeness.py ) -add_test(script_load_addons ${TEST_BLENDER_EXE} +add_test( + NAME script_load_addons + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_load_addons.py ) -add_test(script_load_modules ${TEST_BLENDER_EXE} +add_test( + NAME script_load_modules + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_load_py_modules.py ) # test running operators doesn't segfault under various conditions if(USE_EXPERIMENTAL_TESTS) - add_test(script_run_operators ${TEST_BLENDER_EXE} + add_test( + NAME script_run_operators + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_run_operators.py ) endif() # ------------------------------------------------------------------------------ # PY API TESTS -add_test(script_pyapi_bpy_path ${TEST_BLENDER_EXE} +add_test( + NAME script_pyapi_bpy_path + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_bpy_path.py ) -add_test(script_pyapi_bpy_utils_units ${TEST_BLENDER_EXE} +add_test( + NAME script_pyapi_bpy_utils_units + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_bpy_utils_units.py ) -add_test(script_pyapi_mathutils ${TEST_BLENDER_EXE} +add_test( + NAME script_pyapi_mathutils + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_mathutils.py ) -add_test(script_pyapi_idprop ${TEST_BLENDER_EXE} +add_test( + NAME script_pyapi_idprop + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_idprop.py ) -add_test(script_pyapi_idprop_datablock ${TEST_BLENDER_EXE} +add_test( + NAME script_pyapi_idprop_datablock + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_idprop_datablock.py ) # ------------------------------------------------------------------------------ # MODELING TESTS -add_test(bevel ${TEST_BLENDER_EXE} +add_test( + NAME bevel + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/modeling/bevel_regression.blend --python-text run_tests ) -add_test(split_faces ${TEST_BLENDER_EXE} +add_test( + NAME split_faces + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/modeling/split_faces_test.blend --python-text run_tests ) # ------------------------------------------------------------------------------ # MODIFIERS TESTS -add_test(modifier_array ${TEST_BLENDER_EXE} +add_test( + NAME modifier_array + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/modifier_stack/array_test.blend --python-text run_tests ) @@ -121,21 +144,27 @@ add_test(modifier_array ${TEST_BLENDER_EXE} # OBJ Import tests # disabled until updated & working if(FALSE) -add_test(import_obj_cube ${TEST_BLENDER_EXE} +add_test( + NAME import_obj_cube + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/cube.obj'\) --md5=39cce4bacac2d1b18fc470380279bc15 --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_obj_cube.blend ) -add_test(import_obj_nurbs_cyclic ${TEST_BLENDER_EXE} +add_test( + NAME import_obj_nurbs_cyclic + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/nurbs_cyclic.obj'\) --md5=ad3c307e5883224a0492378cd32691ab --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_obj_nurbs_cyclic.blend ) -add_test(import_obj_makehuman ${TEST_BLENDER_EXE} +add_test( + NAME import_obj_makehuman + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/makehuman.obj'\) --md5=c9f78b185e58358daa4ecaecfa75464e --md5_method=SCENE @@ -144,7 +173,9 @@ add_test(import_obj_makehuman ${TEST_BLENDER_EXE} endif() # OBJ Export tests -add_test(export_obj_cube ${TEST_BLENDER_EXE} +add_test( + NAME export_obj_cube + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_cube.obj',use_selection=False\) @@ -153,7 +184,9 @@ add_test(export_obj_cube ${TEST_BLENDER_EXE} --md5=e80660437ad9bfe082849641c361a233 --md5_method=FILE ) -add_test(export_obj_nurbs ${TEST_BLENDER_EXE} +add_test( + NAME export_obj_nurbs + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_nurbs.obj',use_selection=False,use_nurbs=True\) @@ -164,7 +197,9 @@ add_test(export_obj_nurbs ${TEST_BLENDER_EXE} # disabled until updated & working if(FALSE) -add_test(export_obj_all_objects ${TEST_BLENDER_EXE} +add_test( + NAME export_obj_all_objects + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_all_objects.obj',use_selection=False,use_nurbs=True\) @@ -177,21 +212,27 @@ endif() # PLY Import tests -add_test(import_ply_cube ${TEST_BLENDER_EXE} +add_test( + NAME import_ply_cube + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_mesh.ply\(filepath='${TEST_SRC_DIR}/io_tests/ply/cube_ascii.ply'\) --md5=527134343c27fc0ea73115b85fbfd3ac --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_ply_cube.blend ) -add_test(import_ply_bunny ${TEST_BLENDER_EXE} +add_test( + NAME import_ply_bunny + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_mesh.ply\(filepath='${TEST_SRC_DIR}/io_tests/ply/bunny2.ply'\) --md5=6ea5b8533400a17accf928b8fd024eaa --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_ply_bunny.blend ) -add_test(import_ply_small_holes ${TEST_BLENDER_EXE} +add_test( + NAME import_ply_small_holes + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_mesh.ply\(filepath='${TEST_SRC_DIR}/io_tests/ply/many_small_holes.ply'\) --md5=c3093e26ecae5b6d59fbbcf2a0d0b39f --md5_method=SCENE @@ -201,7 +242,9 @@ add_test(import_ply_small_holes ${TEST_BLENDER_EXE} # PLY Export # disabled until updated & working if(FALSE) -add_test(export_ply_cube_all_data ${TEST_BLENDER_EXE} +add_test( + NAME export_ply_cube_all_data + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/cube_all_data.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_mesh.ply\(filepath='${TEST_OUT_DIR}/export_ply_cube_all_data.ply'\) @@ -209,7 +252,9 @@ add_test(export_ply_cube_all_data ${TEST_BLENDER_EXE} --md5=6adc3748ceae8298496f99d0e7e76c15 --md5_method=FILE ) -add_test(export_ply_suzanne_all_data ${TEST_BLENDER_EXE} +add_test( + NAME export_ply_suzanne_all_data + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/suzanne_all_data.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_mesh.ply\(filepath='${TEST_OUT_DIR}/export_ply_suzanne_all_data.ply'\) @@ -218,7 +263,9 @@ add_test(export_ply_suzanne_all_data ${TEST_BLENDER_EXE} ) endif() -add_test(export_ply_vertices ${TEST_BLENDER_EXE} # lame, add a better one +add_test( + NAME export_ply_vertices # lame, add a better one + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/vertices.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_mesh.ply\(filepath='${TEST_OUT_DIR}/export_ply_vertices.ply'\) @@ -230,21 +277,27 @@ add_test(export_ply_vertices ${TEST_BLENDER_EXE} # lame, add a better one # STL Import tests # disabled until updated & working if(FALSE) -add_test(import_stl_cube ${TEST_BLENDER_EXE} +add_test( + NAME import_stl_cube + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/cube.stl'\) --md5=8ceb5bb7e1cb5f4342fa1669988c66b4 --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_stl_cube.blend ) -add_test(import_stl_conrod ${TEST_BLENDER_EXE} +add_test( + NAME import_stl_conrod + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/conrod.stl'\) --md5=690a4b8eb9002dcd8631c5a575ea7348 --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_stl_conrod.blend ) -add_test(import_stl_knot_max_simplified ${TEST_BLENDER_EXE} +add_test( + NAME import_stl_knot_max_simplified + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/knot_max_simplified.stl'\) --md5=baf82803f45a84ec4ddbad9cef57dd3e --md5_method=SCENE @@ -255,7 +308,9 @@ endif() # STL Export # disabled until updated & working if(FALSE) -add_test(export_stl_cube_all_data ${TEST_BLENDER_EXE} +add_test( + NAME export_stl_cube_all_data + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/cube_all_data.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_mesh.stl\(filepath='${TEST_OUT_DIR}/export_stl_cube_all_data.stl'\) @@ -263,7 +318,9 @@ add_test(export_stl_cube_all_data ${TEST_BLENDER_EXE} --md5=64cb97c0cabb015e1c3f76369835075a --md5_method=FILE ) -add_test(export_stl_suzanne_all_data ${TEST_BLENDER_EXE} +add_test( + NAME export_stl_suzanne_all_data + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/suzanne_all_data.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_mesh.stl\(filepath='${TEST_OUT_DIR}/export_stl_suzanne_all_data.stl'\) @@ -271,7 +328,9 @@ add_test(export_stl_suzanne_all_data ${TEST_BLENDER_EXE} --md5=e9b23c97c139ad64961c635105bb9192 --md5_method=FILE ) -add_test(export_stl_vertices ${TEST_BLENDER_EXE} # lame, add a better one +add_test( + NAME export_stl_vertices # lame, add a better one + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/vertices.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_mesh.stl\(filepath='${TEST_OUT_DIR}/export_stl_vertices.stl'\) @@ -284,21 +343,27 @@ endif() # X3D Import # disabled until updated & working if(FALSE) -add_test(import_x3d_cube ${TEST_BLENDER_EXE} +add_test( + NAME import_x3d_cube + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/color_cube.x3d'\) --md5=3fae9be004199c145941cd3f9f80ad7b --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_x3d_cube.blend ) -add_test(import_x3d_teapot ${TEST_BLENDER_EXE} +add_test( + NAME import_x3d_teapot + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/teapot.x3d'\) --md5=8ee196c71947dce4199d55698501691e --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_x3d_teapot.blend ) -add_test(import_x3d_suzanne_material ${TEST_BLENDER_EXE} +add_test( + NAME import_x3d_suzanne_material + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/suzanne_material.x3d'\) --md5=3edea1353257d8b5a5f071942f417be6 --md5_method=SCENE @@ -306,7 +371,9 @@ add_test(import_x3d_suzanne_material ${TEST_BLENDER_EXE} ) # X3D Export -add_test(export_x3d_cube ${TEST_BLENDER_EXE} +add_test( + NAME export_x3d_cube + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_cube.x3d',use_selection=False\) @@ -314,7 +381,9 @@ add_test(export_x3d_cube ${TEST_BLENDER_EXE} --md5=05312d278fe41da33560fdfb9bdb268f --md5_method=FILE ) -add_test(export_x3d_nurbs ${TEST_BLENDER_EXE} +add_test( + NAME export_x3d_nurbs + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_nurbs.x3d',use_selection=False\) @@ -322,7 +391,9 @@ add_test(export_x3d_nurbs ${TEST_BLENDER_EXE} --md5=4286d4a2aa507ef78b22ddcbdcc88481 --md5_method=FILE ) -add_test(export_x3d_all_objects ${TEST_BLENDER_EXE} +add_test( + NAME export_x3d_all_objects + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_all_objects.x3d',use_selection=False\) @@ -336,21 +407,27 @@ endif() # 3DS Import # disabled until updated & working if(FALSE) -add_test(import_3ds_cube ${TEST_BLENDER_EXE} +add_test( + NAME import_3ds_cube + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/cube.3ds'\) --md5=cb5a45c35a343c3f5beca2a918472951 --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_3ds_cube.blend ) -add_test(import_3ds_hierarchy_lara ${TEST_BLENDER_EXE} +add_test( + NAME import_3ds_hierarchy_lara + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/hierarchy_lara.3ds'\) --md5=766c873d9fdb5f190e43796cfbae63b6 --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_3ds_hierarchy_lara.blend ) -add_test(import_3ds_hierarchy_greek_trireme ${TEST_BLENDER_EXE} +add_test( + NAME import_3ds_hierarchy_greek_trireme + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/hierarchy_greek_trireme.3ds'\) --md5=b62ee30101e8999cb91ef4f8a8760056 --md5_method=SCENE @@ -361,7 +438,9 @@ endif() # 3DS Export # disabled until updated & working if(FALSE) -add_test(export_3ds_cube ${TEST_BLENDER_EXE} +add_test( + NAME export_3ds_cube + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_cube.3ds',use_selection=False\) @@ -369,7 +448,9 @@ add_test(export_3ds_cube ${TEST_BLENDER_EXE} --md5=a31f5071b6c6dc7445b9099cdc7f63b3 --md5_method=FILE ) -add_test(export_3ds_nurbs ${TEST_BLENDER_EXE} +add_test( + NAME export_3ds_nurbs + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_nurbs.3ds',use_selection=False\) @@ -377,7 +458,9 @@ add_test(export_3ds_nurbs ${TEST_BLENDER_EXE} --md5=5bdd21be3c80d814fbc83cb25edb08c2 --md5_method=FILE ) -add_test(export_3ds_all_objects ${TEST_BLENDER_EXE} +add_test( + NAME export_3ds_all_objects + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_all_objects.3ds',use_selection=False\) @@ -392,7 +475,9 @@ endif() # 'use_metadata=False' for reliable md5's # disabled until updated & working if(FALSE) -add_test(export_fbx_cube ${TEST_BLENDER_EXE} +add_test( + NAME export_fbx_cube + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_cube.fbx',use_selection=False,use_metadata=False\) @@ -400,7 +485,9 @@ add_test(export_fbx_cube ${TEST_BLENDER_EXE} --md5=59a35577462f95f9a0b4e6035226ce9b --md5_method=FILE ) -add_test(export_fbx_nurbs ${TEST_BLENDER_EXE} +add_test( + NAME export_fbx_nurbs + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_nurbs.fbx',use_selection=False,use_metadata=False\) @@ -408,7 +495,9 @@ add_test(export_fbx_nurbs ${TEST_BLENDER_EXE} --md5=d31875f18f613fa0c3b16e978f87f6f8 --md5_method=FILE ) -add_test(export_fbx_all_objects ${TEST_BLENDER_EXE} +add_test( + NAME export_fbx_all_objects + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_all_objects.fbx',use_selection=False,use_metadata=False\) @@ -421,31 +510,44 @@ if(WITH_CYCLES) if(OPENIMAGEIO_IDIFF AND EXISTS "${TEST_SRC_DIR}/cycles/ctests/shader") macro(add_cycles_render_test subject) if(MSVC) - add_test(NAME cycles_${subject}_test + add_test( + NAME cycles_${subject}_test COMMAND "$<TARGET_FILE_DIR:blender>/${BLENDER_VERSION_MAJOR}.${BLENDER_VERSION_MINOR}/python/bin/python$<$<CONFIG:Debug>:_d>" ${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py -blender "$<TARGET_FILE:blender>" -testdir "${TEST_SRC_DIR}/cycles/ctests/${subject}" -idiff "${OPENIMAGEIO_IDIFF}" + -outdir "${TEST_OUT_DIR}/cycles" ) else() - add_test(cycles_${subject}_test - ${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py - -blender "${TEST_BLENDER_EXE_BARE}" + add_test( + NAME cycles_${subject}_test + COMMAND ${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py + -blender "$<TARGET_FILE:blender>" -testdir "${TEST_SRC_DIR}/cycles/ctests/${subject}" -idiff "${OPENIMAGEIO_IDIFF}" + -outdir "${TEST_OUT_DIR}/cycles" ) endif() endmacro() if(WITH_OPENGL_TESTS) add_cycles_render_test(opengl) endif() - add_cycles_render_test(image) + add_cycles_render_test(bake) + add_cycles_render_test(denoise) + add_cycles_render_test(displacement) + add_cycles_render_test(image_data_types) + add_cycles_render_test(image_mapping) + add_cycles_render_test(image_texture_limit) + add_cycles_render_test(light) add_cycles_render_test(mblur) add_cycles_render_test(reports) add_cycles_render_test(render) add_cycles_render_test(shader) + add_cycles_render_test(shader_tangent) + add_cycles_render_test(shadow_catcher) + add_cycles_render_test(volume) else() MESSAGE(STATUS "Disabling Cycles tests because tests folder does not exist") endif() @@ -460,7 +562,9 @@ if(WITH_ALEMBIC) get_filename_component(ALEMBIC_ROOT_DIR ${real_include_dir} DIRECTORY) if(MSVC) - add_test(NAME alembic_tests + # FIXME, de-duplicate. + add_test( + NAME alembic_tests COMMAND "$<TARGET_FILE_DIR:blender>/${BLENDER_VERSION_MAJOR}.${BLENDER_VERSION_MINOR}/python/bin/python$<$<CONFIG:Debug>:_d>" ${CMAKE_CURRENT_LIST_DIR}/alembic_tests.py @@ -468,28 +572,22 @@ if(WITH_ALEMBIC) --testdir "${TEST_SRC_DIR}/alembic" --alembic-root "${ALEMBIC_ROOT_DIR}" ) - add_test(NAME script_alembic_import - COMMAND - "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} - --python ${CMAKE_CURRENT_LIST_DIR}/bl_alembic_import_test.py - -- - --testdir "${TEST_SRC_DIR}/alembic" - --with-legacy-depsgraph=${WITH_LEGACY_DEPSGRAPH} - ) - else() - add_test(alembic_tests - ${CMAKE_CURRENT_LIST_DIR}/alembic_tests.py - --blender "${TEST_BLENDER_EXE_BARE}" + add_test( + NAME alembic_tests + COMMAND ${CMAKE_CURRENT_LIST_DIR}/alembic_tests.py + --blender "$<TARGET_FILE:blender>" --testdir "${TEST_SRC_DIR}/alembic" --alembic-root "${ALEMBIC_ROOT_DIR}" ) - add_test(script_alembic_import ${TEST_BLENDER_EXE} + endif() + + add_test( + NAME script_alembic_import + COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} --python ${CMAKE_CURRENT_LIST_DIR}/bl_alembic_import_test.py -- --testdir "${TEST_SRC_DIR}/alembic" --with-legacy-depsgraph=${WITH_LEGACY_DEPSGRAPH} - ) - - endif() + ) endif() diff --git a/tests/python/batch_import.py b/tests/python/batch_import.py index bbe3a70327f..a6e2469349b 100644 --- a/tests/python/batch_import.py +++ b/tests/python/batch_import.py @@ -72,10 +72,8 @@ def batch_import( def file_generator(path): for dirpath, dirnames, filenames in os.walk(path): - - # skip '.svn' - if dirpath.startswith("."): - continue + # skip '.git' + dirnames[:] = [d for d in dirnames if not d.startswith(".")] for filename in filenames: if pattern_match(filename): diff --git a/tests/python/bl_alembic_import_test.py b/tests/python/bl_alembic_import_test.py index f45748f86e7..c3a4af26e11 100644 --- a/tests/python/bl_alembic_import_test.py +++ b/tests/python/bl_alembic_import_test.py @@ -179,22 +179,24 @@ class SimpleImportTest(AbstractAlembicTest): res = bpy.ops.wm.alembic_import(filepath=str(abc), as_background_job=False) self.assertEqual({'FINISHED'}, res) - cube = bpy.context.active_object + plane = bpy.context.active_object # Check that the file loaded ok. bpy.context.scene.frame_set(6) - self.assertAlmostEqual(-1, cube.data.vertices[0].co.x) - self.assertAlmostEqual(-1, cube.data.vertices[0].co.y) - self.assertAlmostEqual(0.5905638933181763, cube.data.vertices[0].co.z) + mesh = plane.to_mesh(bpy.context.scene, True, 'RENDER') + self.assertAlmostEqual(-1, mesh.vertices[0].co.x) + self.assertAlmostEqual(-1, mesh.vertices[0].co.y) + self.assertAlmostEqual(0.5905638933181763, mesh.vertices[0].co.z) # Change path from absolute to relative. This should not break the animation. bpy.context.scene.frame_set(1) bpy.data.cache_files[fname].filepath = relpath bpy.context.scene.frame_set(6) - self.assertAlmostEqual(1, cube.data.vertices[3].co.x) - self.assertAlmostEqual(1, cube.data.vertices[3].co.y) - self.assertAlmostEqual(0.5905638933181763, cube.data.vertices[3].co.z) + mesh = plane.to_mesh(bpy.context.scene, True, 'RENDER') + self.assertAlmostEqual(1, mesh.vertices[3].co.x) + self.assertAlmostEqual(1, mesh.vertices[3].co.y) + self.assertAlmostEqual(0.5905638933181763, mesh.vertices[3].co.z) def test_import_long_names(self): # This file contains very long names. The longest name is 4047 chars. diff --git a/tests/python/bl_load_py_modules.py b/tests/python/bl_load_py_modules.py index 80933cd5b61..39e7bd33d44 100644 --- a/tests/python/bl_load_py_modules.py +++ b/tests/python/bl_load_py_modules.py @@ -93,9 +93,8 @@ def addon_modules_sorted(): def source_list(path, filename_check=None): from os.path import join for dirpath, dirnames, filenames in os.walk(path): - # skip '.svn' - if dirpath.startswith("."): - continue + # skip '.git' + dirnames[:] = [d for d in dirnames if not d.startswith(".")] for filename in filenames: filepath = join(dirpath, filename) @@ -123,6 +122,8 @@ def load_addons(): def load_modules(): + VERBOSE = os.environ.get("BLENDER_VERBOSE") is not None + modules = [] module_paths = [] @@ -162,6 +163,14 @@ def load_modules(): del module_names # + # test we tested all files except for presets and templates + ignore_paths = [ + os.sep + "presets" + os.sep, + os.sep + "templates" + os.sep, + ] + ([(os.sep + f + os.sep) for f in BLACKLIST] + + [(os.sep + f + ".py") for f in BLACKLIST]) + + # # now submodules for m in modules: filepath = m.__file__ @@ -178,15 +187,35 @@ def load_modules(): for f in MODULE_SYS_PATHS.get(mod_name_full, ()) ]) - __import__(mod_name_full) - mod_imp = sys.modules[mod_name_full] - - sys.path[:] = sys_path_back - - # check we load what we ask for. - assert(os.path.samefile(mod_imp.__file__, submod_full)) - - modules.append(mod_imp) + try: + __import__(mod_name_full) + mod_imp = sys.modules[mod_name_full] + + sys.path[:] = sys_path_back + + # check we load what we ask for. + assert(os.path.samefile(mod_imp.__file__, submod_full)) + + modules.append(mod_imp) + except Exception as e: + import traceback + # Module might fail to import, but we don't want whole test to fail here. + # Reasoning: + # - This module might be in ignored list (for example, preset or template), + # so failing here will cause false-positive test failure. + # - If this is module which should not be ignored, it is not added to list + # of successfully loaded modules, meaning the test will catch this + # import failure. + # - We want to catch all failures of this script instead of stopping on + # a first big failure. + do_print = True + if not VERBOSE: + for ignore in ignore_paths: + if ignore in submod_full: + do_print = False + break + if do_print: + traceback.print_exc() # # check which filepaths we didn't load @@ -205,14 +234,6 @@ def load_modules(): for f in loaded_files: source_files.remove(f) - # - # test we tested all files except for presets and templates - ignore_paths = [ - os.sep + "presets" + os.sep, - os.sep + "templates" + os.sep, - ] + ([(os.sep + f + os.sep) for f in BLACKLIST] + - [(os.sep + f + ".py") for f in BLACKLIST]) - for f in source_files: for ignore in ignore_paths: if ignore in f: diff --git a/tests/python/bl_pyapi_bpy_utils_units.py b/tests/python/bl_pyapi_bpy_utils_units.py index f40dab4b5eb..251419cb9ef 100644 --- a/tests/python/bl_pyapi_bpy_utils_units.py +++ b/tests/python/bl_pyapi_bpy_utils_units.py @@ -32,18 +32,17 @@ class UnitsTesting(unittest.TestCase): OUTPUT_TESTS = ( # system, type, prec, sep, compat, value, output ##### LENGTH + # Note: precision handling is a bit complicated when using multi-units... ('IMPERIAL', 'LENGTH', 3, False, False, 0.3048, "1'"), ('IMPERIAL', 'LENGTH', 3, False, True, 0.3048, "1ft"), - ('IMPERIAL', 'LENGTH', 3, True, False, 0.3048 * 2 + 0.0254 * 5.5, "2' 5.5\""), - # Those next two fail, here again because precision ignores order magnitude :/ - #('IMPERIAL', 'LENGTH', 3, False, False, 1609.344 * 1e6, "1000000mi"), # == 1000000.004mi!!! - #('IMPERIAL', 'LENGTH', 6, False, False, 1609.344 * 1e6, "1000000mi"), # == 1000000.003641mi!!! - ('METRIC', 'LENGTH', 3, True, False, 1000 * 2 + 0.001 * 15, "2km 1.5cm"), - ('METRIC', 'LENGTH', 3, True, False, 1234.56789, "1km 234.6m"), - # Note: precision seems basically unused when using multi units! - ('METRIC', 'LENGTH', 9, True, False, 1234.56789, "1km 234.6m"), - ('METRIC', 'LENGTH', 9, False, False, 1234.56789, "1.23456789km"), - ('METRIC', 'LENGTH', 9, True, False, 1000.000123456789, "1km 0.1mm"), + ('IMPERIAL', 'LENGTH', 4, True, False, 0.3048 * 2 + 0.0254 * 5.5, "2' 5.5\""), + ('IMPERIAL', 'LENGTH', 3, False, False, 1609.344 * 1e6, "1000000mi"), + ('IMPERIAL', 'LENGTH', 6, False, False, 1609.344 * 1e6, "1000000mi"), + ('METRIC', 'LENGTH', 3, True, False, 1000 * 2 + 0.001 * 15, "2km 2cm"), + ('METRIC', 'LENGTH', 5, True, False, 1234.56789, "1km 234.6m"), + ('METRIC', 'LENGTH', 6, True, False, 1234.56789, "1km 234.57m"), + ('METRIC', 'LENGTH', 9, False, False, 1234.56789, "1.234568km"), + ('METRIC', 'LENGTH', 9, True, False, 1000.000123456789, "1km 0.123mm"), ) def test_units_inputs(self): diff --git a/tests/python/bl_run_operators.py b/tests/python/bl_run_operators.py index 7d5f4127378..7b6b97e5ad1 100644 --- a/tests/python/bl_run_operators.py +++ b/tests/python/bl_run_operators.py @@ -100,10 +100,8 @@ def blend_list(mainpath): def file_list(path, filename_check=None): for dirpath, dirnames, filenames in os.walk(path): - - # skip '.svn' - if dirpath.startswith("."): - continue + # skip '.git' + dirnames[:] = [d for d in dirnames if not d.startswith(".")] for filename in filenames: filepath = join(dirpath, filename) diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py index a030cc5e0de..2122150467c 100755 --- a/tests/python/cycles_render_tests.py +++ b/tests/python/cycles_render_tests.py @@ -2,7 +2,10 @@ # Apache License, Version 2.0 import argparse +import glob import os +import pathlib +import shlex import shutil import subprocess import sys @@ -24,7 +27,7 @@ class COLORS_DUMMY: COLORS = COLORS_DUMMY -def printMessage(type, status, message): +def print_message(message, type=None, status=''): if type == 'SUCCESS': print(COLORS.GREEN, end="") elif type == 'FAILURE': @@ -50,38 +53,60 @@ def render_file(filepath): dirname = os.path.dirname(filepath) basedir = os.path.dirname(dirname) subject = os.path.basename(dirname) + + custom_args = os.getenv('CYCLESTEST_ARGS') + custom_args = shlex.split(custom_args) if custom_args else [] + + # OSL and GPU examples + # custom_args += ["--python-expr", "import bpy; bpy.context.scene.cycles.shading_system = True"] + # custom_args += ["--python-expr", "import bpy; bpy.context.scene.cycles.device = 'GPU'"] + if subject == 'opengl': - command = ( + command = [ BLENDER, "--window-geometry", "0", "0", "1", "1", "-noaudio", "--factory-startup", "--enable-autoexec", filepath, - "-E", "CYCLES", - # Run with OSL enabled - # "--python-expr", "import bpy; bpy.context.scene.cycles.shading_system = True", + "-E", "CYCLES"] + command += custom_args + command += [ "-o", TEMP_FILE_MASK, "-F", "PNG", '--python', os.path.join(basedir, "util", - "render_opengl.py") - ) + "render_opengl.py")] + elif subject == 'bake': + command = [ + BLENDER, + "-b", + "-noaudio", + "--factory-startup", + "--enable-autoexec", + filepath, + "-E", "CYCLES"] + command += custom_args + command += [ + "-o", TEMP_FILE_MASK, + "-F", "PNG", + '--python', os.path.join(basedir, + "util", + "render_bake.py")] else: - command = ( + command = [ BLENDER, "--background", "-noaudio", "--factory-startup", "--enable-autoexec", filepath, - "-E", "CYCLES", - # Run with OSL enabled - # "--python-expr", "import bpy; bpy.context.scene.cycles.shading_system = True", + "-E", "CYCLES"] + command += custom_args + command += [ "-o", TEMP_FILE_MASK, "-F", "PNG", - "-f", "1", - ) + "-f", "1"] try: output = subprocess.check_output(command) if VERBOSE: @@ -109,68 +134,241 @@ def test_get_name(filepath): filename = os.path.basename(filepath) return os.path.splitext(filename)[0] - -def verify_output(filepath): +def test_get_images(filepath): testname = test_get_name(filepath) dirpath = os.path.dirname(filepath) - reference_dirpath = os.path.join(dirpath, "reference_renders") - reference_image = os.path.join(reference_dirpath, testname + ".png") - failed_image = os.path.join(reference_dirpath, testname + ".fail.png") - if not os.path.exists(reference_image): - return False + + old_dirpath = os.path.join(dirpath, "reference_renders") + old_img = os.path.join(old_dirpath, testname + ".png") + + ref_dirpath = os.path.join(OUTDIR, os.path.basename(dirpath), "ref") + ref_img = os.path.join(ref_dirpath, testname + ".png") + if not os.path.exists(ref_dirpath): + os.makedirs(ref_dirpath) + if os.path.exists(old_img): + shutil.copy(old_img, ref_img) + + new_dirpath = os.path.join(OUTDIR, os.path.basename(dirpath)) + if not os.path.exists(new_dirpath): + os.makedirs(new_dirpath) + new_img = os.path.join(new_dirpath, testname + ".png") + + diff_dirpath = os.path.join(OUTDIR, os.path.basename(dirpath), "diff") + if not os.path.exists(diff_dirpath): + os.makedirs(diff_dirpath) + diff_img = os.path.join(diff_dirpath, testname + ".diff.png") + + return old_img, ref_img, new_img, diff_img + + +class Report: + def __init__(self, testname): + self.failed_tests = "" + self.passed_tests = "" + self.testname = testname + + def output(self): + # write intermediate data for single test + outdir = os.path.join(OUTDIR, self.testname) + if not os.path.exists(outdir): + os.makedirs(outdir) + + filepath = os.path.join(outdir, "failed.data") + pathlib.Path(filepath).write_text(self.failed_tests) + + filepath = os.path.join(outdir, "passed.data") + pathlib.Path(filepath).write_text(self.passed_tests) + + # gather intermediate data for all tests + failed_data = sorted(glob.glob(os.path.join(OUTDIR, "*/failed.data"))) + passed_data = sorted(glob.glob(os.path.join(OUTDIR, "*/passed.data"))) + + failed_tests = "" + passed_tests = "" + + for filename in failed_data: + filepath = os.path.join(OUTDIR, filename) + failed_tests += pathlib.Path(filepath).read_text() + for filename in passed_data: + filepath = os.path.join(OUTDIR, filename) + passed_tests += pathlib.Path(filepath).read_text() + + # write html for all tests + self.html = """ +<html> +<head> + <title>Cycles Test Report</title> + <style> + img {{ image-rendering: pixelated; width: 256px; background-color: #000; }} + img.render {{ + background-color: #fff; + background-image: + -moz-linear-gradient(45deg, #eee 25%, transparent 25%), + -moz-linear-gradient(-45deg, #eee 25%, transparent 25%), + -moz-linear-gradient(45deg, transparent 75%, #eee 75%), + -moz-linear-gradient(-45deg, transparent 75%, #eee 75%); + background-image: + -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, #eee), color-stop(.25, transparent)), + -webkit-gradient(linear, 0 0, 100% 100%, color-stop(.25, #eee), color-stop(.25, transparent)), + -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.75, transparent), color-stop(.75, #eee)), + -webkit-gradient(linear, 0 0, 100% 100%, color-stop(.75, transparent), color-stop(.75, #eee)); + + -moz-background-size:50px 50px; + background-size:50px 50px; + -webkit-background-size:50px 51px; /* override value for shitty webkit */ + + background-position:0 0, 25px 0, 25px -25px, 0px 25px; + }} + table td:first-child {{ width: 256px; }} + </style> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"> +</head> +<body> + <div class="container"> + <br/> + <h1>Cycles Test Report</h1> + <br/> + <table class="table table-striped"> + <thead class="thead-default"> + <tr><th>Name</th><th>New</th><th>Reference</th><th>Diff</th> + </thead> + {}{} + </table> + <br/> + </div> +</body> +</html> + """ . format(failed_tests, passed_tests) + + filepath = os.path.join(OUTDIR, "report.html") + pathlib.Path(filepath).write_text(self.html) + + print_message("Report saved to: " + pathlib.Path(filepath).as_uri()) + + def relative_url(self, filepath): + relpath = os.path.relpath(filepath, OUTDIR) + return pathlib.Path(relpath).as_posix() + + def add_test(self, filepath, error): + name = test_get_name(filepath) + name = name.replace('_', ' ') + + old_img, ref_img, new_img, diff_img = test_get_images(filepath) + + status = error if error else "" + style = """ style="background-color: #f99;" """ if error else "" + + new_url = self.relative_url(new_img) + ref_url = self.relative_url(ref_img) + diff_url = self.relative_url(diff_img) + + test_html = """ + <tr{}> + <td><b>{}</b><br/>{}<br/>{}</td> + <td><img src="{}" onmouseover="this.src='{}';" onmouseout="this.src='{}';" class="render"></td> + <td><img src="{}" onmouseover="this.src='{}';" onmouseout="this.src='{}';" class="render"></td> + <td><img src="{}"></td> + </tr>""" . format(style, name, self.testname, status, + new_url, ref_url, new_url, + ref_url, new_url, ref_url, + diff_url) + + if error: + self.failed_tests += test_html + else: + self.passed_tests += test_html + + +def verify_output(report, filepath): + old_img, ref_img, new_img, diff_img = test_get_images(filepath) + + # copy new image + if os.path.exists(new_img): + os.remove(new_img) + if os.path.exists(TEMP_FILE): + shutil.copy(TEMP_FILE, new_img) + + update = os.getenv('CYCLESTEST_UPDATE') + + if os.path.exists(ref_img): + # diff test with threshold + command = ( + IDIFF, + "-fail", "0.016", + "-failpercent", "1", + ref_img, + TEMP_FILE, + ) + try: + subprocess.check_output(command) + failed = False + except subprocess.CalledProcessError as e: + if VERBOSE: + print_message(e.output.decode("utf-8")) + failed = e.returncode != 1 + else: + if not update: + return False + + failed = True + + if failed and update: + # update reference + shutil.copy(new_img, ref_img) + shutil.copy(new_img, old_img) + failed = False + + # generate diff image command = ( IDIFF, - "-fail", "0.015", - "-failpercent", "1", - reference_image, - TEMP_FILE, + "-o", diff_img, + "-abs", "-scale", "16", + ref_img, + TEMP_FILE ) + try: subprocess.check_output(command) - failed = False except subprocess.CalledProcessError as e: if VERBOSE: - print(e.output.decode("utf-8")) - failed = e.returncode != 1 - if failed: - shutil.copy(TEMP_FILE, failed_image) - elif os.path.exists(failed_image): - os.remove(failed_image) + print_message(e.output.decode("utf-8")) + return not failed -def run_test(filepath): +def run_test(report, filepath): testname = test_get_name(filepath) spacer = "." * (32 - len(testname)) - printMessage('SUCCESS', 'RUN', testname) + print_message(testname, 'SUCCESS', 'RUN') time_start = time.time() error = render_file(filepath) status = "FAIL" if not error: - if not verify_output(filepath): + if not verify_output(report, filepath): error = "VERIFY" time_end = time.time() elapsed_ms = int((time_end - time_start) * 1000) if not error: - printMessage('SUCCESS', 'OK', "{} ({} ms)" . - format(testname, elapsed_ms)) + print_message("{} ({} ms)" . format(testname, elapsed_ms), + 'SUCCESS', 'OK') else: if error == "NO_CYCLES": - print("Can't perform tests because Cycles failed to load!") - return False + print_message("Can't perform tests because Cycles failed to load!") + return error elif error == "NO_START": - print('Can not perform tests because blender fails to start.', + print_message('Can not perform tests because blender fails to start.', 'Make sure INSTALL target was run.') - return False + return error elif error == 'VERIFY': - print("Rendered result is different from reference image") + print_message("Rendered result is different from reference image") else: - print("Unknown error %r" % error) - printMessage('FAILURE', 'FAILED', "{} ({} ms)" . - format(testname, elapsed_ms)) + print_message("Unknown error %r" % error) + print_message("{} ({} ms)" . format(testname, elapsed_ms), + 'FAILURE', 'FAILED') return error + def blend_list(path): for dirpath, dirnames, filenames in os.walk(path): for filename in filenames: @@ -178,17 +376,18 @@ def blend_list(path): filepath = os.path.join(dirpath, filename) yield filepath - def run_all_tests(dirpath): passed_tests = [] failed_tests = [] all_files = list(blend_list(dirpath)) all_files.sort() - printMessage('SUCCESS', "==========", - "Running {} tests from 1 test case." . format(len(all_files))) + report = Report(os.path.basename(dirpath)) + print_message("Running {} tests from 1 test case." . + format(len(all_files)), + 'SUCCESS', "==========") time_start = time.time() for filepath in all_files: - error = run_test(filepath) + error = run_test(report, filepath) testname = test_get_name(filepath) if error: if error == "NO_CYCLES": @@ -198,28 +397,33 @@ def run_all_tests(dirpath): failed_tests.append(testname) else: passed_tests.append(testname) + report.add_test(filepath, error) time_end = time.time() elapsed_ms = int((time_end - time_start) * 1000) - print("") - printMessage('SUCCESS', "==========", - "{} tests from 1 test case ran. ({} ms total)" . - format(len(all_files), elapsed_ms)) - printMessage('SUCCESS', 'PASSED', "{} tests." . - format(len(passed_tests))) + print_message("") + print_message("{} tests from 1 test case ran. ({} ms total)" . + format(len(all_files), elapsed_ms), + 'SUCCESS', "==========") + print_message("{} tests." . + format(len(passed_tests)), + 'SUCCESS', 'PASSED') if failed_tests: - printMessage('FAILURE', 'FAILED', "{} tests, listed below:" . - format(len(failed_tests))) + print_message("{} tests, listed below:" . + format(len(failed_tests)), + 'FAILURE', 'FAILED') failed_tests.sort() for test in failed_tests: - printMessage('FAILURE', "FAILED", "{}" . format(test)) - return False - return True + print_message("{}" . format(test), 'FAILURE', "FAILED") + + report.output() + return not bool(failed_tests) def create_argparse(): parser = argparse.ArgumentParser() parser.add_argument("-blender", nargs="+") parser.add_argument("-testdir", nargs=1) + parser.add_argument("-outdir", nargs=1) parser.add_argument("-idiff", nargs=1) return parser @@ -229,7 +433,7 @@ def main(): args = parser.parse_args() global COLORS - global BLENDER, ROOT, IDIFF + global BLENDER, TESTDIR, IDIFF, OUTDIR global TEMP_FILE, TEMP_FILE_MASK, TEST_SCRIPT global VERBOSE @@ -237,8 +441,12 @@ def main(): COLORS = COLORS_ANSI BLENDER = args.blender[0] - ROOT = args.testdir[0] + TESTDIR = args.testdir[0] IDIFF = args.idiff[0] + OUTDIR = args.outdir[0] + + if not os.path.exists(OUTDIR): + os.makedirs(OUTDIR) TEMP = tempfile.mkdtemp() TEMP_FILE_MASK = os.path.join(TEMP, "test") @@ -248,7 +456,7 @@ def main(): VERBOSE = os.environ.get("BLENDER_VERBOSE") is not None - ok = run_all_tests(ROOT) + ok = run_all_tests(TESTDIR) # Cleanup temp files and folders if os.path.exists(TEMP_FILE): |