diff options
author | Tianwei Shen <shentianweipku@gmail.com> | 2017-04-15 16:44:48 +0300 |
---|---|---|
committer | Tianwei Shen <shentianweipku@gmail.com> | 2017-04-15 16:44:48 +0300 |
commit | f11ff0e672b8df79cdab85c8bebbd8c36c2c1cff (patch) | |
tree | c80138a7af123907c3eb26fee978644c702795cf | |
parent | 473653f33798b727148e8f6379f31cbba95de479 (diff) | |
parent | 97c9c6a3f321f35f0b58ab167aea97a790c94cfb (diff) |
Merge branch 'master' into soc-2016-multiviewsoc-2016-multiview
513 files changed, 11239 insertions, 6569 deletions
diff --git a/.gitmodules b/.gitmodules index 0b8228e3f14..2f52bfce372 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,15 +2,19 @@ path = release/scripts/addons url = ../blender-addons.git ignore = all + branch = master [submodule "release/scripts/addons_contrib"] path = release/scripts/addons_contrib url = ../blender-addons-contrib.git ignore = all + branch = master [submodule "release/datafiles/locale"] path = release/datafiles/locale url = ../blender-translations.git ignore = all + branch = master [submodule "source/tools"] path = source/tools url = ../blender-dev-tools.git ignore = all + branch = master diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index ee49f83b38d..82895acf25e 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -322,8 +322,8 @@ OPENEXR_FORCE_REBUILD=false OPENEXR_SKIP=false _with_built_openexr=false -OIIO_VERSION="1.7.8" -OIIO_VERSION_MIN="1.6.0" +OIIO_VERSION="1.7.13" +OIIO_VERSION_MIN="1.7.13" OIIO_VERSION_MAX="1.9.0" # UNKNOWN currently # Not supported by current OSL... OIIO_FORCE_BUILD=false OIIO_FORCE_REBUILD=false @@ -360,7 +360,7 @@ OPENVDB_FORCE_REBUILD=false OPENVDB_SKIP=false # Alembic needs to be compiled for now -ALEMBIC_VERSION="1.6.0" +ALEMBIC_VERSION="1.7.1" ALEMBIC_VERSION_MIN=$ALEMBIC_VERSION ALEMBIC_FORCE_BUILD=false ALEMBIC_FORCE_REBUILD=false @@ -2236,9 +2236,6 @@ compile_ALEMBIC() { return fi - compile_HDF5 - PRINT "" - # To be changed each time we make edits that would modify the compiled result! alembic_magic=2 _init_alembic @@ -2266,8 +2263,16 @@ compile_ALEMBIC() { cmake_d="-D CMAKE_INSTALL_PREFIX=$_inst" + # Without Boost or TR1, Alembic requires C++11. + if [ "$USE_CXX11" != true ]; then + cmake_d="$cmake_d -D ALEMBIC_LIB_USES_BOOST=ON" + cmake_d="$cmake_d -D ALEMBIC_LIB_USES_TR1=OFF" + fi + if [ -d $INST/boost ]; then - cmake_d="$cmake_d -D BOOST_ROOT=$INST/boost" + if [ -d $INST/boost ]; then + cmake_d="$cmake_d -D BOOST_ROOT=$INST/boost" + fi cmake_d="$cmake_d -D USE_STATIC_BOOST=ON" else cmake_d="$cmake_d -D USE_STATIC_BOOST=OFF" @@ -2285,8 +2290,6 @@ compile_ALEMBIC() { cmake_d="$cmake_d -D USE_STATIC_HDF5=OFF" cmake_d="$cmake_d -D ALEMBIC_ILMBASE_LINK_STATIC=OFF" cmake_d="$cmake_d -D ALEMBIC_SHARED_LIBS=OFF" - cmake_d="$cmake_d -D ALEMBIC_LIB_USES_BOOST=ON" - cmake_d="$cmake_d -D ALEMBIC_LIB_USES_TR1=OFF" INFO "ILMBASE_ROOT=$INST/openexr" fi @@ -2777,7 +2780,7 @@ install_DEB() { boost_version=$(echo `get_package_version_DEB libboost-dev` | sed -r 's/^([0-9]+\.[0-9]+).*/\1/') - install_packages_DEB libboost-{filesystem,iostreams,locale,regex,system,thread,wave}$boost_version-dev + install_packages_DEB libboost-{filesystem,iostreams,locale,regex,system,thread,wave,program-options}$boost_version-dev clean_Boost else compile_Boost @@ -4252,7 +4255,7 @@ print_info() { PRINT " $_3" _buildargs="$_buildargs $_1 $_2 $_3" if [ -d $INST/osl ]; then - _1="-D CYCLES_OSL=$INST/osl" + _1="-D OSL_ROOT_DIR=$INST/osl" PRINT " $_1" _buildargs="$_buildargs $_1" fi diff --git a/build_files/buildbot/config/blender_linux.cmake b/build_files/buildbot/config/blender_linux.cmake index ed5417c1c6e..56f18967300 100644 --- a/build_files/buildbot/config/blender_linux.cmake +++ b/build_files/buildbot/config/blender_linux.cmake @@ -94,6 +94,10 @@ set(OPENCOLORIO_OPENCOLORIO_LIBRARY "${OPENCOLORIO_ROOT_DIR}/lib/libOpenColorIO. set(OPENCOLORIO_TINYXML_LIBRARY "${OPENCOLORIO_ROOT_DIR}/lib/libtinyxml.a" CACHE STRING "" FORCE) set(OPENCOLORIO_YAML-CPP_LIBRARY "${OPENCOLORIO_ROOT_DIR}/lib/libyaml-cpp.a" CACHE STRING "" FORCE) +# Freetype +set(FREETYPE_INCLUDE_DIRS "/usr/include/freetype2" CACHE STRING "" FORCE) +set(FREETYPE_LIBRARY "/usr/lib${MULTILIB}/libfreetype.a" CACHE STRING "" FORCE) + # OpenImageIO if(GLIBC EQUAL "2.19") set(OPENIMAGEIO_LIBRARY @@ -102,6 +106,7 @@ if(GLIBC EQUAL "2.19") /usr/lib${MULTILIB}/libwebp.a /usr/lib${MULTILIB}/liblzma.a /usr/lib${MULTILIB}/libjbig.a + ${FREETYPE_LIBRARY} CACHE STRING "" FORCE ) endif() diff --git a/build_files/buildbot/master.cfg b/build_files/buildbot/master.cfg index 387e53593b3..c650cb8c302 100644 --- a/build_files/buildbot/master.cfg +++ b/build_files/buildbot/master.cfg @@ -4,10 +4,10 @@ # <pep8 compliant> # List of the branches being built automatically overnight -NIGHT_SCHEDULE_BRANCHES = [None] +NIGHT_SCHEDULE_BRANCHES = [None, "blender2.8"] # List of the branches available for force build -FORCE_SCHEDULE_BRANCHES = ["master", "gooseberry", "experimental-build"] +FORCE_SCHEDULE_BRANCHES = ["master", "blender2.8", "experimental-build"] """ Stock Twisted directory lister doesn't provide any information about last file @@ -127,7 +127,14 @@ def schedule_force_build(name): project=forcesched.FixedParameter(name="project", default="", hide=True)), # For now, hide other codebases. forcesched.CodebaseParameter(hide=True, codebase="blender-translations"), - forcesched.CodebaseParameter(hide=True, codebase="blender-addons"), + forcesched.CodebaseParameter( + codebase="blender-addons", + branch=forcesched.ChoiceStringParameter( + name="branch", choices=["master", "blender2.8"], default="master"), + repository=forcesched.FixedParameter(name="repository", default="", hide=True), + project=forcesched.FixedParameter(name="project", default="", hide=True), + revision=forcesched.FixedParameter(name="revision", default="", hide=True), + ), forcesched.CodebaseParameter(hide=True, codebase="blender-addons-contrib"), forcesched.CodebaseParameter(hide=True, codebase="blender-dev-tools"), forcesched.CodebaseParameter(hide=True, codebase="lib svn")], @@ -139,11 +146,15 @@ def schedule_build(name, hour, minute=0): scheduler_name = "nightly " + name if current_branch: scheduler_name += ' ' + current_branch + # Use special addons submodule branch when building blender2.8 branch. + addons_branch = "master" + if current_branch == "blender2.8": + addons_branch = "blender2.8" c['schedulers'].append(timed.Nightly(name=scheduler_name, codebases={ "blender": {"repository": ""}, "blender-translations": {"repository": "", "branch": "master"}, - "blender-addons": {"repository": "", "branch": "master"}, + "blender-addons": {"repository": "", "branch": addons_branch}, "blender-addons-contrib": {"repository": "", "branch": "master"}, "blender-dev-tools": {"repository": "", "branch": "master"}, "lib svn": {"repository": "", "branch": "trunk"}}, @@ -225,8 +236,7 @@ def git_step(branch=''): def git_submodules_update(): - command = ['git', 'submodule', 'foreach', '--recursive', - 'git', 'pull', 'origin', 'master'] + command = ['git', 'submodule', 'update', '--remote'] return ShellCommand(name='Submodules Update', command=command, description='updating', @@ -235,7 +245,10 @@ def git_submodules_update(): def lib_svn_step(dir): - return SVN(name='lib svn', + 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', mode='update', @@ -264,6 +277,9 @@ 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', @@ -286,7 +302,7 @@ def generic_builder(id, libdir='', branch='', rsync=False): f.addStep(FileUpload(name='upload', slavesrc='buildbot_upload.zip', masterdest=filename, - maxsize=150 * 1024 * 1024, + maxsize=180 * 1024 * 1024, workdir='install')) f.addStep(MasterShellCommand(name='unpack', command=['python2.7', unpack_script, filename], diff --git a/build_files/buildbot/master_unpack.py b/build_files/buildbot/master_unpack.py index ec44705931c..67b628f668a 100644 --- a/build_files/buildbot/master_unpack.py +++ b/build_files/buildbot/master_unpack.py @@ -67,6 +67,9 @@ def get_platform(filename): def get_branch(filename): + if filename.startswith("blender-2.8"): + return "blender2.8" + tokens = filename.split("-") branch = "" diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py index 860dd1174cf..0e264a752d5 100644 --- a/build_files/buildbot/slave_compile.py +++ b/build_files/buildbot/slave_compile.py @@ -74,6 +74,9 @@ if 'cmake' in builder: 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') + elif builder.startswith('win'): @@ -91,7 +94,6 @@ if 'cmake' in builder: elif builder.startswith('win32'): bits = 32 cmake_options.extend(['-G', 'Visual Studio 12 2013']) - cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE:FILEPATH=C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v8.0/bin/nvcc.exe') elif builder.startswith('linux'): tokens = builder.split("_") @@ -110,8 +112,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.append('-DCUDA_NVCC_EXECUTABLE=/usr/local/cuda-8.0/bin/nvcc') + cmake_extra_options.extend(["-DCMAKE_C_COMPILER=/usr/bin/gcc-6", + "-DCMAKE_CXX_COMPILER=/usr/bin/g++-6"]) cmake_options.append("-C" + os.path.join(blender_dir, cmake_config_file)) @@ -178,7 +180,7 @@ if 'cmake' in builder: os.remove('CMakeCache.txt') retcode = subprocess.call(target_chroot_prefix + ['cmake', blender_dir] + target_cmake_options) if retcode != 0: - print('Condifuration FAILED!') + print('Configuration FAILED!') sys.exit(retcode) if 'win32' in builder or 'win64' in builder: diff --git a/build_files/buildbot/slave_pack.py b/build_files/buildbot/slave_pack.py index 490f0456045..6929be85003 100644 --- a/build_files/buildbot/slave_pack.py +++ b/build_files/buildbot/slave_pack.py @@ -111,7 +111,8 @@ if builder.find('cmake') != -1: if builder.endswith('vc2015'): platform += "-vc14" builderified_name = 'blender-{}-{}-{}'.format(blender_full_version, git_hash, platform) - if branch != '': + # NOTE: Blender 2.8 is already respected by blender_full_version. + if branch != '' and branch != 'blender2.8': builderified_name = branch + "-" + builderified_name os.rename(result_file, "{}.zip".format(builderified_name)) @@ -177,7 +178,8 @@ if builder.find('cmake') != -1: blender_hash, blender_glibc, blender_arch) - if branch != '': + # NOTE: Blender 2.8 is already respected by blender_full_version. + if branch != '' and branch != 'blender2.8': package_name = branch + "-" + package_name upload_filename = package_name + ".tar.bz2" diff --git a/build_files/cmake/Modules/FindOpenImageIO.cmake b/build_files/cmake/Modules/FindOpenImageIO.cmake index 789097dfd51..d59f9cfcdfc 100644 --- a/build_files/cmake/Modules/FindOpenImageIO.cmake +++ b/build_files/cmake/Modules/FindOpenImageIO.cmake @@ -60,7 +60,7 @@ FIND_FILE(OPENIMAGEIO_IDIFF NAMES idiff HINTS - ${OPENIMAGEIO_ROOT_DIR} + ${_openimageio_SEARCH_DIRS} PATH_SUFFIXES bin ) diff --git a/build_files/cmake/Modules/GTestTesting.cmake b/build_files/cmake/Modules/GTestTesting.cmake index 0732e10133c..e688db35ef1 100644 --- a/build_files/cmake/Modules/GTestTesting.cmake +++ b/build_files/cmake/Modules/GTestTesting.cmake @@ -39,6 +39,9 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST) ${PTHREADS_LIBRARIES} extern_glog extern_gflags) + if(WITH_OPENMP_STATIC) + target_link_libraries(${NAME}_test ${OpenMP_LIBRARIES}) + endif() set_target_properties(${NAME}_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTS_OUTPUT_DIR}" RUNTIME_OUTPUT_DIRECTORY_RELEASE "${TESTS_OUTPUT_DIR}" diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index f9992ee92b9..b7f6649e507 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -595,6 +595,7 @@ function(SETUP_BLENDER_SORTED_LIBS) bf_freestyle bf_ikplugin bf_modifiers + bf_alembic bf_bmesh bf_gpu bf_blenloader @@ -613,7 +614,6 @@ function(SETUP_BLENDER_SORTED_LIBS) bf_imbuf_openimageio bf_imbuf_dds bf_collada - bf_alembic bf_intern_elbeem bf_intern_memutil bf_intern_guardedalloc diff --git a/extern/clew/README.blender b/extern/clew/README.blender index 972b46b754b..127b6bdac63 100644 --- a/extern/clew/README.blender +++ b/extern/clew/README.blender @@ -1,5 +1,5 @@ Project: OpenCL Wrangler URL: https://github.com/OpenCLWrangler/clew License: Apache 2.0 -Upstream version: 79a289e +Upstream version: 27a6867 Local modifications: None diff --git a/extern/clew/src/clew.c b/extern/clew/src/clew.c index 3717c74f1a0..dbdddfc0332 100644 --- a/extern/clew/src/clew.c +++ b/extern/clew/src/clew.c @@ -15,7 +15,7 @@ typedef HMODULE CLEW_DYNLIB_HANDLE; - #define CLEW_DYNLIB_OPEN LoadLibrary + #define CLEW_DYNLIB_OPEN LoadLibraryA #define CLEW_DYNLIB_CLOSE FreeLibrary #define CLEW_DYNLIB_IMPORT GetProcAddress #else @@ -223,7 +223,7 @@ int clewInit() __clewSetCommandQueueProperty = (PFNCLSETCOMMANDQUEUEPROPERTY )CLEW_DYNLIB_IMPORT(module, "clSetCommandQueueProperty"); #endif __clewCreateBuffer = (PFNCLCREATEBUFFER )CLEW_DYNLIB_IMPORT(module, "clCreateBuffer"); - __clewCreateSubBuffer = (PFNCLCREATESUBBUFFER )CLEW_DYNLIB_IMPORT(module, "clCreateBuffer"); + __clewCreateSubBuffer = (PFNCLCREATESUBBUFFER )CLEW_DYNLIB_IMPORT(module, "clCreateSubBuffer"); __clewCreateImage = (PFNCLCREATEIMAGE )CLEW_DYNLIB_IMPORT(module, "clCreateImage"); __clewRetainMemObject = (PFNCLRETAINMEMOBJECT )CLEW_DYNLIB_IMPORT(module, "clRetainMemObject"); __clewReleaseMemObject = (PFNCLRELEASEMEMOBJECT )CLEW_DYNLIB_IMPORT(module, "clReleaseMemObject"); diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index 31fa15a2042..806a8660e8c 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -22,6 +22,7 @@ if(WITH_CYCLES_NATIVE_ONLY) -DWITH_KERNEL_NATIVE ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") + set(CYCLES_KERNEL_FLAGS "-march=native") elseif(NOT WITH_CPU_SSE) set(CXX_HAS_SSE FALSE) set(CXX_HAS_AVX FALSE) @@ -59,10 +60,13 @@ elseif(WIN32 AND MSVC) 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) 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") @@ -79,6 +83,7 @@ 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") diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt index 8cd499b7ca6..aabb8f63640 100644 --- a/intern/cycles/app/CMakeLists.txt +++ b/intern/cycles/app/CMakeLists.txt @@ -1,14 +1,6 @@ set(INC - . - ../bvh - ../device - ../graph - ../kernel - ../kernel/svm - ../render - ../subd - ../util + .. ) set(INC_SYS ) diff --git a/intern/cycles/app/cycles_server.cpp b/intern/cycles/app/cycles_server.cpp index 4ef9cd070bb..e65b9d769e4 100644 --- a/intern/cycles/app/cycles_server.cpp +++ b/intern/cycles/app/cycles_server.cpp @@ -16,15 +16,15 @@ #include <stdio.h> -#include "device.h" - -#include "util_args.h" -#include "util_foreach.h" -#include "util_path.h" -#include "util_stats.h" -#include "util_string.h" -#include "util_task.h" -#include "util_logging.h" +#include "device/device.h" + +#include "util/util_args.h" +#include "util/util_foreach.h" +#include "util/util_path.h" +#include "util/util_stats.h" +#include "util/util_string.h" +#include "util/util_task.h" +#include "util/util_logging.h" using namespace ccl; diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp index 9816d614a7c..0cd249f0d84 100644 --- a/intern/cycles/app/cycles_standalone.cpp +++ b/intern/cycles/app/cycles_standalone.cpp @@ -16,29 +16,29 @@ #include <stdio.h> -#include "buffers.h" -#include "camera.h" -#include "device.h" -#include "scene.h" -#include "session.h" -#include "integrator.h" - -#include "util_args.h" -#include "util_foreach.h" -#include "util_function.h" -#include "util_logging.h" -#include "util_path.h" -#include "util_progress.h" -#include "util_string.h" -#include "util_time.h" -#include "util_transform.h" -#include "util_version.h" +#include "render/buffers.h" +#include "render/camera.h" +#include "device/device.h" +#include "render/scene.h" +#include "render/session.h" +#include "render/integrator.h" + +#include "util/util_args.h" +#include "util/util_foreach.h" +#include "util/util_function.h" +#include "util/util_logging.h" +#include "util/util_path.h" +#include "util/util_progress.h" +#include "util/util_string.h" +#include "util/util_time.h" +#include "util/util_transform.h" +#include "util/util_version.h" #ifdef WITH_CYCLES_STANDALONE_GUI -#include "util_view.h" +#include "util/util_view.h" #endif -#include "cycles_xml.h" +#include "app/cycles_xml.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index 35a30ae683f..04f00ef0e10 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -20,31 +20,31 @@ #include <algorithm> #include <iterator> -#include "node_xml.h" - -#include "background.h" -#include "camera.h" -#include "film.h" -#include "graph.h" -#include "integrator.h" -#include "light.h" -#include "mesh.h" -#include "nodes.h" -#include "object.h" -#include "osl.h" -#include "shader.h" -#include "scene.h" - -#include "subd_patch.h" -#include "subd_split.h" - -#include "util_debug.h" -#include "util_foreach.h" -#include "util_path.h" -#include "util_transform.h" -#include "util_xml.h" - -#include "cycles_xml.h" +#include "graph/node_xml.h" + +#include "render/background.h" +#include "render/camera.h" +#include "render/film.h" +#include "render/graph.h" +#include "render/integrator.h" +#include "render/light.h" +#include "render/mesh.h" +#include "render/nodes.h" +#include "render/object.h" +#include "render/osl.h" +#include "render/shader.h" +#include "render/scene.h" + +#include "subd/subd_patch.h" +#include "subd/subd_split.h" + +#include "util/util_debug.h" +#include "util/util_foreach.h" +#include "util/util_path.h" +#include "util/util_transform.h" +#include "util/util_xml.h" + +#include "app/cycles_xml.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index b57502b3b14..ae4977aaed0 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -1,12 +1,6 @@ set(INC - ../graph - ../render - ../device - ../kernel - ../kernel/svm - ../util - ../subd + .. ../../glew-mx ../../guardedalloc ../../mikktspace diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 6c5bcf09305..cbf469b3a89 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1096,6 +1096,12 @@ class CyclesObjectSettings(bpy.types.PropertyGroup): default=1.0, ) + cls.is_shadow_catcher = BoolProperty( + name="Shadow Catcher", + description="Only render shadows on this object, for compositing renders into real footage", + default=False, + ) + @classmethod def unregister(cls): del bpy.types.Object.cycles diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index c7b9b21e935..2b50d272be8 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -184,9 +184,6 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): sub.label(text="AA Samples:") sub.prop(cscene, "aa_samples", text="Render") sub.prop(cscene, "preview_aa_samples", text="Preview") - sub.separator() - sub.prop(cscene, "sample_all_lights_direct") - sub.prop(cscene, "sample_all_lights_indirect") col = split.column() sub = col.column(align=True) @@ -203,6 +200,10 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): sub.prop(cscene, "subsurface_samples", text="Subsurface") sub.prop(cscene, "volume_samples", text="Volume") + col = layout.column(align=True) + col.prop(cscene, "sample_all_lights_direct") + col.prop(cscene, "sample_all_lights_indirect") + if not (use_opencl(context) and cscene.feature_set != 'EXPERIMENTAL'): layout.row().prop(cscene, "sampling_pattern", text="Pattern") @@ -268,7 +269,7 @@ class CyclesRender_PT_geometry(CyclesButtonsPanel, Panel): row = col.row() row.prop(ccscene, "minimum_width", text="Min Pixels") - row.prop(ccscene, "maximum_width", text="Max Ext.") + row.prop(ccscene, "maximum_width", text="Max Extension") class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel): @@ -786,6 +787,8 @@ class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel): if ob.type != 'LAMP': flow.prop(visibility, "shadow") + layout.prop(cob, "is_shadow_catcher") + col = layout.column() col.label(text="Performance:") row = col.row() diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index f02fc553908..40d6b25f2b7 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ -#include "camera.h" -#include "scene.h" +#include "render/camera.h" +#include "render/scene.h" -#include "blender_sync.h" -#include "blender_util.h" +#include "blender/blender_sync.h" +#include "blender/blender_util.h" -#include "util_logging.h" +#include "util/util_logging.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index ffa5b676917..6fa038e8bf0 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -14,18 +14,18 @@ * limitations under the License. */ -#include "attribute.h" -#include "camera.h" -#include "curves.h" -#include "mesh.h" -#include "object.h" -#include "scene.h" - -#include "blender_sync.h" -#include "blender_util.h" - -#include "util_foreach.h" -#include "util_logging.h" +#include "render/attribute.h" +#include "render/camera.h" +#include "render/curves.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" + +#include "blender/blender_sync.h" +#include "blender/blender_util.h" + +#include "util/util_foreach.h" +#include "util/util_logging.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/blender_logging.cpp b/intern/cycles/blender/blender_logging.cpp index f4f86929168..d0f82e37662 100644 --- a/intern/cycles/blender/blender_logging.cpp +++ b/intern/cycles/blender/blender_logging.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "CCL_api.h" -#include "util_logging.h" +#include "blender/CCL_api.h" +#include "util/util_logging.h" void CCL_init_logging(const char *argv0) { diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index f949b530f90..54571b1fea1 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -15,22 +15,22 @@ */ -#include "mesh.h" -#include "object.h" -#include "scene.h" -#include "camera.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" +#include "render/camera.h" -#include "blender_sync.h" -#include "blender_session.h" -#include "blender_util.h" +#include "blender/blender_sync.h" +#include "blender/blender_session.h" +#include "blender/blender_util.h" -#include "subd_patch.h" -#include "subd_split.h" +#include "subd/subd_patch.h" +#include "subd/subd_split.h" -#include "util_algorithm.h" -#include "util_foreach.h" -#include "util_logging.h" -#include "util_math.h" +#include "util/util_algorithm.h" +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_math.h" #include "mikktspace.h" @@ -560,6 +560,9 @@ static void attr_create_pointiness(Scene *scene, return; } const int num_verts = b_mesh.vertices.length(); + if(num_verts == 0) { + return; + } /* STEP 1: Find out duplicated vertices and point duplicates to a single * original vertex. */ @@ -1164,8 +1167,8 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, } /* skip empty meshes */ - size_t numverts = mesh->verts.size(); - size_t numkeys = mesh->curve_keys.size(); + const size_t numverts = mesh->verts.size(); + const size_t numkeys = mesh->curve_keys.size(); if(!numverts && !numkeys) return; @@ -1223,13 +1226,12 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, /* TODO(sergey): Perform preliminary check for number of verticies. */ if(numverts) { - /* find attributes */ + /* Find attributes. */ Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); bool new_attribute = false; - - /* add new attributes if they don't exist already */ + /* Add new attributes if they don't exist already. */ if(!attr_mP) { attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); if(attr_N) @@ -1237,22 +1239,21 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, new_attribute = true; } - - /* load vertex data from mesh */ + /* Load vertex data from mesh. */ float3 *mP = attr_mP->data_float3() + time_index*numverts; float3 *mN = (attr_mN)? attr_mN->data_float3() + time_index*numverts: NULL; - + /* NOTE: We don't copy more that existing amount of vertices to prevent + * possible memory corruption. + */ BL::Mesh::vertices_iterator v; int i = 0; - for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < numverts; ++v, ++i) { mP[i] = get_float3(v->co()); if(mN) mN[i] = get_float3(v->normal()); } - - /* in case of new attribute, we verify if there really was any motion */ if(new_attribute) { + /* In case of new attribute, we verify if there really was any motion. */ if(b_mesh.vertices.length() != numverts || memcmp(mP, &mesh->verts[0], sizeof(float3)*numverts) == 0) { @@ -1275,7 +1276,6 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, * they had no motion, but we need them anyway now */ float3 *P = &mesh->verts[0]; float3 *N = (attr_N)? attr_N->data_float3(): NULL; - for(int step = 0; step < time_index; step++) { memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts); if(attr_mN) @@ -1283,6 +1283,16 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, } } } + else { + if(b_mesh.vertices.length() != numverts) { + VLOG(1) << "Topology differs, discarding motion blur for object " + << b_ob.name() << " at time " << time_index; + memcpy(mP, &mesh->verts[0], sizeof(float3)*numverts); + if(mN != NULL) { + memcpy(mN, attr_N->data_float3(), sizeof(float3)*numverts); + } + } + } } /* hair motion */ diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 637cf7abda8..2810ad15b9a 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -14,24 +14,24 @@ * limitations under the License. */ -#include "camera.h" -#include "integrator.h" -#include "graph.h" -#include "light.h" -#include "mesh.h" -#include "object.h" -#include "scene.h" -#include "nodes.h" -#include "particles.h" -#include "shader.h" - -#include "blender_object_cull.h" -#include "blender_sync.h" -#include "blender_util.h" - -#include "util_foreach.h" -#include "util_hash.h" -#include "util_logging.h" +#include "render/camera.h" +#include "render/integrator.h" +#include "render/graph.h" +#include "render/light.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" +#include "render/nodes.h" +#include "render/particles.h" +#include "render/shader.h" + +#include "blender/blender_object_cull.h" +#include "blender/blender_sync.h" +#include "blender/blender_util.h" + +#include "util/util_foreach.h" +#include "util/util_hash.h" +#include "util/util_logging.h" CCL_NAMESPACE_BEGIN @@ -343,6 +343,13 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, object_updated = true; } + PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); + bool is_shadow_catcher = get_boolean(cobject, "is_shadow_catcher"); + if(is_shadow_catcher != object->is_shadow_catcher) { + object->is_shadow_catcher = is_shadow_catcher; + object_updated = true; + } + /* object sync * transform comparison should not be needed, but duplis don't work perfect * in the depsgraph and may not signal changes, so this is a workaround */ @@ -372,27 +379,16 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, } } - /* random number */ - object->random_id = hash_string(object->name.c_str()); - - if(persistent_id) { - for(int i = 0; i < OBJECT_PERSISTENT_ID_SIZE; i++) - object->random_id = hash_int_2d(object->random_id, persistent_id[i]); - } - else - object->random_id = hash_int_2d(object->random_id, 0); - - if(b_parent.ptr.data != b_ob.ptr.data) - object->random_id ^= hash_int(hash_string(b_parent.name().c_str())); - - /* dupli texture coordinates */ + /* dupli texture coordinates and random_id */ if(b_dupli_ob) { object->dupli_generated = 0.5f*get_float3(b_dupli_ob.orco()) - make_float3(0.5f, 0.5f, 0.5f); object->dupli_uv = get_float2(b_dupli_ob.uv()); + object->random_id = b_dupli_ob.random_id(); } else { object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f); object->dupli_uv = make_float2(0.0f, 0.0f); + object->random_id = hash_int_2d(hash_string(object->name.c_str()), 0); } object->tag_update(scene); diff --git a/intern/cycles/blender/blender_object_cull.cpp b/intern/cycles/blender/blender_object_cull.cpp index 08918dd1a49..0333c027f70 100644 --- a/intern/cycles/blender/blender_object_cull.cpp +++ b/intern/cycles/blender/blender_object_cull.cpp @@ -16,9 +16,9 @@ #include <cstdlib> -#include "camera.h" +#include "render/camera.h" -#include "blender_object_cull.h" +#include "blender/blender_object_cull.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/blender_object_cull.h b/intern/cycles/blender/blender_object_cull.h index b6f0ca5cd31..2147877a860 100644 --- a/intern/cycles/blender/blender_object_cull.h +++ b/intern/cycles/blender/blender_object_cull.h @@ -17,8 +17,8 @@ #ifndef __BLENDER_OBJECT_CULL_H__ #define __BLENDER_OBJECT_CULL_H__ -#include "blender_sync.h" -#include "util_types.h" +#include "blender/blender_sync.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp index dd2900a8d5b..00f8cb3cf1b 100644 --- a/intern/cycles/blender/blender_particles.cpp +++ b/intern/cycles/blender/blender_particles.cpp @@ -14,14 +14,14 @@ * limitations under the License. */ -#include "mesh.h" -#include "object.h" -#include "particles.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/particles.h" -#include "blender_sync.h" -#include "blender_util.h" +#include "blender/blender_sync.h" +#include "blender/blender_util.h" -#include "util_foreach.h" +#include "util/util_foreach.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 557c4e8c5f0..d509e9de981 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -16,21 +16,21 @@ #include <Python.h> -#include "CCL_api.h" +#include "blender/CCL_api.h" -#include "blender_sync.h" -#include "blender_session.h" +#include "blender/blender_sync.h" +#include "blender/blender_session.h" -#include "util_foreach.h" -#include "util_logging.h" -#include "util_md5.h" -#include "util_opengl.h" -#include "util_path.h" -#include "util_string.h" -#include "util_types.h" +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_md5.h" +#include "util/util_opengl.h" +#include "util/util_path.h" +#include "util/util_string.h" +#include "util/util_types.h" #ifdef WITH_OSL -#include "osl.h" +#include "render/osl.h" #include <OSL/oslquery.h> #include <OSL/oslconfig.h> diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index d00b4b67a58..26f9bccd95d 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -16,30 +16,30 @@ #include <stdlib.h> -#include "background.h" -#include "buffers.h" -#include "camera.h" -#include "device.h" -#include "integrator.h" -#include "film.h" -#include "light.h" -#include "mesh.h" -#include "object.h" -#include "scene.h" -#include "session.h" -#include "shader.h" - -#include "util_color.h" -#include "util_foreach.h" -#include "util_function.h" -#include "util_hash.h" -#include "util_logging.h" -#include "util_progress.h" -#include "util_time.h" - -#include "blender_sync.h" -#include "blender_session.h" -#include "blender_util.h" +#include "render/background.h" +#include "render/buffers.h" +#include "render/camera.h" +#include "device/device.h" +#include "render/integrator.h" +#include "render/film.h" +#include "render/light.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" +#include "render/session.h" +#include "render/shader.h" + +#include "util/util_color.h" +#include "util/util_foreach.h" +#include "util/util_function.h" +#include "util/util_hash.h" +#include "util/util_logging.h" +#include "util/util_progress.h" +#include "util/util_time.h" + +#include "blender/blender_sync.h" +#include "blender/blender_session.h" +#include "blender/blender_util.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index 33b88b9ab5e..22b21a18f2e 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -17,12 +17,12 @@ #ifndef __BLENDER_SESSION_H__ #define __BLENDER_SESSION_H__ -#include "device.h" -#include "scene.h" -#include "session.h" -#include "bake.h" +#include "device/device.h" +#include "render/scene.h" +#include "render/session.h" +#include "render/bake.h" -#include "util_vector.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 8baa53fc2ec..3f04f11aab4 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -14,20 +14,23 @@ * limitations under the License. */ -#include "background.h" -#include "graph.h" -#include "light.h" -#include "nodes.h" -#include "osl.h" -#include "scene.h" -#include "shader.h" - -#include "blender_texture.h" -#include "blender_sync.h" -#include "blender_util.h" - -#include "util_debug.h" -#include "util_string.h" +#include "render/background.h" +#include "render/graph.h" +#include "render/light.h" +#include "render/nodes.h" +#include "render/osl.h" +#include "render/scene.h" +#include "render/shader.h" + +#include "blender/blender_texture.h" +#include "blender/blender_sync.h" +#include "blender/blender_util.h" + +#include "util/util_debug.h" +#include "util/util_foreach.h" +#include "util/util_string.h" +#include "util/util_set.h" +#include "util/util_task.h" CCL_NAMESPACE_BEGIN @@ -1164,6 +1167,9 @@ void BlenderSync::sync_materials(bool update_all) /* material loop */ BL::BlendData::materials_iterator b_mat; + TaskPool pool; + set<Shader*> updated_shaders; + for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) { Shader *shader; @@ -1199,9 +1205,37 @@ void BlenderSync::sync_materials(bool update_all) shader->displacement_method = (experimental) ? get_displacement_method(cmat) : DISPLACE_BUMP; shader->set_graph(graph); - shader->tag_update(scene); + + /* By simplifying the shader graph as soon as possible, some + * redundant shader nodes might be removed which prevents loading + * unnecessary attributes later. + * + * However, since graph simplification also accounts for e.g. mix + * weight, this would cause frequent expensive resyncs in interactive + * sessions, so for those sessions optimization is only performed + * right before compiling. + */ + if(!preview) { + pool.push(function_bind(&ShaderGraph::simplify, graph, scene)); + /* NOTE: Update shaders out of the threads since those routines + * are accessing and writing to a global context. + */ + updated_shaders.insert(shader); + } + else { + /* NOTE: Update tagging can access links which are being + * optimized out. + */ + shader->tag_update(scene); + } } } + + pool.wait_work(); + + foreach(Shader *shader, updated_shaders) { + shader->tag_update(scene); + } } /* Sync World */ diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index d8043105cd8..3b071bf0e7d 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -14,29 +14,29 @@ * limitations under the License. */ -#include "background.h" -#include "camera.h" -#include "film.h" -#include "graph.h" -#include "integrator.h" -#include "light.h" -#include "mesh.h" -#include "nodes.h" -#include "object.h" -#include "scene.h" -#include "shader.h" -#include "curves.h" - -#include "device.h" - -#include "blender_sync.h" -#include "blender_session.h" -#include "blender_util.h" - -#include "util_debug.h" -#include "util_foreach.h" -#include "util_opengl.h" -#include "util_hash.h" +#include "render/background.h" +#include "render/camera.h" +#include "render/film.h" +#include "render/graph.h" +#include "render/integrator.h" +#include "render/light.h" +#include "render/mesh.h" +#include "render/nodes.h" +#include "render/object.h" +#include "render/scene.h" +#include "render/shader.h" +#include "render/curves.h" + +#include "device/device.h" + +#include "blender/blender_sync.h" +#include "blender/blender_session.h" +#include "blender/blender_util.h" + +#include "util/util_debug.h" +#include "util/util_foreach.h" +#include "util/util_opengl.h" +#include "util/util_hash.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 6984cbda259..36bedc505af 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -22,15 +22,15 @@ #include "RNA_access.h" #include "RNA_blender_cpp.h" -#include "blender_util.h" +#include "blender/blender_util.h" -#include "scene.h" -#include "session.h" +#include "render/scene.h" +#include "render/session.h" -#include "util_map.h" -#include "util_set.h" -#include "util_transform.h" -#include "util_vector.h" +#include "util/util_map.h" +#include "util/util_set.h" +#include "util/util_transform.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/blender_texture.cpp b/intern/cycles/blender/blender_texture.cpp index 3807e683c7c..b2e27b76189 100644 --- a/intern/cycles/blender/blender_texture.cpp +++ b/intern/cycles/blender/blender_texture.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "blender_texture.h" +#include "blender/blender_texture.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/blender_texture.h b/intern/cycles/blender/blender_texture.h index ad96f9db8ed..734231a85ec 100644 --- a/intern/cycles/blender/blender_texture.h +++ b/intern/cycles/blender/blender_texture.h @@ -18,7 +18,7 @@ #define __BLENDER_TEXTURE_H__ #include <stdlib.h> -#include "blender_sync.h" +#include "blender/blender_sync.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 23df3c1bc30..abdbb6be0fd 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -17,15 +17,15 @@ #ifndef __BLENDER_UTIL_H__ #define __BLENDER_UTIL_H__ -#include "mesh.h" +#include "render/mesh.h" -#include "util_algorithm.h" -#include "util_map.h" -#include "util_path.h" -#include "util_set.h" -#include "util_transform.h" -#include "util_types.h" -#include "util_vector.h" +#include "util/util_algorithm.h" +#include "util/util_map.h" +#include "util/util_path.h" +#include "util/util_set.h" +#include "util/util_transform.h" +#include "util/util_types.h" +#include "util/util_vector.h" /* Hacks to hook into Blender API * todo: clean this up ... */ @@ -174,22 +174,19 @@ static inline void curvemapping_color_to_array(BL::CurveMapping& cumap, if(rgb_curve) { BL::CurveMap mapI = cumap.curves[3]; - for(int i = 0; i < size; i++) { - float t = min_x + (float)i/(float)(size-1) * range_x; - - data[i][0] = mapR.evaluate(mapI.evaluate(t)); - data[i][1] = mapG.evaluate(mapI.evaluate(t)); - data[i][2] = mapB.evaluate(mapI.evaluate(t)); + const float t = min_x + (float)i/(float)(size-1) * range_x; + data[i] = make_float3(mapR.evaluate(mapI.evaluate(t)), + mapG.evaluate(mapI.evaluate(t)), + mapB.evaluate(mapI.evaluate(t))); } } else { for(int i = 0; i < size; i++) { float t = min_x + (float)i/(float)(size-1) * range_x; - - data[i][0] = mapR.evaluate(t); - data[i][1] = mapG.evaluate(t); - data[i][2] = mapB.evaluate(t); + data[i] = make_float3(mapR.evaluate(t), + mapG.evaluate(t), + mapB.evaluate(t)); } } } diff --git a/intern/cycles/bvh/CMakeLists.txt b/intern/cycles/bvh/CMakeLists.txt index 92e48f0d87f..6078db5a8ca 100644 --- a/intern/cycles/bvh/CMakeLists.txt +++ b/intern/cycles/bvh/CMakeLists.txt @@ -1,12 +1,6 @@ set(INC - . - ../graph - ../kernel - ../kernel/svm - ../render - ../util - ../device + .. ) set(INC_SYS @@ -14,6 +8,8 @@ set(INC_SYS set(SRC bvh.cpp + bvh2.cpp + bvh4.cpp bvh_binning.cpp bvh_build.cpp bvh_node.cpp @@ -24,6 +20,8 @@ set(SRC set(SRC_HEADERS bvh.h + bvh2.h + bvh4.h bvh_binning.h bvh_build.h bvh_node.h diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index 1fb2f371a0f..33143e2d8aa 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -15,45 +15,32 @@ * limitations under the License. */ -#include "mesh.h" -#include "object.h" -#include "scene.h" -#include "curves.h" - -#include "bvh.h" -#include "bvh_build.h" -#include "bvh_node.h" -#include "bvh_params.h" -#include "bvh_unaligned.h" - -#include "util_debug.h" -#include "util_foreach.h" -#include "util_logging.h" -#include "util_map.h" -#include "util_progress.h" -#include "util_system.h" -#include "util_types.h" -#include "util_math.h" +#include "bvh/bvh.h" + +#include "render/mesh.h" +#include "render/object.h" + +#include "bvh/bvh2.h" +#include "bvh/bvh4.h" +#include "bvh/bvh_build.h" +#include "bvh/bvh_node.h" + +#include "util/util_foreach.h" +#include "util/util_progress.h" CCL_NAMESPACE_BEGIN /* Pack Utility */ -struct BVHStackEntry +BVHStackEntry::BVHStackEntry(const BVHNode *n, int i) + : node(n), idx(i) { - const BVHNode *node; - int idx; - - BVHStackEntry(const BVHNode* n = 0, int i = 0) - : node(n), idx(i) - { - } +} - int encodeIdx() const - { - return (node->is_leaf())? ~idx: idx; - } -}; +int BVHStackEntry::encodeIdx() const +{ + return (node->is_leaf())? ~idx: idx; +} /* BVH */ @@ -65,9 +52,9 @@ BVH::BVH(const BVHParams& params_, const vector<Object*>& objects_) BVH *BVH::create(const BVHParams& params, const vector<Object*>& objects) { if(params.use_qbvh) - return new QBVH(params, objects); + return new BVH4(params, objects); else - return new RegularBVH(params, objects); + return new BVH2(params, objects); } /* Building */ @@ -418,832 +405,4 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) } } -/* Regular BVH */ - -static bool node_bvh_is_unaligned(const BVHNode *node) -{ - const BVHNode *node0 = node->get_child(0), - *node1 = node->get_child(1); - return node0->is_unaligned() || node1->is_unaligned(); -} - -RegularBVH::RegularBVH(const BVHParams& params_, const vector<Object*>& objects_) -: BVH(params_, objects_) -{ -} - -void RegularBVH::pack_leaf(const BVHStackEntry& e, - const LeafNode *leaf) -{ - assert(e.idx + BVH_NODE_LEAF_SIZE <= pack.leaf_nodes.size()); - float4 data[BVH_NODE_LEAF_SIZE]; - memset(data, 0, sizeof(data)); - if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) { - /* object */ - data[0].x = __int_as_float(~(leaf->m_lo)); - data[0].y = __int_as_float(0); - } - else { - /* triangle */ - data[0].x = __int_as_float(leaf->m_lo); - data[0].y = __int_as_float(leaf->m_hi); - } - data[0].z = __uint_as_float(leaf->m_visibility); - if(leaf->num_triangles() != 0) { - data[0].w = __uint_as_float(pack.prim_type[leaf->m_lo]); - } - - memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_NODE_LEAF_SIZE); -} - -void RegularBVH::pack_inner(const BVHStackEntry& e, - const BVHStackEntry& e0, - const BVHStackEntry& e1) -{ - if(e0.node->is_unaligned() || e1.node->is_unaligned()) { - pack_unaligned_inner(e, e0, e1); - } else { - pack_aligned_inner(e, e0, e1); - } -} - -void RegularBVH::pack_aligned_inner(const BVHStackEntry& e, - const BVHStackEntry& e0, - const BVHStackEntry& e1) -{ - pack_aligned_node(e.idx, - e0.node->m_bounds, e1.node->m_bounds, - e0.encodeIdx(), e1.encodeIdx(), - e0.node->m_visibility, e1.node->m_visibility); -} - -void RegularBVH::pack_aligned_node(int idx, - const BoundBox& b0, - const BoundBox& b1, - int c0, int c1, - uint visibility0, uint visibility1) -{ - assert(idx + BVH_NODE_SIZE <= pack.nodes.size()); - assert(c0 < 0 || c0 < pack.nodes.size()); - assert(c1 < 0 || c1 < pack.nodes.size()); - - int4 data[BVH_NODE_SIZE] = { - make_int4(visibility0 & ~PATH_RAY_NODE_UNALIGNED, - visibility1 & ~PATH_RAY_NODE_UNALIGNED, - c0, c1), - make_int4(__float_as_int(b0.min.x), - __float_as_int(b1.min.x), - __float_as_int(b0.max.x), - __float_as_int(b1.max.x)), - make_int4(__float_as_int(b0.min.y), - __float_as_int(b1.min.y), - __float_as_int(b0.max.y), - __float_as_int(b1.max.y)), - make_int4(__float_as_int(b0.min.z), - __float_as_int(b1.min.z), - __float_as_int(b0.max.z), - __float_as_int(b1.max.z)), - }; - - memcpy(&pack.nodes[idx], data, sizeof(int4)*BVH_NODE_SIZE); -} - -void RegularBVH::pack_unaligned_inner(const BVHStackEntry& e, - const BVHStackEntry& e0, - const BVHStackEntry& e1) -{ - pack_unaligned_node(e.idx, - e0.node->get_aligned_space(), - e1.node->get_aligned_space(), - e0.node->m_bounds, - e1.node->m_bounds, - e0.encodeIdx(), e1.encodeIdx(), - e0.node->m_visibility, e1.node->m_visibility); -} - -void RegularBVH::pack_unaligned_node(int idx, - const Transform& aligned_space0, - const Transform& aligned_space1, - const BoundBox& bounds0, - const BoundBox& bounds1, - int c0, int c1, - uint visibility0, uint visibility1) -{ - assert(idx + BVH_UNALIGNED_NODE_SIZE <= pack.nodes.size()); - assert(c0 < 0 || c0 < pack.nodes.size()); - assert(c1 < 0 || c1 < pack.nodes.size()); - - float4 data[BVH_UNALIGNED_NODE_SIZE]; - Transform space0 = BVHUnaligned::compute_node_transform(bounds0, - aligned_space0); - Transform space1 = BVHUnaligned::compute_node_transform(bounds1, - aligned_space1); - data[0] = make_float4(__int_as_float(visibility0 | PATH_RAY_NODE_UNALIGNED), - __int_as_float(visibility1 | PATH_RAY_NODE_UNALIGNED), - __int_as_float(c0), - __int_as_float(c1)); - - data[1] = space0.x; - data[2] = space0.y; - data[3] = space0.z; - data[4] = space1.x; - data[5] = space1.y; - data[6] = space1.z; - - memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_UNALIGNED_NODE_SIZE); -} - -void RegularBVH::pack_nodes(const BVHNode *root) -{ - const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT); - const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT); - assert(num_leaf_nodes <= num_nodes); - const size_t num_inner_nodes = num_nodes - num_leaf_nodes; - size_t node_size; - if(params.use_unaligned_nodes) { - const size_t num_unaligned_nodes = - root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT); - node_size = (num_unaligned_nodes * BVH_UNALIGNED_NODE_SIZE) + - (num_inner_nodes - num_unaligned_nodes) * BVH_NODE_SIZE; - } - else { - node_size = num_inner_nodes * BVH_NODE_SIZE; - } - /* Resize arrays */ - pack.nodes.clear(); - pack.leaf_nodes.clear(); - /* For top level BVH, first merge existing BVH's so we know the offsets. */ - if(params.top_level) { - pack_instances(node_size, num_leaf_nodes*BVH_NODE_LEAF_SIZE); - } - else { - pack.nodes.resize(node_size); - pack.leaf_nodes.resize(num_leaf_nodes*BVH_NODE_LEAF_SIZE); - } - - int nextNodeIdx = 0, nextLeafNodeIdx = 0; - - vector<BVHStackEntry> stack; - stack.reserve(BVHParams::MAX_DEPTH*2); - if(root->is_leaf()) { - stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++)); - } - else { - stack.push_back(BVHStackEntry(root, nextNodeIdx)); - nextNodeIdx += node_bvh_is_unaligned(root) - ? BVH_UNALIGNED_NODE_SIZE - : BVH_NODE_SIZE; - } - - while(stack.size()) { - BVHStackEntry e = stack.back(); - stack.pop_back(); - - if(e.node->is_leaf()) { - /* leaf node */ - const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node); - pack_leaf(e, leaf); - } - else { - /* innner node */ - int idx[2]; - for(int i = 0; i < 2; ++i) { - if(e.node->get_child(i)->is_leaf()) { - idx[i] = nextLeafNodeIdx++; - } - else { - idx[i] = nextNodeIdx; - nextNodeIdx += node_bvh_is_unaligned(e.node->get_child(i)) - ? BVH_UNALIGNED_NODE_SIZE - : BVH_NODE_SIZE; - } - } - - stack.push_back(BVHStackEntry(e.node->get_child(0), idx[0])); - stack.push_back(BVHStackEntry(e.node->get_child(1), idx[1])); - - pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]); - } - } - assert(node_size == nextNodeIdx); - /* root index to start traversal at, to handle case of single leaf node */ - pack.root_index = (root->is_leaf())? -1: 0; -} - -void RegularBVH::refit_nodes() -{ - assert(!params.top_level); - - BoundBox bbox = BoundBox::empty; - uint visibility = 0; - refit_node(0, (pack.root_index == -1)? true: false, bbox, visibility); -} - -void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) -{ - if(leaf) { - assert(idx + BVH_NODE_LEAF_SIZE <= pack.leaf_nodes.size()); - const int4 *data = &pack.leaf_nodes[idx]; - const int c0 = data[0].x; - const int c1 = data[0].y; - /* refit leaf node */ - for(int prim = c0; prim < c1; prim++) { - int pidx = pack.prim_index[prim]; - int tob = pack.prim_object[prim]; - Object *ob = objects[tob]; - - if(pidx == -1) { - /* object instance */ - bbox.grow(ob->bounds); - } - else { - /* primitives */ - const Mesh *mesh = ob->mesh; - - if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { - /* curves */ - int str_offset = (params.top_level)? mesh->curve_offset: 0; - Mesh::Curve curve = mesh->get_curve(pidx - str_offset); - int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); - - curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); - - visibility |= PATH_RAY_CURVE; - - /* motion curves */ - if(mesh->use_motion_blur) { - Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if(attr) { - size_t mesh_size = mesh->curve_keys.size(); - size_t steps = mesh->motion_steps - 1; - float3 *key_steps = attr->data_float3(); - - for(size_t i = 0; i < steps; i++) - curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox); - } - } - } - else { - /* triangles */ - int tri_offset = (params.top_level)? mesh->tri_offset: 0; - Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); - const float3 *vpos = &mesh->verts[0]; - - triangle.bounds_grow(vpos, bbox); - - /* motion triangles */ - if(mesh->use_motion_blur) { - Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if(attr) { - size_t mesh_size = mesh->verts.size(); - size_t steps = mesh->motion_steps - 1; - float3 *vert_steps = attr->data_float3(); - - for(size_t i = 0; i < steps; i++) - triangle.bounds_grow(vert_steps + i*mesh_size, bbox); - } - } - } - } - - visibility |= ob->visibility; - } - - /* TODO(sergey): De-duplicate with pack_leaf(). */ - float4 leaf_data[BVH_NODE_LEAF_SIZE]; - leaf_data[0].x = __int_as_float(c0); - leaf_data[0].y = __int_as_float(c1); - leaf_data[0].z = __uint_as_float(visibility); - leaf_data[0].w = __uint_as_float(data[0].w); - memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_NODE_LEAF_SIZE); - } - else { - assert(idx + BVH_NODE_SIZE <= pack.nodes.size()); - - const int4 *data = &pack.nodes[idx]; - const bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0; - const int c0 = data[0].z; - const int c1 = data[0].w; - /* refit inner node, set bbox from children */ - BoundBox bbox0 = BoundBox::empty, bbox1 = BoundBox::empty; - uint visibility0 = 0, visibility1 = 0; - - refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0, visibility0); - refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1, visibility1); - - if(is_unaligned) { - Transform aligned_space = transform_identity(); - pack_unaligned_node(idx, - aligned_space, aligned_space, - bbox0, bbox1, - c0, c1, - visibility0, - visibility1); - } - else { - pack_aligned_node(idx, - bbox0, bbox1, - c0, c1, - visibility0, - visibility1); - } - - bbox.grow(bbox0); - bbox.grow(bbox1); - visibility = visibility0|visibility1; - } -} - -/* QBVH */ - -/* Can we avoid this somehow or make more generic? - * - * Perhaps we can merge nodes in actual tree and make our - * life easier all over the place. - */ -static bool node_qbvh_is_unaligned(const BVHNode *node) -{ - const BVHNode *node0 = node->get_child(0), - *node1 = node->get_child(1); - bool has_unaligned = false; - if(node0->is_leaf()) { - has_unaligned |= node0->is_unaligned(); - } - else { - has_unaligned |= node0->get_child(0)->is_unaligned(); - has_unaligned |= node0->get_child(1)->is_unaligned(); - } - if(node1->is_leaf()) { - has_unaligned |= node1->is_unaligned(); - } - else { - has_unaligned |= node1->get_child(0)->is_unaligned(); - has_unaligned |= node1->get_child(1)->is_unaligned(); - } - return has_unaligned; -} - -QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_) -: BVH(params_, objects_) -{ - params.use_qbvh = true; -} - -void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf) -{ - float4 data[BVH_QNODE_LEAF_SIZE]; - memset(data, 0, sizeof(data)); - if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) { - /* object */ - data[0].x = __int_as_float(~(leaf->m_lo)); - data[0].y = __int_as_float(0); - } - else { - /* triangle */ - data[0].x = __int_as_float(leaf->m_lo); - data[0].y = __int_as_float(leaf->m_hi); - } - data[0].z = __uint_as_float(leaf->m_visibility); - if(leaf->num_triangles() != 0) { - data[0].w = __uint_as_float(pack.prim_type[leaf->m_lo]); - } - - memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_QNODE_LEAF_SIZE); -} - -void QBVH::pack_inner(const BVHStackEntry& e, - const BVHStackEntry *en, - int num) -{ - bool has_unaligned = false; - /* Check whether we have to create unaligned node or all nodes are aligned - * and we can cut some corner here. - */ - if(params.use_unaligned_nodes) { - for(int i = 0; i < num; i++) { - if(en[i].node->is_unaligned()) { - has_unaligned = true; - break; - } - } - } - if(has_unaligned) { - /* There's no unaligned children, pack into AABB node. */ - pack_unaligned_inner(e, en, num); - } - else { - /* Create unaligned node with orientation transform for each of the - * children. - */ - pack_aligned_inner(e, en, num); - } -} - -void QBVH::pack_aligned_inner(const BVHStackEntry& e, - const BVHStackEntry *en, - int num) -{ - BoundBox bounds[4]; - int child[4]; - for(int i = 0; i < num; ++i) { - bounds[i] = en[i].node->m_bounds; - child[i] = en[i].encodeIdx(); - } - pack_aligned_node(e.idx, - bounds, - child, - e.node->m_visibility, - e.node->m_time_from, - e.node->m_time_to, - num); -} - -void QBVH::pack_aligned_node(int idx, - const BoundBox *bounds, - const int *child, - const uint visibility, - const float time_from, - const float time_to, - const int num) -{ - float4 data[BVH_QNODE_SIZE]; - memset(data, 0, sizeof(data)); - - data[0].x = __uint_as_float(visibility & ~PATH_RAY_NODE_UNALIGNED); - data[0].y = time_from; - data[0].z = time_to; - - for(int i = 0; i < num; i++) { - float3 bb_min = bounds[i].min; - float3 bb_max = bounds[i].max; - - data[1][i] = bb_min.x; - data[2][i] = bb_max.x; - data[3][i] = bb_min.y; - data[4][i] = bb_max.y; - data[5][i] = bb_min.z; - data[6][i] = bb_max.z; - - data[7][i] = __int_as_float(child[i]); - } - - for(int i = num; i < 4; i++) { - /* We store BB which would never be recorded as intersection - * so kernel might safely assume there are always 4 child nodes. - */ - data[1][i] = FLT_MAX; - data[2][i] = -FLT_MAX; - - data[3][i] = FLT_MAX; - data[4][i] = -FLT_MAX; - - data[5][i] = FLT_MAX; - data[6][i] = -FLT_MAX; - - data[7][i] = __int_as_float(0); - } - - memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_QNODE_SIZE); -} - -void QBVH::pack_unaligned_inner(const BVHStackEntry& e, - const BVHStackEntry *en, - int num) -{ - Transform aligned_space[4]; - BoundBox bounds[4]; - int child[4]; - for(int i = 0; i < num; ++i) { - aligned_space[i] = en[i].node->get_aligned_space(); - bounds[i] = en[i].node->m_bounds; - child[i] = en[i].encodeIdx(); - } - pack_unaligned_node(e.idx, - aligned_space, - bounds, - child, - e.node->m_visibility, - e.node->m_time_from, - e.node->m_time_to, - num); -} - -void QBVH::pack_unaligned_node(int idx, - const Transform *aligned_space, - const BoundBox *bounds, - const int *child, - const uint visibility, - const float time_from, - const float time_to, - const int num) -{ - float4 data[BVH_UNALIGNED_QNODE_SIZE]; - memset(data, 0, sizeof(data)); - - data[0].x = __uint_as_float(visibility | PATH_RAY_NODE_UNALIGNED); - data[0].y = time_from; - data[0].z = time_to; - - for(int i = 0; i < num; i++) { - Transform space = BVHUnaligned::compute_node_transform( - bounds[i], - aligned_space[i]); - - data[1][i] = space.x.x; - data[2][i] = space.x.y; - data[3][i] = space.x.z; - - data[4][i] = space.y.x; - data[5][i] = space.y.y; - data[6][i] = space.y.z; - - data[7][i] = space.z.x; - data[8][i] = space.z.y; - data[9][i] = space.z.z; - - data[10][i] = space.x.w; - data[11][i] = space.y.w; - data[12][i] = space.z.w; - - data[13][i] = __int_as_float(child[i]); - } - - for(int i = num; i < 4; i++) { - /* We store BB which would never be recorded as intersection - * 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[4][i] = 0.0f; - data[5][i] = 0.0f; - data[6][i] = 0.0f; - - data[7][i] = 0.0f; - data[8][i] = 0.0f; - data[9][i] = 0.0f; - - data[10][i] = -FLT_MAX; - data[11][i] = -FLT_MAX; - data[12][i] = -FLT_MAX; - - data[13][i] = __int_as_float(0); - } - - memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_UNALIGNED_QNODE_SIZE); -} - -/* Quad SIMD Nodes */ - -void QBVH::pack_nodes(const BVHNode *root) -{ - /* Calculate size of the arrays required. */ - const size_t num_nodes = root->getSubtreeSize(BVH_STAT_QNODE_COUNT); - const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT); - assert(num_leaf_nodes <= num_nodes); - const size_t num_inner_nodes = num_nodes - num_leaf_nodes; - size_t node_size; - if(params.use_unaligned_nodes) { - const size_t num_unaligned_nodes = - root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_QNODE_COUNT); - node_size = (num_unaligned_nodes * BVH_UNALIGNED_QNODE_SIZE) + - (num_inner_nodes - num_unaligned_nodes) * BVH_QNODE_SIZE; - } - else { - node_size = num_inner_nodes * BVH_QNODE_SIZE; - } - /* Resize arrays. */ - pack.nodes.clear(); - pack.leaf_nodes.clear(); - /* For top level BVH, first merge existing BVH's so we know the offsets. */ - if(params.top_level) { - pack_instances(node_size, num_leaf_nodes*BVH_QNODE_LEAF_SIZE); - } - else { - pack.nodes.resize(node_size); - pack.leaf_nodes.resize(num_leaf_nodes*BVH_QNODE_LEAF_SIZE); - } - - int nextNodeIdx = 0, nextLeafNodeIdx = 0; - - vector<BVHStackEntry> stack; - stack.reserve(BVHParams::MAX_DEPTH*2); - if(root->is_leaf()) { - stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++)); - } - else { - stack.push_back(BVHStackEntry(root, nextNodeIdx)); - nextNodeIdx += node_qbvh_is_unaligned(root) - ? BVH_UNALIGNED_QNODE_SIZE - : BVH_QNODE_SIZE; - } - - while(stack.size()) { - BVHStackEntry e = stack.back(); - stack.pop_back(); - - if(e.node->is_leaf()) { - /* leaf node */ - const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node); - pack_leaf(e, leaf); - } - else { - /* Inner node. */ - const BVHNode *node = e.node; - const BVHNode *node0 = node->get_child(0); - const BVHNode *node1 = node->get_child(1); - /* Collect nodes. */ - const BVHNode *nodes[4]; - int numnodes = 0; - if(node0->is_leaf()) { - nodes[numnodes++] = node0; - } - else { - nodes[numnodes++] = node0->get_child(0); - nodes[numnodes++] = node0->get_child(1); - } - if(node1->is_leaf()) { - nodes[numnodes++] = node1; - } - else { - nodes[numnodes++] = node1->get_child(0); - nodes[numnodes++] = node1->get_child(1); - } - /* Push entries on the stack. */ - for(int i = 0; i < numnodes; ++i) { - int idx; - if(nodes[i]->is_leaf()) { - idx = nextLeafNodeIdx++; - } - else { - idx = nextNodeIdx; - nextNodeIdx += node_qbvh_is_unaligned(nodes[i]) - ? BVH_UNALIGNED_QNODE_SIZE - : BVH_QNODE_SIZE; - } - stack.push_back(BVHStackEntry(nodes[i], idx)); - } - /* Set node. */ - pack_inner(e, &stack[stack.size()-numnodes], numnodes); - } - } - assert(node_size == nextNodeIdx); - /* Root index to start traversal at, to handle case of single leaf node. */ - pack.root_index = (root->is_leaf())? -1: 0; -} - -void QBVH::refit_nodes() -{ - assert(!params.top_level); - - BoundBox bbox = BoundBox::empty; - uint visibility = 0; - refit_node(0, (pack.root_index == -1)? true: false, bbox, visibility); -} - -void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) -{ - if(leaf) { - int4 *data = &pack.leaf_nodes[idx]; - int4 c = data[0]; - /* Refit leaf node. */ - for(int prim = c.x; prim < c.y; prim++) { - int pidx = pack.prim_index[prim]; - int tob = pack.prim_object[prim]; - Object *ob = objects[tob]; - - if(pidx == -1) { - /* Object instance. */ - bbox.grow(ob->bounds); - } - else { - /* Primitives. */ - const Mesh *mesh = ob->mesh; - - if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { - /* Curves. */ - int str_offset = (params.top_level)? mesh->curve_offset: 0; - Mesh::Curve curve = mesh->get_curve(pidx - str_offset); - int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); - - curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); - - visibility |= PATH_RAY_CURVE; - - /* Motion curves. */ - if(mesh->use_motion_blur) { - Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if(attr) { - size_t mesh_size = mesh->curve_keys.size(); - size_t steps = mesh->motion_steps - 1; - float3 *key_steps = attr->data_float3(); - - for(size_t i = 0; i < steps; i++) - curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox); - } - } - } - else { - /* Triangles. */ - int tri_offset = (params.top_level)? mesh->tri_offset: 0; - Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); - const float3 *vpos = &mesh->verts[0]; - - triangle.bounds_grow(vpos, bbox); - - /* Motion triangles. */ - if(mesh->use_motion_blur) { - Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if(attr) { - size_t mesh_size = mesh->verts.size(); - size_t steps = mesh->motion_steps - 1; - float3 *vert_steps = attr->data_float3(); - - for(size_t i = 0; i < steps; i++) - triangle.bounds_grow(vert_steps + i*mesh_size, bbox); - } - } - } - } - - visibility |= ob->visibility; - } - - /* 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. - * - * Would be nice to de-duplicate code, but trying to make - * making code more general ends up in much nastier code - * in my opinion so far. - * - * Same applies to the inner nodes case below. - */ - float4 leaf_data[BVH_QNODE_LEAF_SIZE]; - leaf_data[0].x = __int_as_float(c.x); - leaf_data[0].y = __int_as_float(c.y); - leaf_data[0].z = __uint_as_float(visibility); - leaf_data[0].w = __uint_as_float(c.w); - memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_QNODE_LEAF_SIZE); - } - else { - int4 *data = &pack.nodes[idx]; - bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0; - int4 c; - if(is_unaligned) { - c = data[13]; - } - else { - c = data[7]; - } - /* Refit inner node, set bbox from children. */ - BoundBox child_bbox[4] = {BoundBox::empty, - BoundBox::empty, - BoundBox::empty, - BoundBox::empty}; - uint child_visibility[4] = {0}; - int num_nodes = 0; - - for(int i = 0; i < 4; ++i) { - if(c[i] != 0) { - refit_node((c[i] < 0)? -c[i]-1: c[i], (c[i] < 0), - child_bbox[i], child_visibility[i]); - ++num_nodes; - bbox.grow(child_bbox[i]); - visibility |= child_visibility[i]; - } - } - - if(is_unaligned) { - Transform aligned_space[4] = {transform_identity(), - transform_identity(), - transform_identity(), - transform_identity()}; - pack_unaligned_node(idx, - aligned_space, - child_bbox, - &c[0], - visibility, - 0.0f, - 1.0f, - 4); - } - else { - pack_aligned_node(idx, - child_bbox, - &c[0], - visibility, - 0.0f, - 1.0f, - 4); - } - } -} - CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h index 08f41fc736f..7bac6112fd9 100644 --- a/intern/cycles/bvh/bvh.h +++ b/intern/cycles/bvh/bvh.h @@ -18,10 +18,10 @@ #ifndef __BVH_H__ #define __BVH_H__ -#include "bvh_params.h" +#include "bvh/bvh_params.h" -#include "util_types.h" -#include "util_vector.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN @@ -33,15 +33,8 @@ class LeafNode; class Object; class Progress; -#define BVH_NODE_SIZE 4 -#define BVH_NODE_LEAF_SIZE 1 -#define BVH_QNODE_SIZE 8 -#define BVH_QNODE_LEAF_SIZE 1 -#define BVH_ALIGN 4096 -#define TRI_NODE_SIZE 3 - -#define BVH_UNALIGNED_NODE_SIZE 7 -#define BVH_UNALIGNED_QNODE_SIZE 14 +#define BVH_ALIGN 4096 +#define TRI_NODE_SIZE 3 /* Packed BVH * @@ -54,7 +47,7 @@ struct PackedBVH { /* BVH leaf nodes storage. */ array<int4> leaf_nodes; /* object index to BVH node index mapping for instances */ - array<int> object_node; + array<int> object_node; /* Mapping from primitive index to index in triangle array. */ array<uint> prim_tri_index; /* Continuous storage of triangle vertices. */ @@ -110,95 +103,16 @@ protected: virtual void refit_nodes() = 0; }; -/* Regular BVH - * - * Typical BVH with each node having two children. */ - -class RegularBVH : public BVH { -protected: - /* constructor */ - friend class BVH; - RegularBVH(const BVHParams& params, const vector<Object*>& objects); - - /* pack */ - void pack_nodes(const BVHNode *root); - - void pack_leaf(const BVHStackEntry& e, - const LeafNode *leaf); - void pack_inner(const BVHStackEntry& e, - const BVHStackEntry& e0, - const BVHStackEntry& e1); - - void pack_aligned_inner(const BVHStackEntry& e, - const BVHStackEntry& e0, - const BVHStackEntry& e1); - void pack_aligned_node(int idx, - const BoundBox& b0, - const BoundBox& b1, - int c0, int c1, - uint visibility0, uint visibility1); - - void pack_unaligned_inner(const BVHStackEntry& e, - const BVHStackEntry& e0, - const BVHStackEntry& e1); - void pack_unaligned_node(int idx, - const Transform& aligned_space0, - const Transform& aligned_space1, - const BoundBox& b0, - const BoundBox& b1, - int c0, int c1, - uint visibility0, uint visibility1); - - /* refit */ - void refit_nodes(); - void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility); -}; - -/* QBVH - * - * Quad BVH, with each node having four children, to use with SIMD instructions. */ +/* Pack Utility */ +struct BVHStackEntry +{ + const BVHNode *node; + int idx; -class QBVH : public BVH { -protected: - /* constructor */ - friend class BVH; - QBVH(const BVHParams& params, const vector<Object*>& objects); - - /* pack */ - void pack_nodes(const BVHNode *root); - - void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf); - void pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num); - - void pack_aligned_inner(const BVHStackEntry& e, - const BVHStackEntry *en, - int num); - void pack_aligned_node(int idx, - const BoundBox *bounds, - const int *child, - const uint visibility, - const float time_from, - const float time_to, - const int num); - - void pack_unaligned_inner(const BVHStackEntry& e, - const BVHStackEntry *en, - int num); - void pack_unaligned_node(int idx, - const Transform *aligned_space, - const BoundBox *bounds, - const int *child, - const uint visibility, - const float time_from, - const float time_to, - const int num); - - /* refit */ - void refit_nodes(); - void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility); + BVHStackEntry(const BVHNode *n = 0, int i = 0); + int encodeIdx() const; }; CCL_NAMESPACE_END #endif /* __BVH_H__ */ - diff --git a/intern/cycles/bvh/bvh2.cpp b/intern/cycles/bvh/bvh2.cpp new file mode 100644 index 00000000000..340ba7dcf53 --- /dev/null +++ b/intern/cycles/bvh/bvh2.cpp @@ -0,0 +1,364 @@ +/* + * Adapted from code copyright 2009-2010 NVIDIA Corporation + * Modifications Copyright 2011, Blender Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bvh/bvh2.h" + +#include "render/mesh.h" +#include "render/object.h" + +#include "bvh/bvh_node.h" +#include "bvh/bvh_unaligned.h" + +CCL_NAMESPACE_BEGIN + +static bool node_bvh_is_unaligned(const BVHNode *node) +{ + const BVHNode *node0 = node->get_child(0), + *node1 = node->get_child(1); + return node0->is_unaligned || node1->is_unaligned; +} + +BVH2::BVH2(const BVHParams& params_, const vector<Object*>& objects_) +: BVH(params_, objects_) +{ +} + +void BVH2::pack_leaf(const BVHStackEntry& e, + const LeafNode *leaf) +{ + assert(e.idx + BVH_NODE_LEAF_SIZE <= pack.leaf_nodes.size()); + float4 data[BVH_NODE_LEAF_SIZE]; + memset(data, 0, sizeof(data)); + if(leaf->num_triangles() == 1 && pack.prim_index[leaf->lo] == -1) { + /* object */ + data[0].x = __int_as_float(~(leaf->lo)); + data[0].y = __int_as_float(0); + } + else { + /* triangle */ + data[0].x = __int_as_float(leaf->lo); + data[0].y = __int_as_float(leaf->hi); + } + data[0].z = __uint_as_float(leaf->visibility); + if(leaf->num_triangles() != 0) { + data[0].w = __uint_as_float(pack.prim_type[leaf->lo]); + } + + memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_NODE_LEAF_SIZE); +} + +void BVH2::pack_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1) +{ + if(e0.node->is_unaligned || e1.node->is_unaligned) { + pack_unaligned_inner(e, e0, e1); + } else { + pack_aligned_inner(e, e0, e1); + } +} + +void BVH2::pack_aligned_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1) +{ + pack_aligned_node(e.idx, + e0.node->bounds, e1.node->bounds, + e0.encodeIdx(), e1.encodeIdx(), + e0.node->visibility, e1.node->visibility); +} + +void BVH2::pack_aligned_node(int idx, + const BoundBox& b0, + const BoundBox& b1, + int c0, int c1, + uint visibility0, uint visibility1) +{ + assert(idx + BVH_NODE_SIZE <= pack.nodes.size()); + assert(c0 < 0 || c0 < pack.nodes.size()); + assert(c1 < 0 || c1 < pack.nodes.size()); + + int4 data[BVH_NODE_SIZE] = { + make_int4(visibility0 & ~PATH_RAY_NODE_UNALIGNED, + visibility1 & ~PATH_RAY_NODE_UNALIGNED, + c0, c1), + make_int4(__float_as_int(b0.min.x), + __float_as_int(b1.min.x), + __float_as_int(b0.max.x), + __float_as_int(b1.max.x)), + make_int4(__float_as_int(b0.min.y), + __float_as_int(b1.min.y), + __float_as_int(b0.max.y), + __float_as_int(b1.max.y)), + make_int4(__float_as_int(b0.min.z), + __float_as_int(b1.min.z), + __float_as_int(b0.max.z), + __float_as_int(b1.max.z)), + }; + + memcpy(&pack.nodes[idx], data, sizeof(int4)*BVH_NODE_SIZE); +} + +void BVH2::pack_unaligned_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1) +{ + pack_unaligned_node(e.idx, + e0.node->get_aligned_space(), + e1.node->get_aligned_space(), + e0.node->bounds, + e1.node->bounds, + e0.encodeIdx(), e1.encodeIdx(), + e0.node->visibility, e1.node->visibility); +} + +void BVH2::pack_unaligned_node(int idx, + const Transform& aligned_space0, + const Transform& aligned_space1, + const BoundBox& bounds0, + const BoundBox& bounds1, + int c0, int c1, + uint visibility0, uint visibility1) +{ + assert(idx + BVH_UNALIGNED_NODE_SIZE <= pack.nodes.size()); + assert(c0 < 0 || c0 < pack.nodes.size()); + assert(c1 < 0 || c1 < pack.nodes.size()); + + float4 data[BVH_UNALIGNED_NODE_SIZE]; + Transform space0 = BVHUnaligned::compute_node_transform(bounds0, + aligned_space0); + Transform space1 = BVHUnaligned::compute_node_transform(bounds1, + aligned_space1); + data[0] = make_float4(__int_as_float(visibility0 | PATH_RAY_NODE_UNALIGNED), + __int_as_float(visibility1 | PATH_RAY_NODE_UNALIGNED), + __int_as_float(c0), + __int_as_float(c1)); + + data[1] = space0.x; + data[2] = space0.y; + data[3] = space0.z; + data[4] = space1.x; + data[5] = space1.y; + data[6] = space1.z; + + memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_UNALIGNED_NODE_SIZE); +} + +void BVH2::pack_nodes(const BVHNode *root) +{ + const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT); + const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT); + assert(num_leaf_nodes <= num_nodes); + const size_t num_inner_nodes = num_nodes - num_leaf_nodes; + size_t node_size; + if(params.use_unaligned_nodes) { + const size_t num_unaligned_nodes = + root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT); + node_size = (num_unaligned_nodes * BVH_UNALIGNED_NODE_SIZE) + + (num_inner_nodes - num_unaligned_nodes) * BVH_NODE_SIZE; + } + else { + node_size = num_inner_nodes * BVH_NODE_SIZE; + } + /* Resize arrays */ + pack.nodes.clear(); + pack.leaf_nodes.clear(); + /* For top level BVH, first merge existing BVH's so we know the offsets. */ + if(params.top_level) { + pack_instances(node_size, num_leaf_nodes*BVH_NODE_LEAF_SIZE); + } + else { + pack.nodes.resize(node_size); + pack.leaf_nodes.resize(num_leaf_nodes*BVH_NODE_LEAF_SIZE); + } + + int nextNodeIdx = 0, nextLeafNodeIdx = 0; + + vector<BVHStackEntry> stack; + stack.reserve(BVHParams::MAX_DEPTH*2); + if(root->is_leaf()) { + stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++)); + } + else { + stack.push_back(BVHStackEntry(root, nextNodeIdx)); + nextNodeIdx += node_bvh_is_unaligned(root) + ? BVH_UNALIGNED_NODE_SIZE + : BVH_NODE_SIZE; + } + + while(stack.size()) { + BVHStackEntry e = stack.back(); + stack.pop_back(); + + if(e.node->is_leaf()) { + /* leaf node */ + const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node); + pack_leaf(e, leaf); + } + else { + /* innner node */ + int idx[2]; + for(int i = 0; i < 2; ++i) { + if(e.node->get_child(i)->is_leaf()) { + idx[i] = nextLeafNodeIdx++; + } + else { + idx[i] = nextNodeIdx; + nextNodeIdx += node_bvh_is_unaligned(e.node->get_child(i)) + ? BVH_UNALIGNED_NODE_SIZE + : BVH_NODE_SIZE; + } + } + + stack.push_back(BVHStackEntry(e.node->get_child(0), idx[0])); + stack.push_back(BVHStackEntry(e.node->get_child(1), idx[1])); + + pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]); + } + } + assert(node_size == nextNodeIdx); + /* root index to start traversal at, to handle case of single leaf node */ + pack.root_index = (root->is_leaf())? -1: 0; +} + +void BVH2::refit_nodes() +{ + assert(!params.top_level); + + BoundBox bbox = BoundBox::empty; + uint visibility = 0; + refit_node(0, (pack.root_index == -1)? true: false, bbox, visibility); +} + +void BVH2::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) +{ + if(leaf) { + assert(idx + BVH_NODE_LEAF_SIZE <= pack.leaf_nodes.size()); + const int4 *data = &pack.leaf_nodes[idx]; + const int c0 = data[0].x; + const int c1 = data[0].y; + /* refit leaf node */ + for(int prim = c0; prim < c1; prim++) { + int pidx = pack.prim_index[prim]; + int tob = pack.prim_object[prim]; + Object *ob = objects[tob]; + + if(pidx == -1) { + /* object instance */ + bbox.grow(ob->bounds); + } + else { + /* primitives */ + const Mesh *mesh = ob->mesh; + + if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { + /* curves */ + int str_offset = (params.top_level)? mesh->curve_offset: 0; + Mesh::Curve curve = mesh->get_curve(pidx - str_offset); + int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); + + curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); + + visibility |= PATH_RAY_CURVE; + + /* motion curves */ + if(mesh->use_motion_blur) { + Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if(attr) { + size_t mesh_size = mesh->curve_keys.size(); + size_t steps = mesh->motion_steps - 1; + float3 *key_steps = attr->data_float3(); + + for(size_t i = 0; i < steps; i++) + curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox); + } + } + } + else { + /* triangles */ + int tri_offset = (params.top_level)? mesh->tri_offset: 0; + Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); + const float3 *vpos = &mesh->verts[0]; + + triangle.bounds_grow(vpos, bbox); + + /* motion triangles */ + if(mesh->use_motion_blur) { + Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if(attr) { + size_t mesh_size = mesh->verts.size(); + size_t steps = mesh->motion_steps - 1; + float3 *vert_steps = attr->data_float3(); + + for(size_t i = 0; i < steps; i++) + triangle.bounds_grow(vert_steps + i*mesh_size, bbox); + } + } + } + } + + visibility |= ob->visibility; + } + + /* TODO(sergey): De-duplicate with pack_leaf(). */ + float4 leaf_data[BVH_NODE_LEAF_SIZE]; + leaf_data[0].x = __int_as_float(c0); + leaf_data[0].y = __int_as_float(c1); + leaf_data[0].z = __uint_as_float(visibility); + leaf_data[0].w = __uint_as_float(data[0].w); + memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_NODE_LEAF_SIZE); + } + else { + assert(idx + BVH_NODE_SIZE <= pack.nodes.size()); + + const int4 *data = &pack.nodes[idx]; + const bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0; + const int c0 = data[0].z; + const int c1 = data[0].w; + /* refit inner node, set bbox from children */ + BoundBox bbox0 = BoundBox::empty, bbox1 = BoundBox::empty; + uint visibility0 = 0, visibility1 = 0; + + refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0, visibility0); + refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1, visibility1); + + if(is_unaligned) { + Transform aligned_space = transform_identity(); + pack_unaligned_node(idx, + aligned_space, aligned_space, + bbox0, bbox1, + c0, c1, + visibility0, + visibility1); + } + else { + pack_aligned_node(idx, + bbox0, bbox1, + c0, c1, + visibility0, + visibility1); + } + + bbox.grow(bbox0); + bbox.grow(bbox1); + visibility = visibility0|visibility1; + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh2.h b/intern/cycles/bvh/bvh2.h new file mode 100644 index 00000000000..df65ddca5b7 --- /dev/null +++ b/intern/cycles/bvh/bvh2.h @@ -0,0 +1,87 @@ +/* + * Adapted from code copyright 2009-2010 NVIDIA Corporation + * Modifications Copyright 2011, 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 __BVH2_H__ +#define __BVH2_H__ + +#include "bvh/bvh.h" +#include "bvh/bvh_params.h" + +#include "util/util_types.h" +#include "util/util_vector.h" + +CCL_NAMESPACE_BEGIN + +class BVHNode; +struct BVHStackEntry; +class BVHParams; +class BoundBox; +class LeafNode; +class Object; +class Progress; + +#define BVH_NODE_SIZE 4 +#define BVH_NODE_LEAF_SIZE 1 +#define BVH_UNALIGNED_NODE_SIZE 7 + +/* BVH2 + * + * Typical BVH with each node having two children. + */ +class BVH2 : public BVH { +protected: + /* constructor */ + friend class BVH; + BVH2(const BVHParams& params, const vector<Object*>& objects); + + /* pack */ + void pack_nodes(const BVHNode *root); + + void pack_leaf(const BVHStackEntry& e, + const LeafNode *leaf); + void pack_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1); + + void pack_aligned_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1); + void pack_aligned_node(int idx, + const BoundBox& b0, + const BoundBox& b1, + int c0, int c1, + uint visibility0, uint visibility1); + + void pack_unaligned_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1); + void pack_unaligned_node(int idx, + const Transform& aligned_space0, + const Transform& aligned_space1, + const BoundBox& b0, + const BoundBox& b1, + int c0, int c1, + uint visibility0, uint visibility1); + + /* refit */ + void refit_nodes(); + void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility); +}; + +CCL_NAMESPACE_END + +#endif /* __BVH2_H__ */ diff --git a/intern/cycles/bvh/bvh4.cpp b/intern/cycles/bvh/bvh4.cpp new file mode 100644 index 00000000000..5034ab811d5 --- /dev/null +++ b/intern/cycles/bvh/bvh4.cpp @@ -0,0 +1,516 @@ +/* + * Adapted from code copyright 2009-2010 NVIDIA Corporation + * Modifications Copyright 2011, Blender Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bvh/bvh4.h" + +#include "render/mesh.h" +#include "render/object.h" + +#include "bvh/bvh_node.h" +#include "bvh/bvh_unaligned.h" + +CCL_NAMESPACE_BEGIN + +/* Can we avoid this somehow or make more generic? + * + * Perhaps we can merge nodes in actual tree and make our + * life easier all over the place. + */ +static bool node_qbvh_is_unaligned(const BVHNode *node) +{ + const BVHNode *node0 = node->get_child(0), + *node1 = node->get_child(1); + bool has_unaligned = false; + if(node0->is_leaf()) { + has_unaligned |= node0->is_unaligned; + } + else { + has_unaligned |= node0->get_child(0)->is_unaligned; + has_unaligned |= node0->get_child(1)->is_unaligned; + } + if(node1->is_leaf()) { + has_unaligned |= node1->is_unaligned; + } + else { + has_unaligned |= node1->get_child(0)->is_unaligned; + has_unaligned |= node1->get_child(1)->is_unaligned; + } + return has_unaligned; +} + +BVH4::BVH4(const BVHParams& params_, const vector<Object*>& objects_) +: BVH(params_, objects_) +{ + params.use_qbvh = true; +} + +void BVH4::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf) +{ + float4 data[BVH_QNODE_LEAF_SIZE]; + memset(data, 0, sizeof(data)); + if(leaf->num_triangles() == 1 && pack.prim_index[leaf->lo] == -1) { + /* object */ + data[0].x = __int_as_float(~(leaf->lo)); + data[0].y = __int_as_float(0); + } + else { + /* triangle */ + data[0].x = __int_as_float(leaf->lo); + data[0].y = __int_as_float(leaf->hi); + } + data[0].z = __uint_as_float(leaf->visibility); + if(leaf->num_triangles() != 0) { + data[0].w = __uint_as_float(pack.prim_type[leaf->lo]); + } + + memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_QNODE_LEAF_SIZE); +} + +void BVH4::pack_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num) +{ + bool has_unaligned = false; + /* Check whether we have to create unaligned node or all nodes are aligned + * and we can cut some corner here. + */ + if(params.use_unaligned_nodes) { + for(int i = 0; i < num; i++) { + if(en[i].node->is_unaligned) { + has_unaligned = true; + break; + } + } + } + if(has_unaligned) { + /* There's no unaligned children, pack into AABB node. */ + pack_unaligned_inner(e, en, num); + } + else { + /* Create unaligned node with orientation transform for each of the + * children. + */ + pack_aligned_inner(e, en, num); + } +} + +void BVH4::pack_aligned_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num) +{ + BoundBox bounds[4]; + int child[4]; + for(int i = 0; i < num; ++i) { + bounds[i] = en[i].node->bounds; + child[i] = en[i].encodeIdx(); + } + pack_aligned_node(e.idx, + bounds, + child, + e.node->visibility, + e.node->time_from, + e.node->time_to, + num); +} + +void BVH4::pack_aligned_node(int idx, + const BoundBox *bounds, + const int *child, + const uint visibility, + const float time_from, + const float time_to, + const int num) +{ + float4 data[BVH_QNODE_SIZE]; + memset(data, 0, sizeof(data)); + + data[0].x = __uint_as_float(visibility & ~PATH_RAY_NODE_UNALIGNED); + data[0].y = time_from; + data[0].z = time_to; + + for(int i = 0; i < num; i++) { + float3 bb_min = bounds[i].min; + float3 bb_max = bounds[i].max; + + data[1][i] = bb_min.x; + data[2][i] = bb_max.x; + data[3][i] = bb_min.y; + data[4][i] = bb_max.y; + data[5][i] = bb_min.z; + data[6][i] = bb_max.z; + + data[7][i] = __int_as_float(child[i]); + } + + for(int i = num; i < 4; i++) { + /* We store BB which would never be recorded as intersection + * so kernel might safely assume there are always 4 child nodes. + */ + data[1][i] = FLT_MAX; + data[2][i] = -FLT_MAX; + + data[3][i] = FLT_MAX; + data[4][i] = -FLT_MAX; + + data[5][i] = FLT_MAX; + data[6][i] = -FLT_MAX; + + data[7][i] = __int_as_float(0); + } + + memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_QNODE_SIZE); +} + +void BVH4::pack_unaligned_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num) +{ + Transform aligned_space[4]; + BoundBox bounds[4]; + int child[4]; + for(int i = 0; i < num; ++i) { + aligned_space[i] = en[i].node->get_aligned_space(); + bounds[i] = en[i].node->bounds; + child[i] = en[i].encodeIdx(); + } + pack_unaligned_node(e.idx, + aligned_space, + bounds, + child, + e.node->visibility, + e.node->time_from, + e.node->time_to, + num); +} + +void BVH4::pack_unaligned_node(int idx, + const Transform *aligned_space, + const BoundBox *bounds, + const int *child, + const uint visibility, + const float time_from, + const float time_to, + const int num) +{ + float4 data[BVH_UNALIGNED_QNODE_SIZE]; + memset(data, 0, sizeof(data)); + + data[0].x = __uint_as_float(visibility | PATH_RAY_NODE_UNALIGNED); + data[0].y = time_from; + data[0].z = time_to; + + for(int i = 0; i < num; i++) { + Transform space = BVHUnaligned::compute_node_transform( + bounds[i], + aligned_space[i]); + + data[1][i] = space.x.x; + data[2][i] = space.x.y; + data[3][i] = space.x.z; + + data[4][i] = space.y.x; + data[5][i] = space.y.y; + data[6][i] = space.y.z; + + data[7][i] = space.z.x; + data[8][i] = space.z.y; + data[9][i] = space.z.z; + + data[10][i] = space.x.w; + data[11][i] = space.y.w; + data[12][i] = space.z.w; + + data[13][i] = __int_as_float(child[i]); + } + + for(int i = num; i < 4; i++) { + /* We store BB which would never be recorded as intersection + * 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[4][i] = 0.0f; + data[5][i] = 0.0f; + data[6][i] = 0.0f; + + data[7][i] = 0.0f; + data[8][i] = 0.0f; + data[9][i] = 0.0f; + + data[10][i] = -FLT_MAX; + data[11][i] = -FLT_MAX; + data[12][i] = -FLT_MAX; + + data[13][i] = __int_as_float(0); + } + + memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_UNALIGNED_QNODE_SIZE); +} + +/* Quad SIMD Nodes */ + +void BVH4::pack_nodes(const BVHNode *root) +{ + /* Calculate size of the arrays required. */ + const size_t num_nodes = root->getSubtreeSize(BVH_STAT_QNODE_COUNT); + const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT); + assert(num_leaf_nodes <= num_nodes); + const size_t num_inner_nodes = num_nodes - num_leaf_nodes; + size_t node_size; + if(params.use_unaligned_nodes) { + const size_t num_unaligned_nodes = + root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_QNODE_COUNT); + node_size = (num_unaligned_nodes * BVH_UNALIGNED_QNODE_SIZE) + + (num_inner_nodes - num_unaligned_nodes) * BVH_QNODE_SIZE; + } + else { + node_size = num_inner_nodes * BVH_QNODE_SIZE; + } + /* Resize arrays. */ + pack.nodes.clear(); + pack.leaf_nodes.clear(); + /* For top level BVH, first merge existing BVH's so we know the offsets. */ + if(params.top_level) { + pack_instances(node_size, num_leaf_nodes*BVH_QNODE_LEAF_SIZE); + } + else { + pack.nodes.resize(node_size); + pack.leaf_nodes.resize(num_leaf_nodes*BVH_QNODE_LEAF_SIZE); + } + + int nextNodeIdx = 0, nextLeafNodeIdx = 0; + + vector<BVHStackEntry> stack; + stack.reserve(BVHParams::MAX_DEPTH*2); + if(root->is_leaf()) { + stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++)); + } + else { + stack.push_back(BVHStackEntry(root, nextNodeIdx)); + nextNodeIdx += node_qbvh_is_unaligned(root) + ? BVH_UNALIGNED_QNODE_SIZE + : BVH_QNODE_SIZE; + } + + while(stack.size()) { + BVHStackEntry e = stack.back(); + stack.pop_back(); + + if(e.node->is_leaf()) { + /* leaf node */ + const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node); + pack_leaf(e, leaf); + } + else { + /* Inner node. */ + const BVHNode *node = e.node; + const BVHNode *node0 = node->get_child(0); + const BVHNode *node1 = node->get_child(1); + /* Collect nodes. */ + const BVHNode *nodes[4]; + int numnodes = 0; + if(node0->is_leaf()) { + nodes[numnodes++] = node0; + } + else { + nodes[numnodes++] = node0->get_child(0); + nodes[numnodes++] = node0->get_child(1); + } + if(node1->is_leaf()) { + nodes[numnodes++] = node1; + } + else { + nodes[numnodes++] = node1->get_child(0); + nodes[numnodes++] = node1->get_child(1); + } + /* Push entries on the stack. */ + for(int i = 0; i < numnodes; ++i) { + int idx; + if(nodes[i]->is_leaf()) { + idx = nextLeafNodeIdx++; + } + else { + idx = nextNodeIdx; + nextNodeIdx += node_qbvh_is_unaligned(nodes[i]) + ? BVH_UNALIGNED_QNODE_SIZE + : BVH_QNODE_SIZE; + } + stack.push_back(BVHStackEntry(nodes[i], idx)); + } + /* Set node. */ + pack_inner(e, &stack[stack.size()-numnodes], numnodes); + } + } + assert(node_size == nextNodeIdx); + /* Root index to start traversal at, to handle case of single leaf node. */ + pack.root_index = (root->is_leaf())? -1: 0; +} + +void BVH4::refit_nodes() +{ + assert(!params.top_level); + + BoundBox bbox = BoundBox::empty; + uint visibility = 0; + refit_node(0, (pack.root_index == -1)? true: false, bbox, visibility); +} + +void BVH4::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) +{ + if(leaf) { + int4 *data = &pack.leaf_nodes[idx]; + int4 c = data[0]; + /* Refit leaf node. */ + for(int prim = c.x; prim < c.y; prim++) { + int pidx = pack.prim_index[prim]; + int tob = pack.prim_object[prim]; + Object *ob = objects[tob]; + + if(pidx == -1) { + /* Object instance. */ + bbox.grow(ob->bounds); + } + else { + /* Primitives. */ + const Mesh *mesh = ob->mesh; + + if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { + /* Curves. */ + int str_offset = (params.top_level)? mesh->curve_offset: 0; + Mesh::Curve curve = mesh->get_curve(pidx - str_offset); + int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); + + curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); + + visibility |= PATH_RAY_CURVE; + + /* Motion curves. */ + if(mesh->use_motion_blur) { + Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if(attr) { + size_t mesh_size = mesh->curve_keys.size(); + size_t steps = mesh->motion_steps - 1; + float3 *key_steps = attr->data_float3(); + + for(size_t i = 0; i < steps; i++) + curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox); + } + } + } + else { + /* Triangles. */ + int tri_offset = (params.top_level)? mesh->tri_offset: 0; + Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); + const float3 *vpos = &mesh->verts[0]; + + triangle.bounds_grow(vpos, bbox); + + /* Motion triangles. */ + if(mesh->use_motion_blur) { + Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if(attr) { + size_t mesh_size = mesh->verts.size(); + size_t steps = mesh->motion_steps - 1; + float3 *vert_steps = attr->data_float3(); + + for(size_t i = 0; i < steps; i++) + triangle.bounds_grow(vert_steps + i*mesh_size, bbox); + } + } + } + } + + visibility |= ob->visibility; + } + + /* 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. + * + * Would be nice to de-duplicate code, but trying to make + * making code more general ends up in much nastier code + * in my opinion so far. + * + * Same applies to the inner nodes case below. + */ + float4 leaf_data[BVH_QNODE_LEAF_SIZE]; + leaf_data[0].x = __int_as_float(c.x); + leaf_data[0].y = __int_as_float(c.y); + leaf_data[0].z = __uint_as_float(visibility); + leaf_data[0].w = __uint_as_float(c.w); + memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_QNODE_LEAF_SIZE); + } + else { + int4 *data = &pack.nodes[idx]; + bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0; + int4 c; + if(is_unaligned) { + c = data[13]; + } + else { + c = data[7]; + } + /* Refit inner node, set bbox from children. */ + BoundBox child_bbox[4] = {BoundBox::empty, + BoundBox::empty, + BoundBox::empty, + BoundBox::empty}; + uint child_visibility[4] = {0}; + int num_nodes = 0; + + for(int i = 0; i < 4; ++i) { + if(c[i] != 0) { + refit_node((c[i] < 0)? -c[i]-1: c[i], (c[i] < 0), + child_bbox[i], child_visibility[i]); + ++num_nodes; + bbox.grow(child_bbox[i]); + visibility |= child_visibility[i]; + } + } + + if(is_unaligned) { + Transform aligned_space[4] = {transform_identity(), + transform_identity(), + transform_identity(), + transform_identity()}; + pack_unaligned_node(idx, + aligned_space, + child_bbox, + &c[0], + visibility, + 0.0f, + 1.0f, + 4); + } + else { + pack_aligned_node(idx, + child_bbox, + &c[0], + visibility, + 0.0f, + 1.0f, + 4); + } + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh4.h b/intern/cycles/bvh/bvh4.h new file mode 100644 index 00000000000..310909a37e1 --- /dev/null +++ b/intern/cycles/bvh/bvh4.h @@ -0,0 +1,87 @@ +/* + * Adapted from code copyright 2009-2010 NVIDIA Corporation + * Modifications Copyright 2011, 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 __BVH4_H__ +#define __BVH4_H__ + +#include "bvh/bvh.h" +#include "bvh/bvh_params.h" + +#include "util/util_types.h" +#include "util/util_vector.h" + +CCL_NAMESPACE_BEGIN + +class BVHNode; +struct BVHStackEntry; +class BVHParams; +class BoundBox; +class LeafNode; +class Object; +class Progress; + +#define BVH_QNODE_SIZE 8 +#define BVH_QNODE_LEAF_SIZE 1 +#define BVH_UNALIGNED_QNODE_SIZE 14 + +/* BVH4 + * + * Quad BVH, with each node having four children, to use with SIMD instructions. + */ +class BVH4 : public BVH { +protected: + /* constructor */ + friend class BVH; + BVH4(const BVHParams& params, const vector<Object*>& objects); + + /* pack */ + void pack_nodes(const BVHNode *root); + + void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf); + void pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num); + + void pack_aligned_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num); + void pack_aligned_node(int idx, + const BoundBox *bounds, + const int *child, + const uint visibility, + const float time_from, + const float time_to, + const int num); + + void pack_unaligned_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num); + void pack_unaligned_node(int idx, + const Transform *aligned_space, + const BoundBox *bounds, + const int *child, + const uint visibility, + const float time_from, + const float time_to, + const int num); + + /* refit */ + void refit_nodes(); + void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility); +}; + +CCL_NAMESPACE_END + +#endif /* __BVH4_H__ */ diff --git a/intern/cycles/bvh/bvh_binning.cpp b/intern/cycles/bvh/bvh_binning.cpp index 5ddd7349f7b..63a7fc11668 100644 --- a/intern/cycles/bvh/bvh_binning.cpp +++ b/intern/cycles/bvh/bvh_binning.cpp @@ -17,13 +17,13 @@ //#define __KERNEL_SSE__ -#include <stdlib.h> +#include "bvh/bvh_binning.h" -#include "bvh_binning.h" +#include <stdlib.h> -#include "util_algorithm.h" -#include "util_boundbox.h" -#include "util_types.h" +#include "util/util_algorithm.h" +#include "util/util_boundbox.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/bvh/bvh_binning.h b/intern/cycles/bvh/bvh_binning.h index 52955f70151..c2e259b1696 100644 --- a/intern/cycles/bvh/bvh_binning.h +++ b/intern/cycles/bvh/bvh_binning.h @@ -18,10 +18,10 @@ #ifndef __BVH_BINNING_H__ #define __BVH_BINNING_H__ -#include "bvh_params.h" -#include "bvh_unaligned.h" +#include "bvh/bvh_params.h" +#include "bvh/bvh_unaligned.h" -#include "util_types.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN @@ -111,5 +111,4 @@ protected: CCL_NAMESPACE_END -#endif - +#endif /* __BVH_BINNING_H__ */ diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 517afc75641..1880964355c 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -15,26 +15,27 @@ * limitations under the License. */ -#include "bvh_binning.h" -#include "bvh_build.h" -#include "bvh_node.h" -#include "bvh_params.h" +#include "bvh/bvh_build.h" + +#include "bvh/bvh_binning.h" +#include "bvh/bvh_node.h" +#include "bvh/bvh_params.h" #include "bvh_split.h" -#include "mesh.h" -#include "object.h" -#include "scene.h" -#include "curves.h" - -#include "util_algorithm.h" -#include "util_debug.h" -#include "util_foreach.h" -#include "util_logging.h" -#include "util_progress.h" -#include "util_stack_allocator.h" -#include "util_simd.h" -#include "util_time.h" -#include "util_queue.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" +#include "render/curves.h" + +#include "util/util_algorithm.h" +#include "util/util_debug.h" +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_progress.h" +#include "util/util_stack_allocator.h" +#include "util/util_simd.h" +#include "util/util_time.h" +#include "util/util_queue.h" CCL_NAMESPACE_BEGIN @@ -866,8 +867,8 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, uint visibility = objects[ref->prim_object()]->visibility; BVHNode *leaf_node = new LeafNode(ref->bounds(), visibility, start, start+1); - leaf_node->m_time_from = ref->time_from(); - leaf_node->m_time_to = ref->time_to(); + leaf_node->time_from = ref->time_from(); + leaf_node->time_to = ref->time_to(); return leaf_node; } else { @@ -876,12 +877,12 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, BVHNode *leaf1 = create_object_leaf_nodes(ref+mid, start+mid, num-mid); BoundBox bounds = BoundBox::empty; - bounds.grow(leaf0->m_bounds); - bounds.grow(leaf1->m_bounds); + bounds.grow(leaf0->bounds); + bounds.grow(leaf1->bounds); BVHNode *inner_node = new InnerNode(bounds, leaf0, leaf1); - inner_node->m_time_from = min(leaf0->m_time_from, leaf1->m_time_from); - inner_node->m_time_to = max(leaf0->m_time_to, leaf1->m_time_to); + inner_node->time_from = min(leaf0->time_from, leaf1->time_from); + inner_node->time_to = max(leaf0->time_to, leaf1->time_to); return inner_node; } } @@ -1004,19 +1005,19 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, time_from = min(time_from, ref.time_from()); time_to = max(time_to, ref.time_to()); } - leaf_node->m_time_from = time_from; - leaf_node->m_time_to = time_to; + leaf_node->time_from = time_from; + leaf_node->time_to = time_to; } if(alignment_found) { /* Need to recalculate leaf bounds with new alignment. */ - leaf_node->m_bounds = BoundBox::empty; + leaf_node->bounds = BoundBox::empty; for(int j = 0; j < num; ++j) { const BVHReference &ref = p_ref[i][j]; BoundBox ref_bounds = unaligned_heuristic.compute_aligned_prim_boundbox( ref, aligned_space); - leaf_node->m_bounds.grow(ref_bounds); + leaf_node->bounds.grow(ref_bounds); } /* Set alignment space. */ leaf_node->set_aligned_space(aligned_space); @@ -1099,8 +1100,8 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, */ for(int i = 0; i < num_leaves; ++i) { LeafNode *leaf = (LeafNode *)leaves[i]; - leaf->m_lo += start_index; - leaf->m_hi += start_index; + leaf->lo += start_index; + leaf->hi += start_index; } /* Create leaf node for object. */ @@ -1129,17 +1130,17 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, return new InnerNode(range.bounds(), leaves[0], leaves[1]); } else if(num_leaves == 3) { - BoundBox inner_bounds = merge(leaves[1]->m_bounds, leaves[2]->m_bounds); + BoundBox inner_bounds = merge(leaves[1]->bounds, leaves[2]->bounds); BVHNode *inner = new InnerNode(inner_bounds, leaves[1], leaves[2]); return new InnerNode(range.bounds(), leaves[0], inner); } else { /* Should be doing more branches if more primitive types added. */ assert(num_leaves <= 5); - BoundBox inner_bounds_a = merge(leaves[0]->m_bounds, leaves[1]->m_bounds); - BoundBox inner_bounds_b = merge(leaves[2]->m_bounds, leaves[3]->m_bounds); + BoundBox inner_bounds_a = merge(leaves[0]->bounds, leaves[1]->bounds); + BoundBox inner_bounds_b = merge(leaves[2]->bounds, leaves[3]->bounds); BVHNode *inner_a = new InnerNode(inner_bounds_a, leaves[0], leaves[1]); BVHNode *inner_b = new InnerNode(inner_bounds_b, leaves[2], leaves[3]); - BoundBox inner_bounds_c = merge(inner_a->m_bounds, inner_b->m_bounds); + BoundBox inner_bounds_c = merge(inner_a->bounds, inner_b->bounds); BVHNode *inner_c = new InnerNode(inner_bounds_c, inner_a, inner_b); if(num_leaves == 5) { return new InnerNode(range.bounds(), inner_c, leaves[4]); @@ -1174,8 +1175,8 @@ void BVHBuild::rotate(BVHNode *node, int max_depth) rotate(parent->children[c], max_depth-1); /* compute current area of all children */ - BoundBox bounds0 = parent->children[0]->m_bounds; - BoundBox bounds1 = parent->children[1]->m_bounds; + BoundBox bounds0 = parent->children[0]->bounds; + BoundBox bounds1 = parent->children[1]->bounds; float area0 = bounds0.half_area(); float area1 = bounds1.half_area(); @@ -1195,8 +1196,8 @@ void BVHBuild::rotate(BVHNode *node, int max_depth) BoundBox& other = (c == 0)? bounds1: bounds0; /* transpose child bounds */ - BoundBox target0 = child->children[0]->m_bounds; - BoundBox target1 = child->children[1]->m_bounds; + BoundBox target0 = child->children[0]->bounds; + BoundBox target1 = child->children[1]->bounds; /* compute cost for both possible swaps */ float cost0 = merge(other, target1).half_area() - child_area[c]; @@ -1228,7 +1229,7 @@ void BVHBuild::rotate(BVHNode *node, int max_depth) InnerNode *child = (InnerNode*)parent->children[best_child]; swap(parent->children[best_other], child->children[best_target]); - child->m_bounds = merge(child->children[0]->m_bounds, child->children[1]->m_bounds); + child->bounds = merge(child->children[0]->bounds, child->children[1]->bounds); } CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h index 430efc3e0f6..7b245139819 100644 --- a/intern/cycles/bvh/bvh_build.h +++ b/intern/cycles/bvh/bvh_build.h @@ -20,17 +20,17 @@ #include <float.h> -#include "bvh.h" -#include "bvh_binning.h" -#include "bvh_unaligned.h" +#include "bvh/bvh_params.h" +#include "bvh/bvh_unaligned.h" -#include "util_boundbox.h" -#include "util_task.h" -#include "util_vector.h" +#include "util/util_task.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN +class Boundbox; class BVHBuildTask; +class BVHNode; class BVHSpatialSplitBuildTask; class BVHParams; class InnerNode; diff --git a/intern/cycles/bvh/bvh_node.cpp b/intern/cycles/bvh/bvh_node.cpp index 67580e1bc7b..4237c62ab5b 100644 --- a/intern/cycles/bvh/bvh_node.cpp +++ b/intern/cycles/bvh/bvh_node.cpp @@ -15,12 +15,13 @@ * limitations under the License. */ -#include "bvh.h" -#include "bvh_build.h" -#include "bvh_node.h" +#include "bvh/bvh_node.h" -#include "util_debug.h" -#include "util_vector.h" +#include "bvh/bvh.h" +#include "bvh/bvh_build.h" + +#include "util/util_debug.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN @@ -62,12 +63,12 @@ int BVHNode::getSubtreeSize(BVH_STAT stat) const } return cnt; case BVH_STAT_ALIGNED_COUNT: - if(!is_unaligned()) { + if(!is_unaligned) { cnt = 1; } break; case BVH_STAT_UNALIGNED_COUNT: - if(is_unaligned()) { + if(is_unaligned) { cnt = 1; } break; @@ -75,7 +76,7 @@ int BVHNode::getSubtreeSize(BVH_STAT stat) const if(!is_leaf()) { bool has_unaligned = false; for(int j = 0; j < num_children(); j++) { - has_unaligned |= get_child(j)->is_unaligned(); + has_unaligned |= get_child(j)->is_unaligned; } cnt += has_unaligned? 0: 1; } @@ -84,7 +85,7 @@ int BVHNode::getSubtreeSize(BVH_STAT stat) const if(!is_leaf()) { bool has_unaligned = false; for(int j = 0; j < num_children(); j++) { - has_unaligned |= get_child(j)->is_unaligned(); + has_unaligned |= get_child(j)->is_unaligned; } cnt += has_unaligned? 1: 0; } @@ -95,12 +96,12 @@ int BVHNode::getSubtreeSize(BVH_STAT stat) const for(int i = 0; i < num_children(); i++) { BVHNode *node = get_child(i); if(node->is_leaf()) { - has_unaligned |= node->is_unaligned(); + has_unaligned |= node->is_unaligned; } else { for(int j = 0; j < node->num_children(); j++) { cnt += node->get_child(j)->getSubtreeSize(stat); - has_unaligned |= node->get_child(j)->is_unaligned(); + has_unaligned |= node->get_child(j)->is_unaligned; } } } @@ -113,12 +114,12 @@ int BVHNode::getSubtreeSize(BVH_STAT stat) const for(int i = 0; i < num_children(); i++) { BVHNode *node = get_child(i); if(node->is_leaf()) { - has_unaligned |= node->is_unaligned(); + has_unaligned |= node->is_unaligned; } else { for(int j = 0; j < node->num_children(); j++) { cnt += node->get_child(j)->getSubtreeSize(stat); - has_unaligned |= node->get_child(j)->is_unaligned(); + has_unaligned |= node->get_child(j)->is_unaligned; } } } @@ -126,10 +127,10 @@ int BVHNode::getSubtreeSize(BVH_STAT stat) const } return cnt; case BVH_STAT_ALIGNED_LEAF_COUNT: - cnt = (is_leaf() && !is_unaligned()) ? 1 : 0; + cnt = (is_leaf() && !is_unaligned) ? 1 : 0; break; case BVH_STAT_UNALIGNED_LEAF_COUNT: - cnt = (is_leaf() && is_unaligned()) ? 1 : 0; + cnt = (is_leaf() && is_unaligned) ? 1 : 0; break; default: assert(0); /* unknown mode */ @@ -157,7 +158,7 @@ float BVHNode::computeSubtreeSAHCost(const BVHParams& p, float probability) cons for(int i = 0; i < num_children(); i++) { BVHNode *child = get_child(i); - SAH += child->computeSubtreeSAHCost(p, probability * child->m_bounds.safe_area()/m_bounds.safe_area()); + SAH += child->computeSubtreeSAHCost(p, probability * child->bounds.safe_area()/bounds.safe_area()); } return SAH; @@ -165,15 +166,15 @@ float BVHNode::computeSubtreeSAHCost(const BVHParams& p, float probability) cons uint BVHNode::update_visibility() { - if(!is_leaf() && m_visibility == 0) { + if(!is_leaf() && visibility == 0) { InnerNode *inner = (InnerNode*)this; BVHNode *child0 = inner->children[0]; BVHNode *child1 = inner->children[1]; - m_visibility = child0->update_visibility()|child1->update_visibility(); + visibility = child0->update_visibility()|child1->update_visibility(); } - return m_visibility; + return visibility; } void BVHNode::update_time() @@ -184,8 +185,8 @@ void BVHNode::update_time() BVHNode *child1 = inner->children[1]; child0->update_time(); child1->update_time(); - m_time_from = min(child0->m_time_from, child1->m_time_from); - m_time_to = max(child0->m_time_to, child1->m_time_to); + time_from = min(child0->time_from, child1->time_from); + time_to = max(child0->time_to, child1->time_to); } } @@ -209,7 +210,7 @@ void LeafNode::print(int depth) const for(int i = 0; i < depth; i++) printf(" "); - printf("leaf node %d to %d\n", m_lo, m_hi); + printf("leaf node %d to %d\n", lo, hi); } CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h index 090c426de56..1c875f5a524 100644 --- a/intern/cycles/bvh/bvh_node.h +++ b/intern/cycles/bvh/bvh_node.h @@ -18,9 +18,8 @@ #ifndef __BVH_NODE_H__ #define __BVH_NODE_H__ -#include "util_boundbox.h" -#include "util_debug.h" -#include "util_types.h" +#include "util/util_boundbox.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN @@ -46,16 +45,16 @@ class BVHParams; class BVHNode { public: - BVHNode() : m_is_unaligned(false), - m_aligned_space(NULL), - m_time_from(0.0f), - m_time_to(1.0f) + BVHNode() : is_unaligned(false), + aligned_space(NULL), + time_from(0.0f), + time_to(1.0f) { } virtual ~BVHNode() { - delete m_aligned_space; + delete aligned_space; } virtual bool is_leaf() const = 0; @@ -63,30 +62,26 @@ public: virtual BVHNode *get_child(int i) const = 0; virtual int num_triangles() const { return 0; } virtual void print(int depth = 0) const = 0; - bool is_unaligned() const { return m_is_unaligned; } inline void set_aligned_space(const Transform& aligned_space) { - m_is_unaligned = true; - if(m_aligned_space == NULL) { - m_aligned_space = new Transform(aligned_space); + is_unaligned = true; + if(this->aligned_space == NULL) { + this->aligned_space = new Transform(aligned_space); } else { - *m_aligned_space = aligned_space; + *this->aligned_space = aligned_space; } } inline Transform get_aligned_space() const { - if(m_aligned_space == NULL) { + if(aligned_space == NULL) { return transform_identity(); } - return *m_aligned_space; + return *aligned_space; } - BoundBox m_bounds; - uint m_visibility; - // Subtree functions int getSubtreeSize(BVH_STAT stat=BVH_STAT_NODE_COUNT) const; float computeSubtreeSAHCost(const BVHParams& p, float probability = 1.0f) const; @@ -95,13 +90,18 @@ public: uint update_visibility(); void update_time(); - bool m_is_unaligned; + // Properties. + BoundBox bounds; + uint visibility; + + bool is_unaligned; - // TODO(sergey): Can be stored as 3x3 matrix, but better to have some - // utilities and type defines in util_transform first. - Transform *m_aligned_space; + /* TODO(sergey): Can be stored as 3x3 matrix, but better to have some + * utilities and type defines in util_transform first. + */ + Transform *aligned_space; - float m_time_from, m_time_to; + float time_from, time_to; }; class InnerNode : public BVHNode @@ -111,20 +111,20 @@ public: BVHNode* child0, BVHNode* child1) { - m_bounds = bounds; + this->bounds = bounds; children[0] = child0; children[1] = child1; if(child0 && child1) - m_visibility = child0->m_visibility|child1->m_visibility; + visibility = child0->visibility|child1->visibility; else - m_visibility = 0; /* happens on build cancel */ + visibility = 0; /* happens on build cancel */ } explicit InnerNode(const BoundBox& bounds) { - m_bounds = bounds; - m_visibility = 0; + this->bounds = bounds; + visibility = 0; children[0] = NULL; children[1] = NULL; } @@ -140,12 +140,12 @@ public: class LeafNode : public BVHNode { public: - LeafNode(const BoundBox& bounds, uint visibility, int lo, int hi) + LeafNode(const BoundBox& bounds, uint visibility, int lo, int hi) + : lo(lo), + hi(hi) { - m_bounds = bounds; - m_visibility = visibility; - m_lo = lo; - m_hi = hi; + this->bounds = bounds; + this->visibility = visibility; } LeafNode(const LeafNode& s) @@ -157,14 +157,13 @@ public: bool is_leaf() const { return true; } int num_children() const { return 0; } BVHNode *get_child(int) const { return NULL; } - int num_triangles() const { return m_hi - m_lo; } + int num_triangles() const { return hi - lo; } void print(int depth) const; - int m_lo; - int m_hi; + int lo; + int hi; }; CCL_NAMESPACE_END #endif /* __BVH_NODE_H__ */ - diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index 7b309504728..7dd699b33a4 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -18,9 +18,9 @@ #ifndef __BVH_PARAMS_H__ #define __BVH_PARAMS_H__ -#include "util_boundbox.h" +#include "util/util_boundbox.h" -#include "kernel_types.h" +#include "kernel/kernel_types.h" CCL_NAMESPACE_BEGIN @@ -246,4 +246,3 @@ struct BVHSpatialStorage { CCL_NAMESPACE_END #endif /* __BVH_PARAMS_H__ */ - diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp index e5bcf9995bf..3a01061b285 100644 --- a/intern/cycles/bvh/bvh_sort.cpp +++ b/intern/cycles/bvh/bvh_sort.cpp @@ -15,12 +15,13 @@ * limitations under the License. */ -#include "bvh_build.h" -#include "bvh_sort.h" +#include "bvh/bvh_sort.h" -#include "util_algorithm.h" -#include "util_debug.h" -#include "util_task.h" +#include "bvh/bvh_build.h" + +#include "util/util_algorithm.h" +#include "util/util_debug.h" +#include "util/util_task.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/bvh/bvh_sort.h b/intern/cycles/bvh/bvh_sort.h index b49ca02eb60..936401d8607 100644 --- a/intern/cycles/bvh/bvh_sort.h +++ b/intern/cycles/bvh/bvh_sort.h @@ -18,8 +18,11 @@ #ifndef __BVH_SORT_H__ #define __BVH_SORT_H__ +#include <cstddef> + CCL_NAMESPACE_BEGIN +class BVHReference; class BVHUnaligned; struct Transform; @@ -33,4 +36,3 @@ void bvh_reference_sort(int start, CCL_NAMESPACE_END #endif /* __BVH_SORT_H__ */ - diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp index d0d5fbe5a7a..c55ba40b565 100644 --- a/intern/cycles/bvh/bvh_split.cpp +++ b/intern/cycles/bvh/bvh_split.cpp @@ -15,14 +15,15 @@ * limitations under the License. */ -#include "bvh_build.h" -#include "bvh_split.h" -#include "bvh_sort.h" +#include "bvh/bvh_split.h" -#include "mesh.h" -#include "object.h" +#include "bvh/bvh_build.h" +#include "bvh/bvh_sort.h" -#include "util_algorithm.h" +#include "render/mesh.h" +#include "render/object.h" + +#include "util/util_algorithm.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/bvh/bvh_split.h b/intern/cycles/bvh/bvh_split.h index dbdb51f1a5b..a874a118b99 100644 --- a/intern/cycles/bvh/bvh_split.h +++ b/intern/cycles/bvh/bvh_split.h @@ -18,8 +18,8 @@ #ifndef __BVH_SPLIT_H__ #define __BVH_SPLIT_H__ -#include "bvh_build.h" -#include "bvh_params.h" +#include "bvh/bvh_build.h" +#include "bvh/bvh_params.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/bvh/bvh_unaligned.cpp b/intern/cycles/bvh/bvh_unaligned.cpp index a876c670914..b522a8f3e10 100644 --- a/intern/cycles/bvh/bvh_unaligned.cpp +++ b/intern/cycles/bvh/bvh_unaligned.cpp @@ -14,18 +14,17 @@ * limitations under the License. */ +#include "bvh/bvh_unaligned.h" -#include "bvh_unaligned.h" +#include "render/mesh.h" +#include "render/object.h" -#include "mesh.h" -#include "object.h" - -#include "bvh_binning.h" +#include "bvh/bvh_binning.h" #include "bvh_params.h" -#include "util_boundbox.h" -#include "util_debug.h" -#include "util_transform.h" +#include "util/util_boundbox.h" +#include "util/util_debug.h" +#include "util/util_transform.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/bvh/bvh_unaligned.h b/intern/cycles/bvh/bvh_unaligned.h index 4d0872f4a39..c3ece051cd5 100644 --- a/intern/cycles/bvh/bvh_unaligned.h +++ b/intern/cycles/bvh/bvh_unaligned.h @@ -17,7 +17,7 @@ #ifndef __BVH_UNALIGNED_H__ #define __BVH_UNALIGNED_H__ -#include "util_vector.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN @@ -78,4 +78,3 @@ protected: CCL_NAMESPACE_END #endif /* __BVH_UNALIGNED_H__ */ - diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt index a2373451696..6ef2aa1caad 100644 --- a/intern/cycles/device/CMakeLists.txt +++ b/intern/cycles/device/CMakeLists.txt @@ -1,13 +1,6 @@ set(INC - . - ../graph - ../kernel - ../kernel/split - ../kernel/svm - ../kernel/osl - ../util - ../render + .. ../../glew-mx ) diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 6b07b9d04bd..968af447e29 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -17,18 +17,18 @@ #include <stdlib.h> #include <string.h> -#include "device.h" -#include "device_intern.h" - -#include "util_debug.h" -#include "util_foreach.h" -#include "util_half.h" -#include "util_math.h" -#include "util_opengl.h" -#include "util_time.h" -#include "util_types.h" -#include "util_vector.h" -#include "util_string.h" +#include "device/device.h" +#include "device/device_intern.h" + +#include "util/util_debug.h" +#include "util/util_foreach.h" +#include "util/util_half.h" +#include "util/util_math.h" +#include "util/util_opengl.h" +#include "util/util_time.h" +#include "util/util_types.h" +#include "util/util_vector.h" +#include "util/util_string.h" CCL_NAMESPACE_BEGIN @@ -48,11 +48,11 @@ std::ostream& operator <<(std::ostream &os, os << "Max nodes group: " << requested_features.max_nodes_group << std::endl; /* TODO(sergey): Decode bitflag into list of names. */ os << "Nodes features: " << requested_features.nodes_features << std::endl; - os << "Use hair: " + os << "Use Hair: " << string_from_bool(requested_features.use_hair) << std::endl; - os << "Use object motion: " + os << "Use Object Motion: " << string_from_bool(requested_features.use_object_motion) << std::endl; - os << "Use camera motion: " + os << "Use Camera Motion: " << string_from_bool(requested_features.use_camera_motion) << std::endl; os << "Use Baking: " << string_from_bool(requested_features.use_baking) << std::endl; diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index ec15a254f81..ac06e561795 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -19,15 +19,15 @@ #include <stdlib.h> -#include "device_memory.h" -#include "device_task.h" +#include "device/device_memory.h" +#include "device/device_task.h" -#include "util_list.h" -#include "util_stats.h" -#include "util_string.h" -#include "util_thread.h" -#include "util_types.h" -#include "util_vector.h" +#include "util/util_list.h" +#include "util/util_stats.h" +#include "util/util_string.h" +#include "util/util_thread.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN @@ -121,6 +121,9 @@ public: /* Use Transparent shadows */ bool use_transparent; + /* Use various shadow tricks, such as shadow catcher. */ + bool use_shadow_tricks; + DeviceRequestedFeatures() { /* TODO(sergey): Find more meaningful defaults. */ @@ -137,6 +140,7 @@ public: use_integrator_branched = false; use_patch_evaluation = false; use_transparent = false; + use_shadow_tricks = false; } bool modified(const DeviceRequestedFeatures& requested_features) @@ -153,7 +157,8 @@ public: use_volume == requested_features.use_volume && use_integrator_branched == requested_features.use_integrator_branched && use_patch_evaluation == requested_features.use_patch_evaluation && - use_transparent == requested_features.use_transparent); + use_transparent == requested_features.use_transparent && + use_shadow_tricks == requested_features.use_shadow_tricks); } /* Convert the requested features structure to a build options, @@ -197,6 +202,9 @@ public: if(!use_transparent && !use_volume) { build_options += " -D__NO_TRANSPARENT__"; } + if(!use_shadow_tricks) { + build_options += " -D__NO_SHADOW_TRICKS__"; + } return build_options; } }; diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index d1027f07510..3c481bb2b39 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -20,34 +20,34 @@ /* So ImathMath is included before our kernel_cpu_compat. */ #ifdef WITH_OSL /* So no context pollution happens from indirectly included windows.h */ -# include "util_windows.h" +# include "util/util_windows.h" # include <OSL/oslexec.h> #endif -#include "device.h" -#include "device_intern.h" -#include "device_split_kernel.h" +#include "device/device.h" +#include "device/device_intern.h" +#include "device/device_split_kernel.h" -#include "kernel.h" -#include "kernel_compat_cpu.h" -#include "kernel_types.h" -#include "split/kernel_split_data.h" -#include "kernel_globals.h" +#include "kernel/kernel.h" +#include "kernel/kernel_compat_cpu.h" +#include "kernel/kernel_types.h" +#include "kernel/split/kernel_split_data.h" +#include "kernel/kernel_globals.h" -#include "osl_shader.h" -#include "osl_globals.h" +#include "kernel/osl/osl_shader.h" +#include "kernel/osl/osl_globals.h" -#include "buffers.h" +#include "render/buffers.h" -#include "util_debug.h" -#include "util_foreach.h" -#include "util_function.h" -#include "util_logging.h" -#include "util_map.h" -#include "util_opengl.h" -#include "util_progress.h" -#include "util_system.h" -#include "util_thread.h" +#include "util/util_debug.h" +#include "util/util_foreach.h" +#include "util/util_function.h" +#include "util/util_logging.h" +#include "util/util_map.h" +#include "util/util_opengl.h" +#include "util/util_progress.h" +#include "util/util_system.h" +#include "util/util_thread.h" CCL_NAMESPACE_BEGIN @@ -856,7 +856,7 @@ int2 CPUSplitKernel::split_kernel_local_size() } int2 CPUSplitKernel::split_kernel_global_size(device_memory& /*kg*/, device_memory& /*data*/, DeviceTask * /*task*/) { - return make_int2(64, 1); + return make_int2(1, 1); } uint64_t CPUSplitKernel::state_buffer_size(device_memory& kernel_globals, device_memory& /*data*/, size_t num_threads) { diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 58471ba67c2..ef283c9d455 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -20,31 +20,31 @@ #include <stdlib.h> #include <string.h> -#include "device.h" -#include "device_intern.h" -#include "device_split_kernel.h" +#include "device/device.h" +#include "device/device_intern.h" +#include "device/device_split_kernel.h" -#include "buffers.h" +#include "render/buffers.h" #ifdef WITH_CUDA_DYNLOAD # include "cuew.h" #else -# include "util_opengl.h" +# include "util/util_opengl.h" # include <cuda.h> # include <cudaGL.h> #endif -#include "util_debug.h" -#include "util_logging.h" -#include "util_map.h" -#include "util_md5.h" -#include "util_opengl.h" -#include "util_path.h" -#include "util_string.h" -#include "util_system.h" -#include "util_types.h" -#include "util_time.h" - -#include "split/kernel_split_data_types.h" +#include "util/util_debug.h" +#include "util/util_logging.h" +#include "util/util_map.h" +#include "util/util_md5.h" +#include "util/util_opengl.h" +#include "util/util_path.h" +#include "util/util_string.h" +#include "util/util_system.h" +#include "util/util_types.h" +#include "util/util_time.h" + +#include "kernel/split/kernel_split_data_types.h" CCL_NAMESPACE_BEGIN @@ -300,8 +300,8 @@ public: { const int cuda_version = cuewCompilerVersion(); const int machine = system_cpu_bits(); - const string kernel_path = path_get("kernel"); - const string include = kernel_path; + const string source_path = path_get("source"); + const string include_path = source_path; string cflags = string_printf("-m%d " "--ptxas-options=\"-v\" " "--use_fast_math " @@ -310,7 +310,7 @@ public: "-I\"%s\"", machine, cuda_version, - include.c_str()); + include_path.c_str()); if(use_adaptive_compilation()) { cflags += " " + requested_features.get_build_options(); } @@ -345,15 +345,15 @@ public: cuda_error_message("CUDA nvcc compiler version could not be parsed."); return false; } - if(cuda_version < 75) { + if(cuda_version < 80) { printf("Unsupported CUDA version %d.%d detected, " - "you need CUDA 7.5 or newer.\n", + "you need CUDA 8.0 or newer.\n", major, minor); return false; } - else if(cuda_version != 75 && cuda_version != 80) { + else if(cuda_version != 80) { printf("CUDA version %d.%d detected, build may succeed but only " - "CUDA 7.5 and 8.0 are officially supported.\n", + "CUDA 8.0 is officially supported.\n", major, minor); } return true; @@ -382,8 +382,8 @@ public: compile_kernel_get_common_cflags(requested_features, split); /* Try to use locally compiled kernel. */ - const string kernel_path = path_get("kernel"); - const string kernel_md5 = path_files_md5_hash(kernel_path); + const string source_path = path_get("source"); + const string kernel_md5 = path_files_md5_hash(source_path); /* We include cflags into md5 so changing cuda toolkit or changing other * compiler command line arguments makes sure cubin gets re-built. @@ -424,9 +424,10 @@ public: return ""; } const char *nvcc = cuewCompilerPath(); - const string kernel = path_join(kernel_path, - path_join("kernels", - path_join("cuda", split ? "kernel_split.cu" : "kernel.cu"))); + const string kernel = path_join( + path_join(source_path, "kernel"), + path_join("kernels", + path_join("cuda", split ? "kernel_split.cu" : "kernel.cu"))); double starttime = time_dt(); printf("Compiling CUDA kernel ...\n"); @@ -1500,7 +1501,7 @@ uint64_t CUDASplitKernel::state_buffer_size(device_memory& /*kg*/, device_memory cuda_assert(cuLaunchKernel(state_buffer_size, 1, 1, 1, 1, 1, 1, - 0, 0, &args, 0)); + 0, 0, (void**)&args, 0)); device->cuda_pop_context(); @@ -1612,10 +1613,23 @@ int2 CUDASplitKernel::split_kernel_local_size() return make_int2(32, 1); } -int2 CUDASplitKernel::split_kernel_global_size(device_memory& /*kg*/, device_memory& /*data*/, DeviceTask */*task*/) +int2 CUDASplitKernel::split_kernel_global_size(device_memory& kg, device_memory& data, DeviceTask * /*task*/) { - /* TODO(mai): implement something here to detect ideal work size */ - return make_int2(256, 256); + 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. (" + << string_human_readable_size(free) << ")."; + + size_t num_elements = max_elements_for_max_buffer_size(kg, data, free / 2); + int2 global_size = make_int2(round_down((int)sqrt(num_elements), 32), (int)sqrt(num_elements)); + VLOG(1) << "Global size: " << global_size << "."; + return global_size; } bool device_cuda_init(void) diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h index 60d166b43ba..4b10514a9d2 100644 --- a/intern/cycles/device/device_memory.h +++ b/intern/cycles/device/device_memory.h @@ -28,10 +28,10 @@ * other devices this is a pointer to device memory, where we will copy memory * to and from. */ -#include "util_debug.h" -#include "util_half.h" -#include "util_types.h" -#include "util_vector.h" +#include "util/util_debug.h" +#include "util/util_half.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp index 3368fd3d756..624260a81c8 100644 --- a/intern/cycles/device/device_multi.cpp +++ b/intern/cycles/device/device_multi.cpp @@ -17,17 +17,17 @@ #include <stdlib.h> #include <sstream> -#include "device.h" -#include "device_intern.h" -#include "device_network.h" +#include "device/device.h" +#include "device/device_intern.h" +#include "device/device_network.h" -#include "buffers.h" +#include "render/buffers.h" -#include "util_foreach.h" -#include "util_list.h" -#include "util_logging.h" -#include "util_map.h" -#include "util_time.h" +#include "util/util_foreach.h" +#include "util/util_list.h" +#include "util/util_logging.h" +#include "util/util_map.h" +#include "util/util_time.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp index 6dc4aecbc50..66758954f44 100644 --- a/intern/cycles/device/device_network.cpp +++ b/intern/cycles/device/device_network.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "device.h" -#include "device_intern.h" -#include "device_network.h" +#include "device/device.h" +#include "device/device_intern.h" +#include "device/device_network.h" -#include "util_foreach.h" -#include "util_logging.h" +#include "util/util_foreach.h" +#include "util/util_logging.h" #if defined(WITH_NETWORK) diff --git a/intern/cycles/device/device_network.h b/intern/cycles/device/device_network.h index d28cfe3121f..a5d24c66018 100644 --- a/intern/cycles/device/device_network.h +++ b/intern/cycles/device/device_network.h @@ -33,12 +33,12 @@ #include <sstream> #include <deque> -#include "buffers.h" +#include "render/buffers.h" -#include "util_foreach.h" -#include "util_list.h" -#include "util_map.h" -#include "util_string.h" +#include "util/util_foreach.h" +#include "util/util_list.h" +#include "util/util_map.h" +#include "util/util_string.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index ba94c592a5f..edd2047debc 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -16,12 +16,12 @@ #ifdef WITH_OPENCL -#include "opencl/opencl.h" +#include "device/opencl/opencl.h" -#include "device_intern.h" +#include "device/device_intern.h" -#include "util_foreach.h" -#include "util_logging.h" +#include "util/util_foreach.h" +#include "util/util_logging.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/device/device_split_kernel.cpp b/intern/cycles/device/device_split_kernel.cpp index 7a4d8c419b5..981ec74fe56 100644 --- a/intern/cycles/device/device_split_kernel.cpp +++ b/intern/cycles/device/device_split_kernel.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "device_split_kernel.h" +#include "device/device_split_kernel.h" -#include "kernel_types.h" -#include "kernel_split_data_types.h" +#include "kernel/kernel_types.h" +#include "kernel/split/kernel_split_data_types.h" -#include "util_time.h" +#include "util/util_time.h" CCL_NAMESPACE_BEGIN @@ -128,30 +128,32 @@ bool DeviceSplitKernel::path_trace(DeviceTask *task, local_size[1] = lsize[1]; } - /* Set gloabl size */ - size_t global_size[2]; - { - int2 gsize = split_kernel_global_size(kgbuffer, kernel_data, task); - - /* Make sure that set work size is a multiple of local - * work size dimensions. - */ - global_size[0] = round_up(gsize[0], local_size[0]); - global_size[1] = round_up(gsize[1], local_size[1]); - } - /* Number of elements in the global state buffer */ int num_global_elements = global_size[0] * global_size[1]; - assert(num_global_elements % WORK_POOL_SIZE == 0); /* Allocate all required global memory once. */ if(first_tile) { first_tile = false; + /* Set gloabl size */ + { + int2 gsize = split_kernel_global_size(kgbuffer, kernel_data, task); + + /* Make sure that set work size is a multiple of local + * work size dimensions. + */ + global_size[0] = round_up(gsize[0], local_size[0]); + global_size[1] = round_up(gsize[1], local_size[1]); + } + + num_global_elements = global_size[0] * global_size[1]; + assert(num_global_elements % WORK_POOL_SIZE == 0); + /* Calculate max groups */ /* Denotes the maximum work groups possible w.r.t. current requested tile size. */ - unsigned int max_work_groups = num_global_elements / WORK_POOL_SIZE + 1; + unsigned int work_pool_size = (device->info.type == DEVICE_CPU) ? WORK_POOL_SIZE_CPU : WORK_POOL_SIZE_GPU; + unsigned int max_work_groups = num_global_elements / work_pool_size + 1; /* Allocate work_pool_wgs memory. */ work_pool_wgs.resize(max_work_groups * sizeof(unsigned int)); @@ -256,10 +258,8 @@ bool DeviceSplitKernel::path_trace(DeviceTask *task, activeRaysAvailable = false; for(int rayStateIter = 0; rayStateIter < global_size[0] * global_size[1]; ++rayStateIter) { - int8_t state = ray_state.get_data()[rayStateIter]; - - if(state != RAY_INACTIVE) { - if(state == RAY_INVALID) { + if(!IS_STATE(ray_state.get_data(), rayStateIter, RAY_INACTIVE)) { + if(IS_STATE(ray_state.get_data(), rayStateIter, RAY_INVALID)) { /* Something went wrong, abort to avoid looping endlessly. */ device->set_error("Split kernel error: invalid ray state"); return false; diff --git a/intern/cycles/device/device_split_kernel.h b/intern/cycles/device/device_split_kernel.h index 6739e754862..55548122c0c 100644 --- a/intern/cycles/device/device_split_kernel.h +++ b/intern/cycles/device/device_split_kernel.h @@ -17,8 +17,8 @@ #ifndef __DEVICE_SPLIT_KERNEL_H__ #define __DEVICE_SPLIT_KERNEL_H__ -#include "device.h" -#include "buffers.h" +#include "device/device.h" +#include "render/buffers.h" CCL_NAMESPACE_BEGIN @@ -95,6 +95,9 @@ private: /* Marked True in constructor and marked false at the end of path_trace(). */ bool first_tile; + /* Cached global size */ + size_t global_size[2]; + public: explicit DeviceSplitKernel(Device* device); virtual ~DeviceSplitKernel(); diff --git a/intern/cycles/device/device_task.cpp b/intern/cycles/device/device_task.cpp index 48d18035c13..ca303365627 100644 --- a/intern/cycles/device/device_task.cpp +++ b/intern/cycles/device/device_task.cpp @@ -17,12 +17,12 @@ #include <stdlib.h> #include <string.h> -#include "device_task.h" +#include "device/device_task.h" -#include "buffers.h" +#include "render/buffers.h" -#include "util_algorithm.h" -#include "util_time.h" +#include "util/util_algorithm.h" +#include "util/util_time.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/device/device_task.h b/intern/cycles/device/device_task.h index f31092fd9d2..feee89fd6e4 100644 --- a/intern/cycles/device/device_task.h +++ b/intern/cycles/device/device_task.h @@ -17,11 +17,11 @@ #ifndef __DEVICE_TASK_H__ #define __DEVICE_TASK_H__ -#include "device_memory.h" +#include "device/device_memory.h" -#include "util_function.h" -#include "util_list.h" -#include "util_task.h" +#include "util/util_function.h" +#include "util/util_list.h" +#include "util/util_task.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/device/opencl/opencl.h b/intern/cycles/device/opencl/opencl.h index 59e61aad25c..764216d0dfa 100644 --- a/intern/cycles/device/opencl/opencl.h +++ b/intern/cycles/device/opencl/opencl.h @@ -16,11 +16,11 @@ #ifdef WITH_OPENCL -#include "device.h" +#include "device/device.h" -#include "util_map.h" -#include "util_param.h" -#include "util_string.h" +#include "util/util_map.h" +#include "util/util_param.h" +#include "util/util_string.h" #include "clew.h" diff --git a/intern/cycles/device/opencl/opencl_base.cpp b/intern/cycles/device/opencl/opencl_base.cpp index 0328dfed689..52d0662a8e3 100644 --- a/intern/cycles/device/opencl/opencl_base.cpp +++ b/intern/cycles/device/opencl/opencl_base.cpp @@ -16,15 +16,15 @@ #ifdef WITH_OPENCL -#include "opencl.h" +#include "device/opencl/opencl.h" -#include "kernel_types.h" +#include "kernel/kernel_types.h" -#include "util_foreach.h" -#include "util_logging.h" -#include "util_md5.h" -#include "util_path.h" -#include "util_time.h" +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_md5.h" +#include "util/util_path.h" +#include "util/util_time.h" CCL_NAMESPACE_BEGIN @@ -527,7 +527,7 @@ void OpenCLDeviceBase::film_convert(DeviceTask& task, device_ptr buffer, device_ #define KERNEL_TEX(type, ttype, name) \ set_kernel_arg_mem(ckFilmConvertKernel, &start_arg_index, #name); -#include "kernel_textures.h" +#include "kernel/kernel_textures.h" #undef KERNEL_TEX start_arg_index += kernel_set_args(ckFilmConvertKernel, @@ -578,7 +578,7 @@ void OpenCLDeviceBase::shader(DeviceTask& task) #define KERNEL_TEX(type, ttype, name) \ set_kernel_arg_mem(kernel, &start_arg_index, #name); -#include "kernel_textures.h" +#include "kernel/kernel_textures.h" #undef KERNEL_TEX start_arg_index += kernel_set_args(kernel, diff --git a/intern/cycles/device/opencl/opencl_mega.cpp b/intern/cycles/device/opencl/opencl_mega.cpp index 049e332272b..a2fd1d71156 100644 --- a/intern/cycles/device/opencl/opencl_mega.cpp +++ b/intern/cycles/device/opencl/opencl_mega.cpp @@ -16,15 +16,15 @@ #ifdef WITH_OPENCL -#include "opencl.h" +#include "device/opencl/opencl.h" -#include "buffers.h" +#include "render/buffers.h" -#include "kernel_types.h" +#include "kernel/kernel_types.h" -#include "util_md5.h" -#include "util_path.h" -#include "util_time.h" +#include "util/util_md5.h" +#include "util/util_path.h" +#include "util/util_time.h" CCL_NAMESPACE_BEGIN @@ -84,7 +84,7 @@ public: #define KERNEL_TEX(type, ttype, name) \ set_kernel_arg_mem(ckPathTraceKernel, &start_arg_index, #name); -#include "kernel_textures.h" +#include "kernel/kernel_textures.h" #undef KERNEL_TEX start_arg_index += kernel_set_args(ckPathTraceKernel, diff --git a/intern/cycles/device/opencl/opencl_split.cpp b/intern/cycles/device/opencl/opencl_split.cpp index d50ae585062..b8df57ec7b9 100644 --- a/intern/cycles/device/opencl/opencl_split.cpp +++ b/intern/cycles/device/opencl/opencl_split.cpp @@ -16,19 +16,19 @@ #ifdef WITH_OPENCL -#include "opencl.h" +#include "device/opencl/opencl.h" -#include "buffers.h" +#include "render/buffers.h" -#include "kernel_types.h" -#include "kernel_split_data_types.h" +#include "kernel/kernel_types.h" +#include "kernel/split/kernel_split_data_types.h" -#include "device_split_kernel.h" +#include "device/device_split_kernel.h" -#include "util_logging.h" -#include "util_md5.h" -#include "util_path.h" -#include "util_time.h" +#include "util/util_logging.h" +#include "util/util_md5.h" +#include "util/util_path.h" +#include "util/util_time.h" CCL_NAMESPACE_BEGIN @@ -110,7 +110,7 @@ public: ccl_constant KernelData *data; #define KERNEL_TEX(type, ttype, name) \ ccl_global type *name; -#include "kernel_textures.h" +#include "kernel/kernel_textures.h" #undef KERNEL_TEX SplitData split_data; SplitParams split_param_data; @@ -291,7 +291,7 @@ public: /* 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_textures.h" +#include "kernel/kernel_textures.h" #undef KERNEL_TEX start_arg_index += @@ -340,7 +340,7 @@ public: return make_int2(64, 1); } - virtual int2 split_kernel_global_size(device_memory& kg, device_memory& data, DeviceTask */*task*/) + virtual int2 split_kernel_global_size(device_memory& kg, device_memory& data, DeviceTask * /*task*/) { cl_device_type type = OpenCLInfo::get_device_type(device->cdDevice); /* Use small global size on CPU devices as it seems to be much faster. */ diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp index 1f5b9ee0896..fe1c65a2224 100644 --- a/intern/cycles/device/opencl/opencl_util.cpp +++ b/intern/cycles/device/opencl/opencl_util.cpp @@ -16,12 +16,12 @@ #ifdef WITH_OPENCL -#include "opencl.h" +#include "device/opencl/opencl.h" -#include "util_logging.h" -#include "util_md5.h" -#include "util_path.h" -#include "util_time.h" +#include "util/util_logging.h" +#include "util/util_md5.h" +#include "util/util_path.h" +#include "util/util_time.h" using std::cerr; using std::endl; @@ -235,7 +235,7 @@ string OpenCLCache::get_kernel_md5() thread_scoped_lock lock(self.kernel_md5_lock); if(self.kernel_md5.empty()) { - self.kernel_md5 = path_files_md5_hash(path_get("kernel")); + self.kernel_md5 = path_files_md5_hash(path_get("source")); } return self.kernel_md5; } @@ -281,6 +281,7 @@ void OpenCLDeviceBase::OpenCLProgram::add_log(string msg, bool debug) } else if(!debug) { printf("%s\n", msg.c_str()); + fflush(stdout); } else { VLOG(2) << msg; @@ -339,12 +340,12 @@ bool OpenCLDeviceBase::OpenCLProgram::build_kernel(const string *debug_src) bool OpenCLDeviceBase::OpenCLProgram::compile_kernel(const string *debug_src) { - string source = "#include \"kernels/opencl/" + kernel_file + "\"\n"; + string source = "#include \"kernel/kernels/opencl/" + kernel_file + "\"\n"; /* We compile kernels consisting of many files. unfortunately OpenCL * kernel caches do not seem to recognize changes in included files. * so we force recompile on changes by adding the md5 hash of all files. */ - source = path_source_replace_includes(source, path_get("kernel")); + source = path_source_replace_includes(source, path_get("source")); source += "\n// " + util_md5_string(source) + "\n"; if(debug_src) { @@ -443,8 +444,8 @@ void OpenCLDeviceBase::OpenCLProgram::load() add_log(string("OpenCL program ") + program_name + " not found in cache.", true); /* need to create source to get md5 */ - string source = "#include \"kernels/opencl/" + kernel_file + "\"\n"; - source = path_source_replace_includes(source, path_get("kernel")); + string source = "#include \"kernel/kernels/opencl/" + kernel_file + "\"\n"; + source = path_source_replace_includes(source, path_get("source")); string basename = "cycles_kernel_" + program_name + "_" + device_md5 + "_" + util_md5_string(source); basename = path_cache_get(path_join("kernels", basename)); @@ -1057,13 +1058,16 @@ cl_device_type OpenCLInfo::get_device_type(cl_device_id device_id) string OpenCLInfo::get_readable_device_name(cl_device_id device_id) { char board_name[1024]; + size_t length = 0; if(clGetDeviceInfo(device_id, CL_DEVICE_BOARD_NAME_AMD, sizeof(board_name), &board_name, - NULL) == CL_SUCCESS) + &length) == CL_SUCCESS) { - return board_name; + if(length != 0 && board_name[0] != '\0') { + return board_name; + } } /* Fallback to standard device name API. */ return get_device_name(device_id); diff --git a/intern/cycles/graph/CMakeLists.txt b/intern/cycles/graph/CMakeLists.txt index 4ea18728f1c..e70a18137bd 100644 --- a/intern/cycles/graph/CMakeLists.txt +++ b/intern/cycles/graph/CMakeLists.txt @@ -1,7 +1,6 @@ set(INC - . - ../util + .. ) set(SRC diff --git a/intern/cycles/graph/node.cpp b/intern/cycles/graph/node.cpp index 3c228a716d5..10d91a1e4ef 100644 --- a/intern/cycles/graph/node.cpp +++ b/intern/cycles/graph/node.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "node.h" -#include "node_type.h" +#include "graph/node.h" +#include "graph/node_type.h" -#include "util_foreach.h" -#include "util_param.h" -#include "util_transform.h" +#include "util/util_foreach.h" +#include "util/util_param.h" +#include "util/util_transform.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/graph/node.h b/intern/cycles/graph/node.h index 64410f4539b..53425f5faf1 100644 --- a/intern/cycles/graph/node.h +++ b/intern/cycles/graph/node.h @@ -16,11 +16,11 @@ #pragma once -#include "node_type.h" +#include "graph/node_type.h" -#include "util_map.h" -#include "util_param.h" -#include "util_vector.h" +#include "util/util_map.h" +#include "util/util_param.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/graph/node_enum.h b/intern/cycles/graph/node_enum.h index 2bae531c036..4e40c294f4f 100644 --- a/intern/cycles/graph/node_enum.h +++ b/intern/cycles/graph/node_enum.h @@ -16,8 +16,8 @@ #pragma once -#include "util_map.h" -#include "util_param.h" +#include "util/util_map.h" +#include "util/util_param.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp index 5b98de778ad..a3a8fa5f382 100644 --- a/intern/cycles/graph/node_type.cpp +++ b/intern/cycles/graph/node_type.cpp @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "node_type.h" -#include "util_foreach.h" -#include "util_transform.h" +#include "graph/node_type.h" +#include "util/util_foreach.h" +#include "util/util_transform.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h index 1fb135f6d22..7d46e31ce24 100644 --- a/intern/cycles/graph/node_type.h +++ b/intern/cycles/graph/node_type.h @@ -16,12 +16,12 @@ #pragma once -#include "node_enum.h" +#include "graph/node_enum.h" -#include "util_map.h" -#include "util_param.h" -#include "util_string.h" -#include "util_vector.h" +#include "util/util_map.h" +#include "util/util_param.h" +#include "util/util_string.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/graph/node_xml.cpp b/intern/cycles/graph/node_xml.cpp index 590e09645ed..aad2740ffc0 100644 --- a/intern/cycles/graph/node_xml.cpp +++ b/intern/cycles/graph/node_xml.cpp @@ -14,11 +14,11 @@ * limitations under the License. */ -#include "node_xml.h" +#include "graph/node_xml.h" -#include "util_foreach.h" -#include "util_string.h" -#include "util_transform.h" +#include "util/util_foreach.h" +#include "util/util_string.h" +#include "util/util_transform.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/graph/node_xml.h b/intern/cycles/graph/node_xml.h index 7494c5e6e55..63e80bf79f2 100644 --- a/intern/cycles/graph/node_xml.h +++ b/intern/cycles/graph/node_xml.h @@ -16,11 +16,11 @@ #pragma once -#include "node.h" +#include "graph/node.h" -#include "util_map.h" -#include "util_string.h" -#include "util_xml.h" +#include "util/util_map.h" +#include "util/util_string.h" +#include "util/util_xml.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 53c872e829d..dbc2ba2503a 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -1,10 +1,7 @@ remove_extra_strict_flags() set(INC - . - ../util - osl - svm + .. ) set(INC_SYS @@ -196,6 +193,7 @@ set(SRC_UTIL_HEADERS ../util/util_hash.h ../util/util_math.h ../util/util_math_fast.h + ../util/util_math_intersect.h ../util/util_static_assert.h ../util/util_transform.h ../util/util_texture.h @@ -308,8 +306,7 @@ if(WITH_CYCLES_CUDA_BINARIES) ${cuda_math_flags} ${cuda_extra_flags} ${cuda_debug_flags} - -I${CMAKE_CURRENT_SOURCE_DIR}/../util - -I${CMAKE_CURRENT_SOURCE_DIR}/svm + -I${CMAKE_CURRENT_SOURCE_DIR}/.. -DCCL_NAMESPACE_BEGIN= -DCCL_NAMESPACE_END= -DNVCC @@ -350,6 +347,9 @@ endif() include_directories(${INC}) include_directories(SYSTEM ${INC_SYS}) +set_source_files_properties(kernels/cpu/kernel.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_KERNEL_FLAGS}") +set_source_files_properties(kernels/cpu/kernel_split.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_KERNEL_FLAGS}") + if(CXX_HAS_SSE) list(APPEND SRC kernels/cpu/kernel_sse2.cpp @@ -412,33 +412,33 @@ endif() #add_custom_target(cycles_kernel_preprocess ALL DEPENDS ${KERNEL_PREPROCESSED}) #delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${KERNEL_PREPROCESSED}" ${CYCLES_INSTALL_PATH}/kernel) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_state_buffer_size.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_split.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_data_init.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_path_init.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_queue_enqueue.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_scene_intersect.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_lamp_emission.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_do_volume.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_indirect_background.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_shader_eval.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_subsurface_scatter.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_direct_lighting.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_shadow_blocked_ao.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_shadow_blocked_dl.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_next_iteration_setup.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_indirect_subsurface.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_buffer_update.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/cuda/kernel.cu" ${CYCLES_INSTALL_PATH}/kernel/kernels/cuda) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/cuda/kernel_split.cu" ${CYCLES_INSTALL_PATH}/kernel/kernels/cuda) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNELS_CUDA_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/kernels/cuda) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_BVH_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/bvh) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_CLOSURE_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/closure) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_SVM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/svm) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_GEOM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/geom) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_UTIL_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel) -delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_SPLIT_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/split) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_state_buffer_size.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_split.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_data_init.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_path_init.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_queue_enqueue.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_scene_intersect.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_lamp_emission.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_do_volume.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_indirect_background.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_shader_eval.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_subsurface_scatter.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_direct_lighting.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_shadow_blocked_ao.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_shadow_blocked_dl.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_next_iteration_setup.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_indirect_subsurface.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_buffer_update.cl" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/cuda/kernel.cu" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/cuda) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/cuda/kernel_split.cu" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/cuda) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNELS_CUDA_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/cuda) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_BVH_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/bvh) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_CLOSURE_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/closure) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_SVM_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/svm) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_GEOM_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/geom) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_UTIL_HEADERS}" ${CYCLES_INSTALL_PATH}/source/util) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_SPLIT_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/split) diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h index 321983c1abc..85741016b25 100644 --- a/intern/cycles/kernel/bvh/bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -27,43 +27,43 @@ CCL_NAMESPACE_BEGIN -#include "bvh_types.h" +#include "kernel/bvh/bvh_types.h" /* Common QBVH functions. */ #ifdef __QBVH__ -# include "qbvh_nodes.h" +# include "kernel/bvh/qbvh_nodes.h" #endif /* Regular BVH traversal */ -#include "bvh_nodes.h" +#include "kernel/bvh/bvh_nodes.h" #define BVH_FUNCTION_NAME bvh_intersect #define BVH_FUNCTION_FEATURES 0 -#include "bvh_traversal.h" +#include "kernel/bvh/bvh_traversal.h" #if defined(__INSTANCING__) # define BVH_FUNCTION_NAME bvh_intersect_instancing # define BVH_FUNCTION_FEATURES BVH_INSTANCING -# include "bvh_traversal.h" +# include "kernel/bvh/bvh_traversal.h" #endif #if defined(__HAIR__) # define BVH_FUNCTION_NAME bvh_intersect_hair # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH -# include "bvh_traversal.h" +# include "kernel/bvh/bvh_traversal.h" #endif #if defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION -# include "bvh_traversal.h" +# include "kernel/bvh/bvh_traversal.h" #endif #if defined(__HAIR__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_hair_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION -# include "bvh_traversal.h" +# include "kernel/bvh/bvh_traversal.h" #endif /* Subsurface scattering BVH traversal */ @@ -71,12 +71,12 @@ CCL_NAMESPACE_BEGIN #if defined(__SUBSURFACE__) # define BVH_FUNCTION_NAME bvh_intersect_subsurface # define BVH_FUNCTION_FEATURES BVH_HAIR -# include "bvh_subsurface.h" +# include "kernel/bvh/bvh_subsurface.h" # if defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion # define BVH_FUNCTION_FEATURES BVH_MOTION|BVH_HAIR -# include "bvh_subsurface.h" +# include "kernel/bvh/bvh_subsurface.h" # endif #endif /* __SUBSURFACE__ */ @@ -85,18 +85,18 @@ CCL_NAMESPACE_BEGIN #if defined(__VOLUME__) # define BVH_FUNCTION_NAME bvh_intersect_volume # define BVH_FUNCTION_FEATURES BVH_HAIR -# include "bvh_volume.h" +# include "kernel/bvh/bvh_volume.h" # if defined(__INSTANCING__) # define BVH_FUNCTION_NAME bvh_intersect_volume_instancing # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR -# include "bvh_volume.h" +# include "kernel/bvh/bvh_volume.h" # endif # if defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_volume_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION|BVH_HAIR -# include "bvh_volume.h" +# include "kernel/bvh/bvh_volume.h" # endif #endif /* __VOLUME__ */ @@ -105,30 +105,30 @@ CCL_NAMESPACE_BEGIN #if defined(__SHADOW_RECORD_ALL__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all # define BVH_FUNCTION_FEATURES 0 -# include "bvh_shadow_all.h" +# include "kernel/bvh/bvh_shadow_all.h" # if defined(__INSTANCING__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all_instancing # define BVH_FUNCTION_FEATURES BVH_INSTANCING -# include "bvh_shadow_all.h" +# include "kernel/bvh/bvh_shadow_all.h" # endif # if defined(__HAIR__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR -# include "bvh_shadow_all.h" +# include "kernel/bvh/bvh_shadow_all.h" # endif # if defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION -# include "bvh_shadow_all.h" +# include "kernel/bvh/bvh_shadow_all.h" # endif # if defined(__HAIR__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_MOTION -# include "bvh_shadow_all.h" +# include "kernel/bvh/bvh_shadow_all.h" # endif #endif /* __SHADOW_RECORD_ALL__ */ @@ -137,18 +137,18 @@ CCL_NAMESPACE_BEGIN #if defined(__VOLUME_RECORD_ALL__) # define BVH_FUNCTION_NAME bvh_intersect_volume_all # define BVH_FUNCTION_FEATURES BVH_HAIR -# include "bvh_volume_all.h" +# include "kernel/bvh/bvh_volume_all.h" # if defined(__INSTANCING__) # define BVH_FUNCTION_NAME bvh_intersect_volume_all_instancing # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR -# include "bvh_volume_all.h" +# include "kernel/bvh/bvh_volume_all.h" # endif # if defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION|BVH_HAIR -# include "bvh_volume_all.h" +# include "kernel/bvh/bvh_volume_all.h" # endif #endif /* __VOLUME_RECORD_ALL__ */ @@ -202,8 +202,9 @@ ccl_device_intersect bool scene_intersect(KernelGlobals *kg, } #ifdef __SUBSURFACE__ +/* Note: ray is passed by value to work around a possible CUDA compiler bug. */ ccl_device_intersect void scene_intersect_subsurface(KernelGlobals *kg, - const Ray *ray, + const Ray ray, SubsurfaceIntersection *ss_isect, int subsurface_object, uint *lcg_state, @@ -212,7 +213,7 @@ ccl_device_intersect void scene_intersect_subsurface(KernelGlobals *kg, #ifdef __OBJECT_MOTION__ if(kernel_data.bvh.have_motion) { return bvh_intersect_subsurface_motion(kg, - ray, + &ray, ss_isect, subsurface_object, lcg_state, @@ -220,7 +221,7 @@ ccl_device_intersect void scene_intersect_subsurface(KernelGlobals *kg, } #endif /* __OBJECT_MOTION__ */ return bvh_intersect_subsurface(kg, - ray, + &ray, ss_isect, subsurface_object, lcg_state, @@ -229,30 +230,63 @@ ccl_device_intersect void scene_intersect_subsurface(KernelGlobals *kg, #endif #ifdef __SHADOW_RECORD_ALL__ -ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, const Ray *ray, Intersection *isect, uint max_hits, uint *num_hits) +ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, + const Ray *ray, + Intersection *isect, + int skip_object, + uint max_hits, + uint *num_hits) { # ifdef __OBJECT_MOTION__ if(kernel_data.bvh.have_motion) { # ifdef __HAIR__ - if(kernel_data.bvh.have_curves) - return bvh_intersect_shadow_all_hair_motion(kg, ray, isect, max_hits, num_hits); + if(kernel_data.bvh.have_curves) { + return bvh_intersect_shadow_all_hair_motion(kg, + ray, + isect, + skip_object, + max_hits, + num_hits); + } # endif /* __HAIR__ */ - return bvh_intersect_shadow_all_motion(kg, ray, isect, max_hits, num_hits); + return bvh_intersect_shadow_all_motion(kg, + ray, + isect, + skip_object, + max_hits, + num_hits); } # endif /* __OBJECT_MOTION__ */ # ifdef __HAIR__ - if(kernel_data.bvh.have_curves) - return bvh_intersect_shadow_all_hair(kg, ray, isect, max_hits, num_hits); + if(kernel_data.bvh.have_curves) { + return bvh_intersect_shadow_all_hair(kg, + ray, + isect, + skip_object, + max_hits, + num_hits); + } # endif /* __HAIR__ */ # ifdef __INSTANCING__ - if(kernel_data.bvh.have_instancing) - return bvh_intersect_shadow_all_instancing(kg, ray, isect, max_hits, num_hits); + if(kernel_data.bvh.have_instancing) { + return bvh_intersect_shadow_all_instancing(kg, + ray, + isect, + skip_object, + max_hits, + num_hits); + } # endif /* __INSTANCING__ */ - return bvh_intersect_shadow_all(kg, ray, isect, max_hits, num_hits); + return bvh_intersect_shadow_all(kg, + ray, + isect, + skip_object, + max_hits, + num_hits); } #endif /* __SHADOW_RECORD_ALL__ */ diff --git a/intern/cycles/kernel/bvh/bvh_nodes.h b/intern/cycles/kernel/bvh/bvh_nodes.h index 192aab89eae..74a9ebf14e4 100644 --- a/intern/cycles/kernel/bvh/bvh_nodes.h +++ b/intern/cycles/kernel/bvh/bvh_nodes.h @@ -17,8 +17,8 @@ // TODO(sergey): Look into avoid use of full Transform and use 3x3 matrix and // 3-vector which might be faster. ccl_device_forceinline Transform bvh_unaligned_node_fetch_space(KernelGlobals *kg, - int node_addr, - int child) + int node_addr, + int child) { Transform space; const int child_addr = node_addr + child * 3; @@ -31,12 +31,12 @@ ccl_device_forceinline Transform bvh_unaligned_node_fetch_space(KernelGlobals *k #if !defined(__KERNEL_SSE2__) ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals *kg, - const float3 P, - const float3 idir, - const float t, - const int node_addr, - const uint visibility, - float dist[2]) + const float3 P, + const float3 idir, + const float t, + const int node_addr, + const uint visibility, + float dist[2]) { /* fetch node data */ @@ -78,14 +78,14 @@ ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals *kg, } ccl_device_forceinline int bvh_aligned_node_intersect_robust(KernelGlobals *kg, - const float3 P, - const float3 idir, - const float t, - const float difl, - const float extmax, - const int node_addr, - const uint visibility, - float dist[2]) + const float3 P, + const float3 idir, + const float t, + const float difl, + const float extmax, + const int node_addr, + const uint visibility, + float dist[2]) { /* fetch node data */ @@ -203,13 +203,13 @@ ccl_device_forceinline bool bvh_unaligned_node_intersect_child_robust( } ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals *kg, - const float3 P, - const float3 dir, - const float3 idir, - const float t, - const int node_addr, - const uint visibility, - float dist[2]) + const float3 P, + const float3 dir, + const float3 idir, + const float t, + const int node_addr, + const uint visibility, + float dist[2]) { int mask = 0; float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); @@ -233,15 +233,15 @@ ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals *kg, } ccl_device_forceinline int bvh_unaligned_node_intersect_robust(KernelGlobals *kg, - const float3 P, - const float3 dir, - const float3 idir, - const float t, - const float difl, - const float extmax, - const int node_addr, - const uint visibility, - float dist[2]) + const float3 P, + const float3 dir, + const float3 idir, + const float t, + const float difl, + const float extmax, + const int node_addr, + const uint visibility, + float dist[2]) { int mask = 0; float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); @@ -265,13 +265,13 @@ ccl_device_forceinline int bvh_unaligned_node_intersect_robust(KernelGlobals *kg } ccl_device_forceinline int bvh_node_intersect(KernelGlobals *kg, - const float3 P, - const float3 dir, - const float3 idir, - const float t, - const int node_addr, - const uint visibility, - float dist[2]) + const float3 P, + const float3 dir, + const float3 idir, + const float t, + const int node_addr, + const uint visibility, + float dist[2]) { float4 node = kernel_tex_fetch(__bvh_nodes, node_addr); if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { @@ -296,15 +296,15 @@ ccl_device_forceinline int bvh_node_intersect(KernelGlobals *kg, } ccl_device_forceinline int bvh_node_intersect_robust(KernelGlobals *kg, - const float3 P, - const float3 dir, - const float3 idir, - const float t, - const float difl, - const float extmax, - const int node_addr, - const uint visibility, - float dist[2]) + const float3 P, + const float3 dir, + const float3 idir, + const float t, + const float difl, + const float extmax, + const int node_addr, + const uint visibility, + float dist[2]) { float4 node = kernel_tex_fetch(__bvh_nodes, node_addr); if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { @@ -442,13 +442,13 @@ ccl_device_forceinline int bvh_aligned_node_intersect_robust( } ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals *kg, - const float3 P, - const float3 dir, - const ssef& isect_near, - const ssef& isect_far, - const int node_addr, - const uint visibility, - float dist[2]) + const float3 P, + const float3 dir, + const ssef& isect_near, + const ssef& isect_far, + const int node_addr, + const uint visibility, + float dist[2]) { Transform space0 = bvh_unaligned_node_fetch_space(kg, node_addr, 0); Transform space1 = bvh_unaligned_node_fetch_space(kg, node_addr, 1); @@ -503,14 +503,14 @@ ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals *kg, } ccl_device_forceinline int bvh_unaligned_node_intersect_robust(KernelGlobals *kg, - const float3 P, - const float3 dir, - const ssef& isect_near, - const ssef& isect_far, - const float difl, - const int node_addr, - const uint visibility, - float dist[2]) + const float3 P, + const float3 dir, + const ssef& isect_near, + const ssef& isect_far, + const float difl, + const int node_addr, + const uint visibility, + float dist[2]) { Transform space0 = bvh_unaligned_node_fetch_space(kg, node_addr, 0); Transform space1 = bvh_unaligned_node_fetch_space(kg, node_addr, 1); @@ -574,17 +574,17 @@ ccl_device_forceinline int bvh_unaligned_node_intersect_robust(KernelGlobals *kg } ccl_device_forceinline int bvh_node_intersect(KernelGlobals *kg, - const float3& P, - const float3& dir, - const ssef& isect_near, - const ssef& isect_far, - const ssef& tsplat, - const ssef Psplat[3], - const ssef idirsplat[3], - const shuffle_swap_t shufflexyz[3], - const int node_addr, - const uint visibility, - float dist[2]) + const float3& P, + const float3& dir, + const ssef& isect_near, + const ssef& isect_far, + const ssef& tsplat, + const ssef Psplat[3], + const ssef idirsplat[3], + const shuffle_swap_t shufflexyz[3], + const int node_addr, + const uint visibility, + float dist[2]) { float4 node = kernel_tex_fetch(__bvh_nodes, node_addr); if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { @@ -612,19 +612,19 @@ ccl_device_forceinline int bvh_node_intersect(KernelGlobals *kg, } 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& tsplat, - const ssef Psplat[3], - const ssef idirsplat[3], - const shuffle_swap_t shufflexyz[3], - const float difl, - const float extmax, - const int node_addr, - const uint visibility, - float dist[2]) + const float3& P, + const float3& dir, + const ssef& isect_near, + const ssef& isect_far, + const ssef& tsplat, + const ssef Psplat[3], + const ssef idirsplat[3], + const shuffle_swap_t shufflexyz[3], + const float difl, + const float extmax, + const int node_addr, + const uint visibility, + float dist[2]) { float4 node = kernel_tex_fetch(__bvh_nodes, node_addr); if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h index b4f65bc8efd..267e098f912 100644 --- a/intern/cycles/kernel/bvh/bvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h @@ -18,7 +18,7 @@ */ #ifdef __QBVH__ -# include "qbvh_shadow_all.h" +# include "kernel/bvh/qbvh_shadow_all.h" #endif #if BVH_FEATURE(BVH_HAIR) @@ -45,6 +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 max_hits, uint *num_hits) { @@ -100,9 +101,6 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); #endif /* __KERNEL_SSE2__ */ - IsectPrecalc isect_precalc; - triangle_intersect_precalc(dir, &isect_precalc); - /* traversal loop */ do { do { @@ -189,6 +187,16 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, 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 @@ -198,9 +206,9 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, switch(p_type) { case PRIMITIVE_TRIANGLE: { hit = triangle_intersect(kg, - &isect_precalc, isect_array, P, + dir, PATH_RAY_SHADOW, object, prim_addr); @@ -314,7 +322,6 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, isect_t = bvh_instance_push(kg, object, ray, &P, &dir, &idir, isect_t); # endif - triangle_intersect_precalc(dir, &isect_precalc); num_hits_in_instance = 0; isect_array->t = isect_t; @@ -354,8 +361,6 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac); # endif - triangle_intersect_precalc(dir, &isect_precalc); - /* scale isect->t to adjust for instancing */ for(int i = 0; i < num_hits_in_instance; i++) { (isect_array-i-1)->t *= t_fac; @@ -367,7 +372,6 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, # else bvh_instance_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX); # endif - triangle_intersect_precalc(dir, &isect_precalc); } isect_t = tmax; @@ -398,6 +402,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 max_hits, uint *num_hits) { @@ -406,6 +411,7 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, return BVH_FUNCTION_FULL_NAME(QBVH)(kg, ray, isect_array, + skip_object, max_hits, num_hits); } @@ -416,6 +422,7 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect_array, + skip_object, max_hits, num_hits); } diff --git a/intern/cycles/kernel/bvh/bvh_subsurface.h b/intern/cycles/kernel/bvh/bvh_subsurface.h index 583f7f7c469..bda7e34907a 100644 --- a/intern/cycles/kernel/bvh/bvh_subsurface.h +++ b/intern/cycles/kernel/bvh/bvh_subsurface.h @@ -18,7 +18,7 @@ */ #ifdef __QBVH__ -# include "qbvh_subsurface.h" +# include "kernel/bvh/qbvh_subsurface.h" #endif #if BVH_FEATURE(BVH_HAIR) @@ -109,9 +109,6 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); #endif - IsectPrecalc isect_precalc; - triangle_intersect_precalc(dir, &isect_precalc); - /* traversal loop */ do { do { @@ -197,9 +194,9 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, for(; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); triangle_intersect_subsurface(kg, - &isect_precalc, ss_isect, P, + dir, object, prim_addr, isect_t, diff --git a/intern/cycles/kernel/bvh/bvh_traversal.h b/intern/cycles/kernel/bvh/bvh_traversal.h index 0eca0c8e38b..c58d3b0316c 100644 --- a/intern/cycles/kernel/bvh/bvh_traversal.h +++ b/intern/cycles/kernel/bvh/bvh_traversal.h @@ -18,7 +18,7 @@ */ #ifdef __QBVH__ -# include "qbvh_traversal.h" +# include "kernel/bvh/qbvh_traversal.h" #endif #if BVH_FEATURE(BVH_HAIR) @@ -104,9 +104,6 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); #endif - IsectPrecalc isect_precalc; - triangle_intersect_precalc(dir, &isect_precalc); - /* traversal loop */ do { do { @@ -238,9 +235,9 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, BVH_DEBUG_NEXT_INTERSECTION(); kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); if(triangle_intersect(kg, - &isect_precalc, isect, P, + dir, visibility, object, prim_addr)) @@ -358,7 +355,6 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, # else isect->t = bvh_instance_push(kg, object, ray, &P, &dir, &idir, isect->t); # endif - triangle_intersect_precalc(dir, &isect_precalc); # if defined(__KERNEL_SSE2__) Psplat[0] = ssef(P.x); @@ -395,7 +391,6 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, # else isect->t = bvh_instance_pop(kg, object, ray, &P, &dir, &idir, isect->t); # endif - triangle_intersect_precalc(dir, &isect_precalc); # if defined(__KERNEL_SSE2__) Psplat[0] = ssef(P.x); diff --git a/intern/cycles/kernel/bvh/bvh_volume.h b/intern/cycles/kernel/bvh/bvh_volume.h index 136034aa484..764aaee44a1 100644 --- a/intern/cycles/kernel/bvh/bvh_volume.h +++ b/intern/cycles/kernel/bvh/bvh_volume.h @@ -18,7 +18,7 @@ */ #ifdef __QBVH__ -# include "qbvh_volume.h" +# include "kernel/bvh/qbvh_volume.h" #endif #if BVH_FEATURE(BVH_HAIR) @@ -97,9 +97,6 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); #endif - IsectPrecalc isect_precalc; - triangle_intersect_precalc(dir, &isect_precalc); - /* traversal loop */ do { do { @@ -194,9 +191,9 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, continue; } triangle_intersect(kg, - &isect_precalc, isect, P, + dir, visibility, object, prim_addr); @@ -243,8 +240,6 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, isect->t = bvh_instance_push(kg, object, ray, &P, &dir, &idir, isect->t); # endif - triangle_intersect_precalc(dir, &isect_precalc); - # if defined(__KERNEL_SSE2__) Psplat[0] = ssef(P.x); Psplat[1] = ssef(P.y); @@ -286,8 +281,6 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, isect->t = bvh_instance_pop(kg, object, ray, &P, &dir, &idir, isect->t); # endif - triangle_intersect_precalc(dir, &isect_precalc); - # if defined(__KERNEL_SSE2__) Psplat[0] = ssef(P.x); Psplat[1] = ssef(P.y); diff --git a/intern/cycles/kernel/bvh/bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h index 6f3346e7634..04ec334e54d 100644 --- a/intern/cycles/kernel/bvh/bvh_volume_all.h +++ b/intern/cycles/kernel/bvh/bvh_volume_all.h @@ -18,7 +18,7 @@ */ #ifdef __QBVH__ -# include "qbvh_volume_all.h" +# include "kernel/bvh/qbvh_volume_all.h" #endif #if BVH_FEATURE(BVH_HAIR) @@ -101,9 +101,6 @@ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); #endif /* __KERNEL_SSE2__ */ - IsectPrecalc isect_precalc; - triangle_intersect_precalc(dir, &isect_precalc); - /* traversal loop */ do { do { @@ -199,9 +196,9 @@ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, continue; } hit = triangle_intersect(kg, - &isect_precalc, isect_array, P, + dir, visibility, object, prim_addr); @@ -294,7 +291,6 @@ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, isect_t = bvh_instance_push(kg, object, ray, &P, &dir, &idir, isect_t); # endif - triangle_intersect_precalc(dir, &isect_precalc); num_hits_in_instance = 0; isect_array->t = isect_t; @@ -340,7 +336,6 @@ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, # else bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac); # endif - triangle_intersect_precalc(dir, &isect_precalc); /* Scale isect->t to adjust for instancing. */ for(int i = 0; i < num_hits_in_instance; i++) { (isect_array-i-1)->t *= t_fac; @@ -352,7 +347,6 @@ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, # else bvh_instance_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX); # endif - triangle_intersect_precalc(dir, &isect_precalc); } isect_t = tmax; diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h index 2a4da3eea82..ce474438f2c 100644 --- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h @@ -33,6 +33,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, Intersection *isect_array, + const int skip_object, const uint max_hits, uint *num_hits) { @@ -96,15 +97,13 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, &near_x, &near_y, &near_z, &far_x, &far_y, &far_z); - IsectPrecalc isect_precalc; - triangle_intersect_precalc(dir, &isect_precalc); - /* Traversal loop. */ do { do { /* Traverse internal nodes. */ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + (void)inodes; if(false #ifdef __VISIBILITY_FLAG__ @@ -270,6 +269,16 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, 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 @@ -279,9 +288,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, switch(p_type) { case PRIMITIVE_TRIANGLE: { hit = triangle_intersect(kg, - &isect_precalc, isect_array, P, + dir, PATH_RAY_SHADOW, object, prim_addr); @@ -414,8 +423,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif - triangle_intersect_precalc(dir, &isect_precalc); - ++stack_ptr; kernel_assert(stack_ptr < BVH_QSTACK_SIZE); traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL; @@ -471,8 +478,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif - triangle_intersect_precalc(dir, &isect_precalc); - object = OBJECT_NONE; node_addr = traversal_stack[stack_ptr].addr; --stack_ptr; diff --git a/intern/cycles/kernel/bvh/qbvh_subsurface.h b/intern/cycles/kernel/bvh/qbvh_subsurface.h index a6431a94e6e..be7658d11d7 100644 --- a/intern/cycles/kernel/bvh/qbvh_subsurface.h +++ b/intern/cycles/kernel/bvh/qbvh_subsurface.h @@ -105,9 +105,6 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, &near_x, &near_y, &near_z, &far_x, &far_y, &far_z); - IsectPrecalc isect_precalc; - triangle_intersect_precalc(dir, &isect_precalc); - /* Traversal loop. */ do { do { @@ -253,9 +250,9 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, for(; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); triangle_intersect_subsurface(kg, - &isect_precalc, ss_isect, P, + dir, object, prim_addr, isect_t, diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h index c20a8f3703f..fca75a1d416 100644 --- a/intern/cycles/kernel/bvh/qbvh_traversal.h +++ b/intern/cycles/kernel/bvh/qbvh_traversal.h @@ -106,15 +106,13 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, &near_x, &near_y, &near_z, &far_x, &far_y, &far_z); - IsectPrecalc isect_precalc; - triangle_intersect_precalc(dir, &isect_precalc); - /* Traversal loop. */ do { do { /* Traverse internal nodes. */ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + (void)inodes; if(UNLIKELY(node_dist > isect->t) #if BVH_FEATURE(BVH_MOTION) @@ -122,8 +120,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, || UNLIKELY(ray->time > inodes.z) #endif #ifdef __VISIBILITY_FLAG__ - || (__float_as_uint(inodes.x) & visibility) == 0) + || (__float_as_uint(inodes.x) & visibility) == 0 #endif + ) { /* Pop. */ node_addr = traversal_stack[stack_ptr].addr; @@ -333,9 +332,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, BVH_DEBUG_NEXT_INTERSECTION(); kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); if(triangle_intersect(kg, - &isect_precalc, isect, P, + dir, visibility, object, prim_addr)) { @@ -447,8 +446,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif - triangle_intersect_precalc(dir, &isect_precalc); - ++stack_ptr; kernel_assert(stack_ptr < BVH_QSTACK_SIZE); traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL; @@ -489,8 +486,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif - triangle_intersect_precalc(dir, &isect_precalc); - object = OBJECT_NONE; node_addr = traversal_stack[stack_ptr].addr; node_dist = traversal_stack[stack_ptr].dist; diff --git a/intern/cycles/kernel/bvh/qbvh_volume.h b/intern/cycles/kernel/bvh/qbvh_volume.h index 859c5da808b..192ce009524 100644 --- a/intern/cycles/kernel/bvh/qbvh_volume.h +++ b/intern/cycles/kernel/bvh/qbvh_volume.h @@ -91,9 +91,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, &near_x, &near_y, &near_z, &far_x, &far_y, &far_z); - IsectPrecalc isect_precalc; - triangle_intersect_precalc(dir, &isect_precalc); - /* Traversal loop. */ do { do { @@ -266,7 +263,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, continue; } /* Intersect ray against primitive. */ - triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, prim_addr); + triangle_intersect(kg, isect, P, dir, visibility, object, prim_addr); } break; } @@ -316,8 +313,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif - triangle_intersect_precalc(dir, &isect_precalc); - ++stack_ptr; kernel_assert(stack_ptr < BVH_QSTACK_SIZE); traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL; @@ -362,8 +357,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif - triangle_intersect_precalc(dir, &isect_precalc); - object = OBJECT_NONE; node_addr = traversal_stack[stack_ptr].addr; --stack_ptr; diff --git a/intern/cycles/kernel/bvh/qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h index bbe588c878f..ac5f58a9a51 100644 --- a/intern/cycles/kernel/bvh/qbvh_volume_all.h +++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h @@ -95,9 +95,6 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, &near_x, &near_y, &near_z, &far_x, &far_y, &far_z); - IsectPrecalc isect_precalc; - triangle_intersect_precalc(dir, &isect_precalc); - /* Traversal loop. */ do { do { @@ -271,7 +268,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, continue; } /* Intersect ray against primitive. */ - hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, prim_addr); + hit = triangle_intersect(kg, isect_array, P, dir, visibility, object, prim_addr); if(hit) { /* Move on to next entry in intersections array. */ isect_array++; @@ -367,7 +364,6 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif - triangle_intersect_precalc(dir, &isect_precalc); num_hits_in_instance = 0; isect_array->t = isect_t; @@ -432,8 +428,6 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif - triangle_intersect_precalc(dir, &isect_precalc); - object = OBJECT_NONE; node_addr = traversal_stack[stack_ptr].addr; --stack_ptr; diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index a44b9e2d9b9..9139b99353a 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -14,37 +14,37 @@ * limitations under the License. */ -#include "../closure/bsdf_ashikhmin_velvet.h" -#include "../closure/bsdf_diffuse.h" -#include "../closure/bsdf_oren_nayar.h" -#include "../closure/bsdf_phong_ramp.h" -#include "../closure/bsdf_diffuse_ramp.h" -#include "../closure/bsdf_microfacet.h" -#include "../closure/bsdf_microfacet_multi.h" -#include "../closure/bsdf_reflection.h" -#include "../closure/bsdf_refraction.h" -#include "../closure/bsdf_transparent.h" -#include "../closure/bsdf_ashikhmin_shirley.h" -#include "../closure/bsdf_toon.h" -#include "../closure/bsdf_hair.h" +#include "kernel/closure/bsdf_ashikhmin_velvet.h" +#include "kernel/closure/bsdf_diffuse.h" +#include "kernel/closure/bsdf_oren_nayar.h" +#include "kernel/closure/bsdf_phong_ramp.h" +#include "kernel/closure/bsdf_diffuse_ramp.h" +#include "kernel/closure/bsdf_microfacet.h" +#include "kernel/closure/bsdf_microfacet_multi.h" +#include "kernel/closure/bsdf_reflection.h" +#include "kernel/closure/bsdf_refraction.h" +#include "kernel/closure/bsdf_transparent.h" +#include "kernel/closure/bsdf_ashikhmin_shirley.h" +#include "kernel/closure/bsdf_toon.h" +#include "kernel/closure/bsdf_hair.h" #ifdef __SUBSURFACE__ -# include "../closure/bssrdf.h" +# include "kernel/closure/bssrdf.h" #endif #ifdef __VOLUME__ -# include "../closure/volume.h" +# include "kernel/closure/volume.h" #endif CCL_NAMESPACE_BEGIN ccl_device_forceinline int bsdf_sample(KernelGlobals *kg, - ShaderData *sd, - const ShaderClosure *sc, - float randu, - float randv, - float3 *eval, - float3 *omega_in, - differential3 *domega_in, - float *pdf) + ShaderData *sd, + const ShaderClosure *sc, + float randu, + float randv, + float3 *eval, + float3 *omega_in, + differential3 *domega_in, + float *pdf) { int label; diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h index 1dd24078037..7d87727004f 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h @@ -313,18 +313,18 @@ ccl_device_forceinline float mf_glass_pdf(const float3 wi, const float3 wo, cons #define MF_PHASE_FUNCTION glass #define MF_MULTI_GLASS -#include "bsdf_microfacet_multi_impl.h" +#include "kernel/closure/bsdf_microfacet_multi_impl.h" /* The diffuse phase function is not implemented as a node yet. */ #if 0 #define MF_PHASE_FUNCTION diffuse #define MF_MULTI_DIFFUSE -#include "bsdf_microfacet_multi_impl.h" +#include "kernel/closure/bsdf_microfacet_multi_impl.h" #endif #define MF_PHASE_FUNCTION glossy #define MF_MULTI_GLOSSY -#include "bsdf_microfacet_multi_impl.h" +#include "kernel/closure/bsdf_microfacet_multi_impl.h" ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughness) { diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h index 6838e26c242..c623e3490fd 100644 --- a/intern/cycles/kernel/geom/geom.h +++ b/intern/cycles/kernel/geom/geom.h @@ -14,19 +14,19 @@ * limitations under the License. */ -#include "geom_attribute.h" -#include "geom_object.h" +#include "kernel/geom/geom_attribute.h" +#include "kernel/geom/geom_object.h" #ifdef __PATCH_EVAL__ -# include "geom_patch.h" +# include "kernel/geom/geom_patch.h" #endif -#include "geom_triangle.h" -#include "geom_subd_triangle.h" -#include "geom_triangle_intersect.h" -#include "geom_motion_triangle.h" -#include "geom_motion_triangle_intersect.h" -#include "geom_motion_triangle_shader.h" -#include "geom_motion_curve.h" -#include "geom_curve.h" -#include "geom_volume.h" -#include "geom_primitive.h" +#include "kernel/geom/geom_triangle.h" +#include "kernel/geom/geom_subd_triangle.h" +#include "kernel/geom/geom_triangle_intersect.h" +#include "kernel/geom/geom_motion_triangle.h" +#include "kernel/geom/geom_motion_triangle_intersect.h" +#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_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 7cc840ce78d..5c3b0ee3c15 100644 --- a/intern/cycles/kernel/geom/geom_curve.h +++ b/intern/cycles/kernel/geom/geom_curve.h @@ -22,6 +22,12 @@ CCL_NAMESPACE_BEGIN #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) @@ -222,10 +228,10 @@ ccl_device_inline ssef transform_point_T3(const ssef t[3], const ssef &a) #ifdef __KERNEL_SSE2__ /* Pass P and dir by reference to aligned vector */ -ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersection *isect, +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_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersection *isect, +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 { @@ -264,7 +270,7 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte int ka = max(k0 - 1, v00.x); int kb = min(k1 + 1, v00.x + v00.y - 1); -#ifdef __KERNEL_AVX2__ +#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); @@ -299,7 +305,7 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte ssef htfm1 = shuffle<1, 0, 1, 3>(load1f_first(extract<0>(d_ss)), vdir0); ssef htfm2 = shuffle<1, 3, 2, 3>(mul_shuf, vdir0); -#ifdef __KERNEL_AVX2__ +#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); @@ -559,7 +565,7 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte 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)); + 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); @@ -688,7 +694,7 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte return hit; } -ccl_device_forceinline bool bvh_curve_intersect(KernelGlobals *kg, Intersection *isect, +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 */ diff --git a/intern/cycles/kernel/geom/geom_motion_curve.h b/intern/cycles/kernel/geom/geom_motion_curve.h index dc1388b6643..119bdb2f15c 100644 --- a/intern/cycles/kernel/geom/geom_motion_curve.h +++ b/intern/cycles/kernel/geom/geom_motion_curve.h @@ -152,7 +152,7 @@ ccl_device_inline void motion_cardinal_curve_keys(KernelGlobals *kg, keys[3] = (1.0f - t)*keys[3] + t*next_keys[3]; } -#ifdef __KERNEL_AVX2__ +#if defined(__KERNEL_AVX2__) && defined(__KERNEL_SSE__) /* Similar to above, but returns keys as pair of two AVX registers with each * holding two float4. */ diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h b/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h index 2500228281e..f74995becf5 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h @@ -166,14 +166,15 @@ float3 motion_triangle_refine_subsurface(KernelGlobals *kg, * time and do a ray intersection with the resulting triangle. */ -ccl_device_inline bool motion_triangle_intersect(KernelGlobals *kg, - Intersection *isect, - float3 P, - float3 dir, - float time, - uint visibility, - int object, - int prim_addr) +ccl_device_inline bool motion_triangle_intersect( + KernelGlobals *kg, + Intersection *isect, + float3 P, + float3 dir, + float time, + uint visibility, + int object, + int prim_addr) { /* Primitive index for vertex location lookup. */ int prim = kernel_tex_fetch(__prim_index, prim_addr); @@ -185,11 +186,15 @@ ccl_device_inline bool motion_triangle_intersect(KernelGlobals *kg, motion_triangle_vertices(kg, fobject, prim, time, verts); /* Ray-triangle intersection, unoptimized. */ float t, u, v; - if(ray_triangle_intersect_uv(P, - dir, - isect->t, - verts[2], verts[0], verts[1], - &u, &v, &t)) + if(ray_triangle_intersect(P, + dir, + isect->t, +#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) + (ssef*)verts, +#else + verts[0], verts[1], verts[2], +#endif + &u, &v, &t)) { #ifdef __VISIBILITY_FLAG__ /* Visibility flag test. we do it here under the assumption @@ -237,11 +242,15 @@ ccl_device_inline void motion_triangle_intersect_subsurface( motion_triangle_vertices(kg, fobject, prim, time, verts); /* Ray-triangle intersection, unoptimized. */ float t, u, v; - if(ray_triangle_intersect_uv(P, - dir, - tmax, - verts[2], verts[0], verts[1], - &u, &v, &t)) + if(ray_triangle_intersect(P, + dir, + tmax, +#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) + (ssef*)verts, +#else + verts[0], verts[1], verts[2], +#endif + &u, &v, &t)) { for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) { if(ss_isect->hits[i].t == t) { diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index 4d234dd62bd..804e74d7e37 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -22,232 +22,50 @@ CCL_NAMESPACE_BEGIN -/* Workaround stupidness of CUDA/OpenCL which doesn't allow to access indexed - * component of float3 value. - */ -#ifndef __KERNEL_CPU__ -# define IDX(vec, idx) \ - ((idx == 0) ? ((vec).x) : ( (idx == 1) ? ((vec).y) : ((vec).z) )) -#else -# define IDX(vec, idx) ((vec)[idx]) -#endif - -/* Ray-Triangle intersection for BVH traversal - * - * Sven Woop - * Watertight Ray/Triangle Intersection - * - * http://jcgt.org/published/0002/01/05/paper.pdf - */ - -/* Precalculated data for the ray->tri intersection. */ -typedef struct IsectPrecalc { - /* Maximal dimension kz, and orthogonal dimensions. */ - int kx, ky, kz; - - /* Shear constants. */ - float Sx, Sy, Sz; -} IsectPrecalc; - -#if (defined(__KERNEL_OPENCL_APPLE__)) || \ - (defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86))) -ccl_device_noinline -#else -ccl_device_inline -#endif -void triangle_intersect_precalc(float3 dir, - IsectPrecalc *isect_precalc) -{ - /* Calculate dimension where the ray direction is maximal. */ -#ifndef __KERNEL_SSE__ - int kz = util_max_axis(make_float3(fabsf(dir.x), - fabsf(dir.y), - fabsf(dir.z))); - int kx = kz + 1; if(kx == 3) kx = 0; - int ky = kx + 1; if(ky == 3) ky = 0; -#else - int kx, ky, kz; - /* Avoiding mispredicted branch on direction. */ - kz = util_max_axis(fabs(dir)); - static const char inc_xaxis[] = {1, 2, 0, 55}; - static const char inc_yaxis[] = {2, 0, 1, 55}; - kx = inc_xaxis[kz]; - ky = inc_yaxis[kz]; -#endif - - float dir_kz = IDX(dir, kz); - - /* Swap kx and ky dimensions to preserve winding direction of triangles. */ - if(dir_kz < 0.0f) { - int tmp = kx; - kx = ky; - ky = tmp; - } - - /* Calculate the shear constants. */ - float inv_dir_z = 1.0f / dir_kz; - isect_precalc->Sx = IDX(dir, kx) * inv_dir_z; - isect_precalc->Sy = IDX(dir, ky) * inv_dir_z; - isect_precalc->Sz = inv_dir_z; - - /* Store the dimensions. */ - isect_precalc->kx = kx; - isect_precalc->ky = ky; - isect_precalc->kz = kz; -} - -/* TODO(sergey): Make it general utility function. */ -ccl_device_inline float xor_signmask(float x, int y) -{ - return __int_as_float(__float_as_int(x) ^ y); -} - ccl_device_inline bool triangle_intersect(KernelGlobals *kg, - const IsectPrecalc *isect_precalc, Intersection *isect, float3 P, + float3 dir, uint visibility, int object, int prim_addr) { - const int kx = isect_precalc->kx; - const int ky = isect_precalc->ky; - const int kz = isect_precalc->kz; - const float Sx = isect_precalc->Sx; - const float Sy = isect_precalc->Sy; - const float Sz = isect_precalc->Sz; - - /* Calculate vertices relative to ray origin. */ const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, prim_addr); - -#if defined(__KERNEL_AVX2__) && defined(__KERNEL_SSE__) - const avxf avxf_P(P.m128, P.m128); - - const avxf tri_ab = kernel_tex_fetch_avxf(__prim_tri_verts, tri_vindex + 0); - const avxf tri_bc = kernel_tex_fetch_avxf(__prim_tri_verts, tri_vindex + 1); - - const avxf AB = tri_ab - avxf_P; - const avxf BC = tri_bc - avxf_P; - - const __m256i permute_mask = _mm256_set_epi32(0x3, kz, ky, kx, 0x3, kz, ky, kx); - - const avxf AB_k = shuffle(AB, permute_mask); - const avxf BC_k = shuffle(BC, permute_mask); - - /* Akz, Akz, Bkz, Bkz, Bkz, Bkz, Ckz, Ckz */ - const avxf ABBC_kz = shuffle<2>(AB_k, BC_k); - - /* Akx, Aky, Bkx, Bky, Bkx,Bky, Ckx, Cky */ - const avxf ABBC_kxy = shuffle<0,1,0,1>(AB_k, BC_k); - - const avxf Sxy(Sy, Sx, Sy, Sx); - - /* Ax, Ay, Bx, By, Bx, By, Cx, Cy */ - const avxf ABBC_xy = nmadd(ABBC_kz, Sxy, ABBC_kxy); - - float ABBC_kz_array[8]; - _mm256_storeu_ps((float*)&ABBC_kz_array, ABBC_kz); - - const float A_kz = ABBC_kz_array[0]; - const float B_kz = ABBC_kz_array[2]; - const float C_kz = ABBC_kz_array[6]; - - /* By, Bx, Cy, Cx, By, Bx, Ay, Ax */ - const avxf BCBA_yx = permute<3,2,7,6,3,2,1,0>(ABBC_xy); - - const avxf neg_mask(0,0,0,0,0x80000000, 0x80000000, 0x80000000, 0x80000000); - - /* W U V - * (AxBy-AyBx) (BxCy-ByCx) XX XX (BxBy-ByBx) (CxAy-CyAx) XX XX - */ - const avxf WUxxxxVxx_neg = _mm256_hsub_ps(ABBC_xy * BCBA_yx, neg_mask /* Dont care */); - - const avxf WUVWnegWUVW = permute<0,1,5,0,0,1,5,0>(WUxxxxVxx_neg) ^ neg_mask; - - /* Calculate scaled barycentric coordinates. */ - float WUVW_array[4]; - _mm_storeu_ps((float*)&WUVW_array, _mm256_castps256_ps128 (WUVWnegWUVW)); - - const float W = WUVW_array[0]; - const float U = WUVW_array[1]; - const float V = WUVW_array[2]; - - const int WUVW_mask = 0x7 & _mm256_movemask_ps(WUVWnegWUVW); - const int WUVW_zero = 0x7 & _mm256_movemask_ps(_mm256_cmp_ps(WUVWnegWUVW, - _mm256_setzero_ps(), 0)); - - if(!((WUVW_mask == 7) || (WUVW_mask == 0)) && ((WUVW_mask | WUVW_zero) != 7)) { - return false; - } +#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) + const ssef *ssef_verts = (ssef*)&kg->__prim_tri_verts.data[tri_vindex]; #else const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0), tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2); - const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z); - const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z); - const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z); - - const float A_kx = IDX(A, kx), A_ky = IDX(A, ky), A_kz = IDX(A, kz); - const float B_kx = IDX(B, kx), B_ky = IDX(B, ky), B_kz = IDX(B, kz); - const float C_kx = IDX(C, kx), C_ky = IDX(C, ky), C_kz = IDX(C, kz); - - /* Perform shear and scale of vertices. */ - const float Ax = A_kx - Sx * A_kz; - const float Ay = A_ky - Sy * A_kz; - const float Bx = B_kx - Sx * B_kz; - const float By = B_ky - Sy * B_kz; - const float Cx = C_kx - Sx * C_kz; - const float Cy = C_ky - Sy * C_kz; - - /* Calculate scaled barycentric coordinates. */ - float U = Cx * By - Cy * Bx; - float V = Ax * Cy - Ay * Cx; - float W = Bx * Ay - By * Ax; - if((U < 0.0f || V < 0.0f || W < 0.0f) && - (U > 0.0f || V > 0.0f || W > 0.0f)) - { - return false; - } #endif - - /* Calculate determinant. */ - float det = U + V + W; - if(UNLIKELY(det == 0.0f)) { - return false; - } - - /* Calculate scaled z-coordinates of vertices and use them to calculate - * the hit distance. - */ - const float T = (U * A_kz + V * B_kz + W * C_kz) * Sz; - const int sign_det = (__float_as_int(det) & 0x80000000); - const float sign_T = xor_signmask(T, sign_det); - if((sign_T < 0.0f) || - (sign_T > isect->t * xor_signmask(det, sign_det))) + float t, u, v; + if(ray_triangle_intersect(P, + dir, + isect->t, +#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) + ssef_verts, +#else + float4_to_float3(tri_a), + float4_to_float3(tri_b), + float4_to_float3(tri_c), +#endif + &u, &v, &t)) { - 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, prim_addr) & visibility) + /* Visibility flag test. we do it here under the assumption + * that most triangles are culled by node flags. + */ + if(kernel_tex_fetch(__prim_visibility, prim_addr) & visibility) #endif - { -#ifdef __KERNEL_CUDA__ - if(A == B && B == C) { - return false; + { + isect->prim = prim_addr; + isect->object = object; + isect->type = PRIMITIVE_TRIANGLE; + isect->u = u; + isect->v = v; + isect->t = t; + return true; } -#endif - /* Normalize U, V, W, and T. */ - const float inv_det = 1.0f / det; - isect->prim = prim_addr; - isect->object = object; - isect->type = PRIMITIVE_TRIANGLE; - isect->u = U * inv_det; - isect->v = V * inv_det; - isect->t = T * inv_det; - return true; } return false; } @@ -260,138 +78,37 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, #ifdef __SUBSURFACE__ ccl_device_inline void triangle_intersect_subsurface( KernelGlobals *kg, - const IsectPrecalc *isect_precalc, SubsurfaceIntersection *ss_isect, float3 P, + float3 dir, int object, int prim_addr, float tmax, uint *lcg_state, int max_hits) { - const int kx = isect_precalc->kx; - const int ky = isect_precalc->ky; - const int kz = isect_precalc->kz; - const float Sx = isect_precalc->Sx; - const float Sy = isect_precalc->Sy; - const float Sz = isect_precalc->Sz; - - /* Calculate vertices relative to ray origin. */ const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, prim_addr); - const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0), - tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), - tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2); - -#if defined(__KERNEL_AVX2__) && defined(__KERNEL_SSE__) - const avxf avxf_P(P.m128, P.m128); - - const avxf tri_ab = kernel_tex_fetch_avxf(__prim_tri_verts, tri_vindex + 0); - const avxf tri_bc = kernel_tex_fetch_avxf(__prim_tri_verts, tri_vindex + 1); - - const avxf AB = tri_ab - avxf_P; - const avxf BC = tri_bc - avxf_P; - - const __m256i permuteMask = _mm256_set_epi32(0x3, kz, ky, kx, 0x3, kz, ky, kx); - - const avxf AB_k = shuffle(AB, permuteMask); - const avxf BC_k = shuffle(BC, permuteMask); - - /* Akz, Akz, Bkz, Bkz, Bkz, Bkz, Ckz, Ckz */ - const avxf ABBC_kz = shuffle<2>(AB_k, BC_k); - - /* Akx, Aky, Bkx, Bky, Bkx,Bky, Ckx, Cky */ - const avxf ABBC_kxy = shuffle<0,1,0,1>(AB_k, BC_k); - - const avxf Sxy(Sy, Sx, Sy, Sx); - - /* Ax, Ay, Bx, By, Bx, By, Cx, Cy */ - const avxf ABBC_xy = nmadd(ABBC_kz, Sxy, ABBC_kxy); - - float ABBC_kz_array[8]; - _mm256_storeu_ps((float*)&ABBC_kz_array, ABBC_kz); - - const float A_kz = ABBC_kz_array[0]; - const float B_kz = ABBC_kz_array[2]; - const float C_kz = ABBC_kz_array[6]; - - /* By, Bx, Cy, Cx, By, Bx, Ay, Ax */ - const avxf BCBA_yx = permute<3,2,7,6,3,2,1,0>(ABBC_xy); - - const avxf negMask(0,0,0,0,0x80000000, 0x80000000, 0x80000000, 0x80000000); - - /* W U V - * (AxBy-AyBx) (BxCy-ByCx) XX XX (BxBy-ByBx) (CxAy-CyAx) XX XX - */ - const avxf WUxxxxVxx_neg = _mm256_hsub_ps(ABBC_xy * BCBA_yx, negMask /* Dont care */); - - const avxf WUVWnegWUVW = permute<0,1,5,0,0,1,5,0>(WUxxxxVxx_neg) ^ negMask; - - /* Calculate scaled barycentric coordinates. */ - float WUVW_array[4]; - _mm_storeu_ps((float*)&WUVW_array, _mm256_castps256_ps128 (WUVWnegWUVW)); - - const float W = WUVW_array[0]; - const float U = WUVW_array[1]; - const float V = WUVW_array[2]; - - const int WUVW_mask = 0x7 & _mm256_movemask_ps(WUVWnegWUVW); - const int WUVW_zero = 0x7 & _mm256_movemask_ps(_mm256_cmp_ps(WUVWnegWUVW, - _mm256_setzero_ps(), 0)); - - if(!((WUVW_mask == 7) || (WUVW_mask == 0)) && ((WUVW_mask | WUVW_zero) != 7)) { - return; - } +#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) + const ssef *ssef_verts = (ssef*)&kg->__prim_tri_verts.data[tri_vindex]; #else - const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z); - const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z); - const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z); - - const float A_kx = IDX(A, kx), A_ky = IDX(A, ky), A_kz = IDX(A, kz); - const float B_kx = IDX(B, kx), B_ky = IDX(B, ky), B_kz = IDX(B, kz); - const float C_kx = IDX(C, kx), C_ky = IDX(C, ky), C_kz = IDX(C, kz); - - /* Perform shear and scale of vertices. */ - const float Ax = A_kx - Sx * A_kz; - const float Ay = A_ky - Sy * A_kz; - const float Bx = B_kx - Sx * B_kz; - const float By = B_ky - Sy * B_kz; - const float Cx = C_kx - Sx * C_kz; - const float Cy = C_ky - Sy * C_kz; - - /* Calculate scaled barycentric coordinates. */ - float U = Cx * By - Cy * Bx; - float V = Ax * Cy - Ay * Cx; - float W = Bx * Ay - By * Ax; - - if((U < 0.0f || V < 0.0f || W < 0.0f) && - (U > 0.0f || V > 0.0f || W > 0.0f)) - { - return; - } + const float3 tri_a = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex+0)), + tri_b = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex+1)), + tri_c = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex+2)); #endif - - /* Calculate determinant. */ - float det = U + V + W; - if(UNLIKELY(det == 0.0f)) { - return; - } - - /* Calculate scaled z−coordinates of vertices and use them to calculate - * the hit distance. - */ - const int sign_det = (__float_as_int(det) & 0x80000000); - const float T = (U * A_kz + V * B_kz + W * C_kz) * Sz; - const float sign_T = xor_signmask(T, sign_det); - if((sign_T < 0.0f) || - (sign_T > tmax * xor_signmask(det, sign_det))) + float t, u, v; + if(!ray_triangle_intersect(P, + dir, + tmax, +#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) + ssef_verts, +#else + tri_a, tri_b, tri_c, +#endif + &u, &v, &t)) { return; } - /* Normalize U, V, W, and T. */ - const float inv_det = 1.0f / det; - - const float t = T * inv_det; for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) { if(ss_isect->hits[i].t == t) { return; @@ -418,18 +135,19 @@ ccl_device_inline void triangle_intersect_subsurface( isect->prim = prim_addr; isect->object = object; isect->type = PRIMITIVE_TRIANGLE; - isect->u = U * inv_det; - isect->v = V * inv_det; + isect->u = u; + isect->v = v; isect->t = t; /* Record geometric normal. */ - /* TODO(sergey): Use float4_to_float3() on just an edges. */ - const float3 v0 = float4_to_float3(tri_a); - const float3 v1 = float4_to_float3(tri_b); - const float3 v2 = float4_to_float3(tri_c); - ss_isect->Ng[hit] = normalize(cross(v1 - v0, v2 - v0)); -} +#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) + const float3 tri_a = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex+0)), + tri_b = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex+1)), + tri_c = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex+2)); #endif + ss_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a)); +} +#endif /* __SUBSURFACE__ */ /* Refine triangle intersection to more precise hit point. For rays that travel * far the precision is often not so good, this reintersects the primitive from @@ -570,6 +288,4 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg, return P; } -#undef IDX - CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel.h b/intern/cycles/kernel/kernel.h index cd339e6237e..06c0fb2fbca 100644 --- a/intern/cycles/kernel/kernel.h +++ b/intern/cycles/kernel/kernel.h @@ -19,8 +19,8 @@ /* CPU Kernel Interface */ -#include "util_types.h" -#include "kernel_types.h" +#include "util/util_types.h" +#include "kernel/kernel_types.h" CCL_NAMESPACE_BEGIN @@ -48,31 +48,31 @@ void kernel_tex_copy(KernelGlobals *kg, ExtensionType extension = EXTENSION_REPEAT); #define KERNEL_ARCH cpu -#include "kernels/cpu/kernel_cpu.h" +#include "kernel/kernels/cpu/kernel_cpu.h" #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 # define KERNEL_ARCH cpu_sse2 -# include "kernels/cpu/kernel_cpu.h" +# include "kernel/kernels/cpu/kernel_cpu.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 */ #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3 # define KERNEL_ARCH cpu_sse3 -# include "kernels/cpu/kernel_cpu.h" +# include "kernel/kernels/cpu/kernel_cpu.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 */ #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 # define KERNEL_ARCH cpu_sse41 -# include "kernels/cpu/kernel_cpu.h" +# include "kernel/kernels/cpu/kernel_cpu.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 */ #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX # define KERNEL_ARCH cpu_avx -# include "kernels/cpu/kernel_cpu.h" +# include "kernel/kernels/cpu/kernel_cpu.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX */ #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 # define KERNEL_ARCH cpu_avx2 -# include "kernels/cpu/kernel_cpu.h" +# include "kernel/kernels/cpu/kernel_cpu.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 */ CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h index 6c3ee6b8098..823d30dde78 100644 --- a/intern/cycles/kernel/kernel_accumulate.h +++ b/intern/cycles/kernel/kernel_accumulate.h @@ -52,10 +52,17 @@ ccl_device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 v { eval->diffuse = value; } +#ifdef __SHADOW_TRICKS__ + eval->sum_no_mis = make_float3(0.0f, 0.0f, 0.0f); +#endif } -ccl_device_inline void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value) +ccl_device_inline void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value, float mis_weight) { +#ifdef __SHADOW_TRICKS__ + eval->sum_no_mis += value; +#endif + value *= mis_weight; #ifdef __PASSES__ if(eval->use_light_pass) { if(CLOSURE_IS_BSDF_DIFFUSE(type)) @@ -96,7 +103,7 @@ ccl_device_inline bool bsdf_eval_is_zero(BsdfEval *eval) } } -ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float value) +ccl_device_inline void bsdf_eval_mis(BsdfEval *eval, float value) { #ifdef __PASSES__ if(eval->use_light_pass) { @@ -115,8 +122,19 @@ ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float value) } } +ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float value) +{ +#ifdef __SHADOW_TRICKS__ + eval->sum_no_mis *= value; +#endif + bsdf_eval_mis(eval, value); +} + ccl_device_inline void bsdf_eval_mul3(BsdfEval *eval, float3 value) { +#ifdef __SHADOW_TRICKS__ + eval->sum_no_mis *= value; +#endif #ifdef __PASSES__ if(eval->use_light_pass) { eval->diffuse *= value; @@ -134,7 +152,7 @@ ccl_device_inline void bsdf_eval_mul3(BsdfEval *eval, float3 value) #endif } -ccl_device_inline float3 bsdf_eval_sum(BsdfEval *eval) +ccl_device_inline float3 bsdf_eval_sum(const BsdfEval *eval) { #ifdef __PASSES__ if(eval->use_light_pass) { @@ -198,6 +216,12 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass) { 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); +#endif } ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space float3 *throughput, @@ -252,7 +276,12 @@ ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, float3 thro } } -ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput, float3 alpha, float3 bsdf, float3 ao, int bounce) +ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, + float3 throughput, + float3 alpha, + float3 bsdf, + float3 ao, + int bounce) { #ifdef __PASSES__ if(L->use_light_pass) { @@ -271,6 +300,26 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput { L->emission += throughput*bsdf*ao; } + +#ifdef __SHADOW_TRICKS__ + float3 light = throughput * bsdf; + L->path_total += light; + L->path_total_shaded += ao * light; +#endif +} + +ccl_device_inline void path_radiance_accum_total_ao( + PathRadiance *L, + float3 throughput, + float3 bsdf) +{ +#ifdef __SHADOW_TRICKS__ + L->path_total += throughput * bsdf; +#else + (void) L; + (void) throughput; + (void) bsdf; +#endif } ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 throughput, BsdfEval *bsdf_eval, float3 shadow, float shadow_fac, int bounce, bool is_lamp) @@ -301,15 +350,38 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 through { L->emission += throughput*bsdf_eval->diffuse*shadow; } + +#ifdef __SHADOW_TRICKS__ + 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( + PathRadiance *L, + float3 throughput, + const BsdfEval *bsdf_eval) +{ +#ifdef __SHADOW_TRICKS__ + L->path_total += throughput * bsdf_eval->sum_no_mis; +#else + (void) L; + (void) throughput; + (void) bsdf_eval; +#endif } -ccl_device_inline void path_radiance_accum_background(PathRadiance *L, float3 throughput, float3 value, int bounce) +ccl_device_inline void path_radiance_accum_background(PathRadiance *L, + ccl_addr_space PathState *state, + float3 throughput, + float3 value) { #ifdef __PASSES__ if(L->use_light_pass) { - if(bounce == 0) + if(state->bounce == 0) L->background += throughput*value; - else if(bounce == 1) + else if(state->bounce == 1) L->direct_emission += throughput*value; else L->indirect += throughput*value; @@ -319,6 +391,13 @@ ccl_device_inline void path_radiance_accum_background(PathRadiance *L, float3 th { L->emission += throughput*value; } + +#ifdef __SHADOW_TRICKS__ + L->path_total += throughput * value; + if(state->flag & PATH_RAY_SHADOW_CATCHER_ONLY) { + L->path_total_shaded += throughput * value; + } +#endif } ccl_device_inline void path_radiance_sum_indirect(PathRadiance *L) @@ -399,7 +478,7 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi float sum = fabsf((L_sum).x) + fabsf((L_sum).y) + fabsf((L_sum).z); /* Reject invalid value */ - if(!isfinite(sum)) { + if(!isfinite_safe(sum)) { kernel_assert(!"Non-finite sum in path_radiance_clamp_and_sum!"); L_sum = make_float3(0.0f, 0.0f, 0.0f); @@ -468,7 +547,7 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi /* Reject invalid value */ float sum = fabsf((L_sum).x) + fabsf((L_sum).y) + fabsf((L_sum).z); - if(!isfinite(sum)) { + 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); } @@ -501,5 +580,34 @@ ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance L->emission += L_sample->emission * fac; } -CCL_NAMESPACE_END +#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, + ccl_addr_space float* L_transparent) +{ + const float shadow = path_radiance_sum_shadow(L); + float3 L_sum; + if(kernel_data.background.transparent) { + *L_transparent = 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_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h index e347a1eca18..21da180bb8e 100644 --- a/intern/cycles/kernel/kernel_compat_cpu.h +++ b/intern/cycles/kernel/kernel_compat_cpu.h @@ -35,12 +35,12 @@ # define __NODES_FEATURES__ NODE_FEATURE_ALL #endif -#include "util_debug.h" -#include "util_math.h" -#include "util_simd.h" -#include "util_half.h" -#include "util_types.h" -#include "util_texture.h" +#include "util/util_debug.h" +#include "util/util_math.h" +#include "util/util_simd.h" +#include "util/util_half.h" +#include "util/util_types.h" +#include "util/util_texture.h" #define ccl_addr_space @@ -87,9 +87,9 @@ template<typename T> struct texture { ccl_always_inline avxf fetch_avxf(const int index) { kernel_assert(index >= 0 && (index+1) < width); - ssef *ssefData = (ssef*)data; - ssef *ssefNodeData = &ssefData[index]; - return _mm256_loadu_ps((float *)ssefNodeData); + ssef *ssef_data = (ssef*)data; + ssef *ssef_node_data = &ssef_data[index]; + return _mm256_loadu_ps((float *)ssef_node_data); } #endif @@ -316,184 +316,213 @@ template<typename T> struct texture_image { return interp_3d_ex(x, y, z, interpolation); } - ccl_always_inline float4 interp_3d_ex(float x, float y, float z, - int interpolation = INTERPOLATION_LINEAR) + ccl_always_inline float4 interp_3d_ex_closest(float x, float y, float z) { - if(UNLIKELY(!data)) - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - - int ix, iy, iz, nix, niy, niz; - - if(interpolation == INTERPOLATION_CLOSEST) { - frac(x*(float)width, &ix); - frac(y*(float)height, &iy); - frac(z*(float)depth, &iz); - - switch(extension) { - case EXTENSION_REPEAT: - ix = wrap_periodic(ix, width); - iy = wrap_periodic(iy, height); - iz = wrap_periodic(iz, depth); - break; - case EXTENSION_CLIP: - if(x < 0.0f || y < 0.0f || z < 0.0f || - x > 1.0f || y > 1.0f || z > 1.0f) - { - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - /* Fall through. */ - case EXTENSION_EXTEND: - ix = wrap_clamp(ix, width); - iy = wrap_clamp(iy, height); - iz = wrap_clamp(iz, depth); - break; - default: - kernel_assert(0); + int ix, iy, iz; + frac(x*(float)width, &ix); + frac(y*(float)height, &iy); + frac(z*(float)depth, &iz); + + switch(extension) { + case EXTENSION_REPEAT: + ix = wrap_periodic(ix, width); + iy = wrap_periodic(iy, height); + iz = wrap_periodic(iz, depth); + break; + case EXTENSION_CLIP: + if(x < 0.0f || y < 0.0f || z < 0.0f || + x > 1.0f || y > 1.0f || z > 1.0f) + { return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - - return read(data[ix + iy*width + iz*width*height]); + } + /* Fall through. */ + case EXTENSION_EXTEND: + ix = wrap_clamp(ix, width); + iy = wrap_clamp(iy, height); + iz = wrap_clamp(iz, depth); + break; + default: + kernel_assert(0); + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); } - else if(interpolation == INTERPOLATION_LINEAR) { - float tx = frac(x*(float)width - 0.5f, &ix); - float ty = frac(y*(float)height - 0.5f, &iy); - float tz = frac(z*(float)depth - 0.5f, &iz); - - switch(extension) { - case EXTENSION_REPEAT: - ix = wrap_periodic(ix, width); - iy = wrap_periodic(iy, height); - iz = wrap_periodic(iz, depth); - nix = wrap_periodic(ix+1, width); - niy = wrap_periodic(iy+1, height); - niz = wrap_periodic(iz+1, depth); - break; - case EXTENSION_CLIP: - if(x < 0.0f || y < 0.0f || z < 0.0f || - x > 1.0f || y > 1.0f || z > 1.0f) - { - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - /* Fall through. */ - case EXTENSION_EXTEND: - nix = wrap_clamp(ix+1, width); - niy = wrap_clamp(iy+1, height); - niz = wrap_clamp(iz+1, depth); + return read(data[ix + iy*width + iz*width*height]); + } - ix = wrap_clamp(ix, width); - iy = wrap_clamp(iy, height); - iz = wrap_clamp(iz, depth); - break; - default: - kernel_assert(0); + ccl_always_inline float4 interp_3d_ex_linear(float x, float y, float z) + { + int ix, iy, iz; + int nix, niy, niz; + + float tx = frac(x*(float)width - 0.5f, &ix); + float ty = frac(y*(float)height - 0.5f, &iy); + float tz = frac(z*(float)depth - 0.5f, &iz); + + switch(extension) { + case EXTENSION_REPEAT: + ix = wrap_periodic(ix, width); + iy = wrap_periodic(iy, height); + iz = wrap_periodic(iz, depth); + + nix = wrap_periodic(ix+1, width); + niy = wrap_periodic(iy+1, height); + niz = wrap_periodic(iz+1, depth); + break; + case EXTENSION_CLIP: + if(x < 0.0f || y < 0.0f || z < 0.0f || + x > 1.0f || y > 1.0f || z > 1.0f) + { return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - - float4 r; - - r = (1.0f - tz)*(1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width + iz*width*height]); - r += (1.0f - tz)*(1.0f - ty)*tx*read(data[nix + iy*width + iz*width*height]); - r += (1.0f - tz)*ty*(1.0f - tx)*read(data[ix + niy*width + iz*width*height]); - r += (1.0f - tz)*ty*tx*read(data[nix + niy*width + iz*width*height]); - - r += tz*(1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width + niz*width*height]); - r += tz*(1.0f - ty)*tx*read(data[nix + iy*width + niz*width*height]); - r += tz*ty*(1.0f - tx)*read(data[ix + niy*width + niz*width*height]); - r += tz*ty*tx*read(data[nix + niy*width + niz*width*height]); - - return r; + } + /* Fall through. */ + case EXTENSION_EXTEND: + nix = wrap_clamp(ix+1, width); + niy = wrap_clamp(iy+1, height); + niz = wrap_clamp(iz+1, depth); + + ix = wrap_clamp(ix, width); + iy = wrap_clamp(iy, height); + iz = wrap_clamp(iz, depth); + break; + default: + kernel_assert(0); + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); } - else { - /* Tricubic b-spline interpolation. */ - const float tx = frac(x*(float)width - 0.5f, &ix); - const float ty = frac(y*(float)height - 0.5f, &iy); - const float tz = frac(z*(float)depth - 0.5f, &iz); - int pix, piy, piz, nnix, nniy, nniz; - switch(extension) { - case EXTENSION_REPEAT: - ix = wrap_periodic(ix, width); - iy = wrap_periodic(iy, height); - iz = wrap_periodic(iz, depth); + float4 r; - pix = wrap_periodic(ix-1, width); - piy = wrap_periodic(iy-1, height); - piz = wrap_periodic(iz-1, depth); + r = (1.0f - tz)*(1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width + iz*width*height]); + r += (1.0f - tz)*(1.0f - ty)*tx*read(data[nix + iy*width + iz*width*height]); + r += (1.0f - tz)*ty*(1.0f - tx)*read(data[ix + niy*width + iz*width*height]); + r += (1.0f - tz)*ty*tx*read(data[nix + niy*width + iz*width*height]); - nix = wrap_periodic(ix+1, width); - niy = wrap_periodic(iy+1, height); - niz = wrap_periodic(iz+1, depth); + r += tz*(1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width + niz*width*height]); + r += tz*(1.0f - ty)*tx*read(data[nix + iy*width + niz*width*height]); + r += tz*ty*(1.0f - tx)*read(data[ix + niy*width + niz*width*height]); + r += tz*ty*tx*read(data[nix + niy*width + niz*width*height]); - nnix = wrap_periodic(ix+2, width); - nniy = wrap_periodic(iy+2, height); - nniz = wrap_periodic(iz+2, depth); - break; - case EXTENSION_CLIP: - if(x < 0.0f || y < 0.0f || z < 0.0f || - x > 1.0f || y > 1.0f || z > 1.0f) - { - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - /* Fall through. */ - case EXTENSION_EXTEND: - pix = wrap_clamp(ix-1, width); - piy = wrap_clamp(iy-1, height); - piz = wrap_clamp(iz-1, depth); - - nix = wrap_clamp(ix+1, width); - niy = wrap_clamp(iy+1, height); - niz = wrap_clamp(iz+1, depth); - - nnix = wrap_clamp(ix+2, width); - nniy = wrap_clamp(iy+2, height); - nniz = wrap_clamp(iz+2, depth); + return r; + } - ix = wrap_clamp(ix, width); - iy = wrap_clamp(iy, height); - iz = wrap_clamp(iz, depth); - break; - default: - kernel_assert(0); + /* TODO(sergey): For some unspeakable reason both GCC-6 and Clang-3.9 are + * causing stack overflow issue in this function unless it is inlined. + * + * Only happens for AVX2 kernel and global __KERNEL_SSE__ vectorization + * enabled. + */ +#ifdef __GNUC__ + ccl_always_inline +#else + ccl_never_inline +#endif + float4 interp_3d_ex_tricubic(float x, float y, float z) + { + int ix, iy, iz; + int nix, niy, niz; + /* Tricubic b-spline interpolation. */ + const float tx = frac(x*(float)width - 0.5f, &ix); + const float ty = frac(y*(float)height - 0.5f, &iy); + const float tz = frac(z*(float)depth - 0.5f, &iz); + int pix, piy, piz, nnix, nniy, nniz; + + switch(extension) { + case EXTENSION_REPEAT: + ix = wrap_periodic(ix, width); + iy = wrap_periodic(iy, height); + iz = wrap_periodic(iz, depth); + + pix = wrap_periodic(ix-1, width); + piy = wrap_periodic(iy-1, height); + piz = wrap_periodic(iz-1, depth); + + nix = wrap_periodic(ix+1, width); + niy = wrap_periodic(iy+1, height); + niz = wrap_periodic(iz+1, depth); + + nnix = wrap_periodic(ix+2, width); + nniy = wrap_periodic(iy+2, height); + nniz = wrap_periodic(iz+2, depth); + break; + case EXTENSION_CLIP: + if(x < 0.0f || y < 0.0f || z < 0.0f || + x > 1.0f || y > 1.0f || z > 1.0f) + { return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - - const int xc[4] = {pix, ix, nix, nnix}; - const int yc[4] = {width * piy, - width * iy, - width * niy, - width * nniy}; - const int zc[4] = {width * height * piz, - width * height * iz, - width * height * niz, - width * height * nniz}; - float u[4], v[4], w[4]; + } + /* Fall through. */ + case EXTENSION_EXTEND: + pix = wrap_clamp(ix-1, width); + piy = wrap_clamp(iy-1, height); + piz = wrap_clamp(iz-1, depth); + + nix = wrap_clamp(ix+1, width); + niy = wrap_clamp(iy+1, height); + niz = wrap_clamp(iz+1, depth); + + nnix = wrap_clamp(ix+2, width); + nniy = wrap_clamp(iy+2, height); + nniz = wrap_clamp(iz+2, depth); + + ix = wrap_clamp(ix, width); + iy = wrap_clamp(iy, height); + iz = wrap_clamp(iz, depth); + break; + default: + kernel_assert(0); + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } - /* Some helper macro to keep code reasonable size, - * let compiler to inline all the matrix multiplications. - */ + const int xc[4] = {pix, ix, nix, nnix}; + const int yc[4] = {width * piy, + width * iy, + width * niy, + width * nniy}; + const int zc[4] = {width * height * piz, + width * height * iz, + width * height * niz, + width * height * nniz}; + float u[4], v[4], w[4]; + + /* Some helper macro to keep code reasonable size, + * let compiler to inline all the matrix multiplications. + */ #define DATA(x, y, z) (read(data[xc[x] + yc[y] + zc[z]])) #define COL_TERM(col, row) \ - (v[col] * (u[0] * DATA(0, col, row) + \ - u[1] * DATA(1, col, row) + \ - u[2] * DATA(2, col, row) + \ - u[3] * DATA(3, col, row))) + (v[col] * (u[0] * DATA(0, col, row) + \ + u[1] * DATA(1, col, row) + \ + u[2] * DATA(2, col, row) + \ + u[3] * DATA(3, col, row))) #define ROW_TERM(row) \ - (w[row] * (COL_TERM(0, row) + \ - COL_TERM(1, row) + \ - COL_TERM(2, row) + \ - COL_TERM(3, row))) + (w[row] * (COL_TERM(0, row) + \ + COL_TERM(1, row) + \ + COL_TERM(2, row) + \ + COL_TERM(3, row))) - SET_CUBIC_SPLINE_WEIGHTS(u, tx); - SET_CUBIC_SPLINE_WEIGHTS(v, ty); - SET_CUBIC_SPLINE_WEIGHTS(w, tz); + SET_CUBIC_SPLINE_WEIGHTS(u, tx); + SET_CUBIC_SPLINE_WEIGHTS(v, ty); + SET_CUBIC_SPLINE_WEIGHTS(w, tz); - /* Actual interpolation. */ - return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3); + /* Actual interpolation. */ + return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3); #undef COL_TERM #undef ROW_TERM #undef DATA + } + + ccl_always_inline float4 interp_3d_ex(float x, float y, float z, + int interpolation = INTERPOLATION_LINEAR) + { + if(UNLIKELY(!data)) + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + + switch(interpolation) { + case INTERPOLATION_CLOSEST: + return interp_3d_ex_closest(x, y, z); + case INTERPOLATION_LINEAR: + return interp_3d_ex_linear(x, y, z); + default: + return interp_3d_ex_tricubic(x, y, z); } } diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h index 37a9e8d2f84..c375d17a95f 100644 --- a/intern/cycles/kernel/kernel_compat_cuda.h +++ b/intern/cycles/kernel/kernel_compat_cuda.h @@ -33,12 +33,13 @@ #include <cuda.h> #include <cuda_fp16.h> #include <float.h> +#include <stdint.h> /* Qualifier wrappers for different names on different devices */ #define ccl_device __device__ __inline__ # define ccl_device_forceinline __device__ __forceinline__ -#if (__KERNEL_CUDA_VERSION__ == 80) && (__CUDA_ARCH__ < 500) +#if __CUDA_ARCH__ < 500 # define ccl_device_inline __device__ __forceinline__ #else # define ccl_device_inline __device__ __inline__ @@ -60,8 +61,8 @@ /* Types */ -#include "util_half.h" -#include "util_types.h" +#include "util/util_half.h" +#include "util/util_types.h" /* Work item functions */ diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h index 6c963dea4f5..c2263ac0d49 100644 --- a/intern/cycles/kernel/kernel_compat_opencl.h +++ b/intern/cycles/kernel/kernel_compat_opencl.h @@ -143,8 +143,8 @@ /* define NULL */ #define NULL 0 -#include "util_half.h" -#include "util_types.h" +#include "util/util_half.h" +#include "util/util_types.h" #endif /* __KERNEL_COMPAT_OPENCL_H__ */ diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index cf14a159e47..9e7d51f23f5 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -156,7 +156,12 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, if(bsdf_eval_is_zero(eval)) return false; - if(kernel_data.integrator.light_inv_rr_threshold > 0.0f) { + if(kernel_data.integrator.light_inv_rr_threshold > 0.0f +#ifdef __SHADOW_TRICKS__ + && (state->flag & PATH_RAY_SHADOW_CATCHER) == 0 +#endif + ) + { float probability = max3(fabs(bsdf_eval_sum(eval))) * kernel_data.integrator.light_inv_rr_threshold; if(probability < 1.0f) { if(rand_terminate >= probability) { diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h index 1c3884890bf..c9c97ea977e 100644 --- a/intern/cycles/kernel/kernel_globals.h +++ b/intern/cycles/kernel/kernel_globals.h @@ -47,7 +47,7 @@ typedef struct KernelGlobals { # define KERNEL_TEX(type, ttype, name) ttype name; # define KERNEL_IMAGE_TEX(type, ttype, name) -# include "kernel_textures.h" +# include "kernel/kernel_textures.h" KernelData __data; @@ -97,7 +97,7 @@ typedef struct KernelGlobals { # define KERNEL_TEX(type, ttype, name) const __constant__ __device__ type *name; # endif # define KERNEL_IMAGE_TEX(type, ttype, name) ttype name; -# include "kernel_textures.h" +# include "kernel/kernel_textures.h" #endif /* __KERNEL_CUDA__ */ @@ -110,7 +110,7 @@ typedef ccl_addr_space struct KernelGlobals { # define KERNEL_TEX(type, ttype, name) \ ccl_global type *name; -# include "kernel_textures.h" +# include "kernel/kernel_textures.h" # ifdef __SPLIT_KERNEL__ SplitData split_data; diff --git a/intern/cycles/kernel/kernel_math.h b/intern/cycles/kernel/kernel_math.h index 9bee5603474..bd0e23b7705 100644 --- a/intern/cycles/kernel/kernel_math.h +++ b/intern/cycles/kernel/kernel_math.h @@ -17,11 +17,11 @@ #ifndef __KERNEL_MATH_H__ #define __KERNEL_MATH_H__ -#include "util_color.h" -#include "util_math.h" -#include "util_math_fast.h" -#include "util_texture.h" -#include "util_transform.h" +#include "util/util_color.h" +#include "util/util_math.h" +#include "util/util_math_fast.h" +#include "util/util_math_intersect.h" +#include "util/util_texture.h" +#include "util/util_transform.h" #endif /* __KERNEL_MATH_H__ */ - diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index ebf03ad9778..e7957042182 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -15,41 +15,41 @@ */ #ifdef __OSL__ -# include "osl_shader.h" +# include "kernel/osl/osl_shader.h" #endif -#include "kernel_random.h" -#include "kernel_projection.h" -#include "kernel_montecarlo.h" -#include "kernel_differential.h" -#include "kernel_camera.h" +#include "kernel/kernel_random.h" +#include "kernel/kernel_projection.h" +#include "kernel/kernel_montecarlo.h" +#include "kernel/kernel_differential.h" +#include "kernel/kernel_camera.h" -#include "geom/geom.h" -#include "bvh/bvh.h" +#include "kernel/geom/geom.h" +#include "kernel/bvh/bvh.h" -#include "kernel_accumulate.h" -#include "kernel_shader.h" -#include "kernel_light.h" -#include "kernel_passes.h" +#include "kernel/kernel_accumulate.h" +#include "kernel/kernel_shader.h" +#include "kernel/kernel_light.h" +#include "kernel/kernel_passes.h" #ifdef __SUBSURFACE__ -# include "kernel_subsurface.h" +# include "kernel/kernel_subsurface.h" #endif #ifdef __VOLUME__ -# include "kernel_volume.h" +# include "kernel/kernel_volume.h" #endif -#include "kernel_path_state.h" -#include "kernel_shadow.h" -#include "kernel_emission.h" -#include "kernel_path_common.h" -#include "kernel_path_surface.h" -#include "kernel_path_volume.h" -#include "kernel_path_subsurface.h" +#include "kernel/kernel_path_state.h" +#include "kernel/kernel_shadow.h" +#include "kernel/kernel_emission.h" +#include "kernel/kernel_path_common.h" +#include "kernel/kernel_path_surface.h" +#include "kernel/kernel_path_volume.h" +#include "kernel/kernel_path_subsurface.h" #ifdef __KERNEL_DEBUG__ -# include "kernel_debug.h" +# include "kernel/kernel_debug.h" #endif CCL_NAMESPACE_BEGIN @@ -92,6 +92,9 @@ ccl_device_noinline void kernel_path_ao(KernelGlobals *kg, if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) { path_radiance_accum_ao(L, throughput, ao_alpha, ao_bsdf, ao_shadow, state->bounce); } + else { + path_radiance_accum_total_ao(L, throughput, ao_bsdf); + } } } @@ -290,9 +293,9 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, /* sample background shader */ float3 L_background = indirect_background(kg, emission_sd, state, ray); path_radiance_accum_background(L, + state, throughput, - L_background, - state->bounce); + L_background); #endif /* __BACKGROUND__ */ break; @@ -312,6 +315,12 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, 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) { @@ -374,7 +383,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, /* do bssrdf scatter step if we picked a bssrdf closure */ if(sc) { - uint lcg_state = lcg_state_init(rng, state, 0x68bc21eb); + uint lcg_state = lcg_state_init(rng, state->rng_offset, state->sample, 0x68bc21eb); float bssrdf_u, bssrdf_v; path_state_rng_2D(kg, @@ -396,7 +405,8 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, #if defined(__EMISSION__) && defined(__BRANCHED_PATH__) if(kernel_data.integrator.use_direct_light) { - int all = kernel_data.integrator.sample_all_lights_indirect; + int all = (kernel_data.integrator.sample_all_lights_indirect) || + (state->flag & PATH_RAY_SHADOW_CATCHER); kernel_branched_path_surface_connect_light(kg, rng, sd, @@ -466,7 +476,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, } extmax = kernel_data.curve.maximum_width; - lcg_state = lcg_state_init(rng, &state, 0x51633e2d); + lcg_state = lcg_state_init(rng, state.rng_offset, state.sample, 0x51633e2d); } if(state.bounce > kernel_data.integrator.ao_bounces) { @@ -611,7 +621,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, #ifdef __BACKGROUND__ /* sample background shader */ float3 L_background = indirect_background(kg, &emission_sd, &state, &ray); - path_radiance_accum_background(&L, throughput, L_background, state.bounce); + path_radiance_accum_background(&L, &state, throughput, L_background); #endif /* __BACKGROUND__ */ break; @@ -625,6 +635,21 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, 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); + 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) || @@ -742,7 +767,16 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, } #endif /* __SUBSURFACE__ */ - float3 L_sum = path_radiance_clamp_and_sum(kg, &L); + float3 L_sum; +#ifdef __SHADOW_TRICKS__ + if(state.flag & PATH_RAY_SHADOW_CATCHER) { + L_sum = path_radiance_sum_shadowcatcher(kg, &L, &L_transparent); + } + else +#endif /* __SHADOW_TRICKS__ */ + { + L_sum = path_radiance_clamp_and_sum(kg, &L); + } kernel_write_light_passes(kg, buffer, &L, sample); diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index d58960cae4e..36fd6c95fe7 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -55,8 +55,12 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg, 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, emission_sd, state, &light_ray, &ao_shadow)) { path_radiance_accum_ao(L, throughput*num_samples_inv, ao_alpha, ao_bsdf, ao_shadow, state->bounce); + } + else { + path_radiance_accum_total_ao(L, throughput*num_samples_inv, ao_bsdf); + } } } } @@ -147,7 +151,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, continue; /* set up random number generator */ - uint lcg_state = lcg_state_init(rng, state, 0x68bc21eb); + uint lcg_state = lcg_state_init(rng, state->rng_offset, state->sample, 0x68bc21eb); int num_samples = kernel_data.integrator.subsurface_samples; float num_samples_inv = 1.0f/num_samples; RNG bssrdf_rng = cmj_hash(*rng, i); @@ -206,7 +210,8 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, #ifdef __EMISSION__ /* direct light */ if(kernel_data.integrator.use_direct_light) { - int all = kernel_data.integrator.sample_all_lights_direct; + int all = (kernel_data.integrator.sample_all_lights_direct) || + (state->flag & PATH_RAY_SHADOW_CATCHER); kernel_branched_path_surface_connect_light( kg, rng, @@ -280,7 +285,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in } extmax = kernel_data.curve.maximum_width; - lcg_state = lcg_state_init(rng, &state, 0x51633e2d); + lcg_state = lcg_state_init(rng, state.rng_offset, state.sample, 0x51633e2d); } bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax); @@ -461,7 +466,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #ifdef __BACKGROUND__ /* sample background shader */ float3 L_background = indirect_background(kg, &emission_sd, &state, &ray); - path_radiance_accum_background(&L, throughput, L_background, state.bounce); + path_radiance_accum_background(&L, &state, throughput, L_background); #endif /* __BACKGROUND__ */ break; @@ -472,6 +477,21 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in shader_eval_surface(kg, &sd, rng, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN); 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); + 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)) { @@ -544,7 +564,8 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #ifdef __EMISSION__ /* direct light */ if(kernel_data.integrator.use_direct_light) { - int all = kernel_data.integrator.sample_all_lights_direct; + int all = (kernel_data.integrator.sample_all_lights_direct) || + (state.flag & PATH_RAY_SHADOW_CATCHER); kernel_branched_path_surface_connect_light(kg, rng, &sd, &emission_sd, &hit_state, throughput, 1.0f, &L, all); } @@ -581,7 +602,16 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #endif /* __VOLUME__ */ } - float3 L_sum = path_radiance_clamp_and_sum(kg, &L); + float3 L_sum; +#ifdef __SHADOW_TRICKS__ + if(state.flag & PATH_RAY_SHADOW_CATCHER) { + L_sum = path_radiance_sum_shadowcatcher(kg, &L, &L_transparent); + } + else +#endif /* __SHADOW_TRICKS__ */ + { + L_sum = path_radiance_clamp_and_sum(kg, &L); + } kernel_write_light_passes(kg, buffer, &L, sample); diff --git a/intern/cycles/kernel/kernel_path_common.h b/intern/cycles/kernel/kernel_path_common.h index 7b903556bf9..82f83deb595 100644 --- a/intern/cycles/kernel/kernel_path_common.h +++ b/intern/cycles/kernel/kernel_path_common.h @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "util_hash.h" +#include "util/util_hash.h" CCL_NAMESPACE_BEGIN @@ -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, - ccl_addr_space RNG *rng, + RNG *rng, ccl_addr_space Ray *ray) { float filter_u; diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h index 661dc52fb31..c0cd2a63120 100644 --- a/intern/cycles/kernel/kernel_path_state.h +++ b/intern/cycles/kernel/kernel_path_state.h @@ -19,7 +19,7 @@ CCL_NAMESPACE_BEGIN ccl_device_inline void path_state_init(KernelGlobals *kg, ShaderData *stack_sd, ccl_addr_space PathState *state, - ccl_addr_space RNG *rng, + RNG *rng, int sample, ccl_addr_space Ray *ray) { @@ -54,6 +54,10 @@ ccl_device_inline void path_state_init(KernelGlobals *kg, 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) diff --git a/intern/cycles/kernel/kernel_path_subsurface.h b/intern/cycles/kernel/kernel_path_subsurface.h index d22ec992074..10b568ac3dd 100644 --- a/intern/cycles/kernel/kernel_path_subsurface.h +++ b/intern/cycles/kernel/kernel_path_subsurface.h @@ -28,7 +28,7 @@ bool kernel_path_subsurface_scatter( ShaderData *emission_sd, PathRadiance *L, ccl_addr_space PathState *state, - ccl_addr_space RNG *rng, + RNG *rng, ccl_addr_space Ray *ray, ccl_addr_space float3 *throughput, ccl_addr_space SubsurfaceIndirectRays *ss_indirect) @@ -47,7 +47,7 @@ bool kernel_path_subsurface_scatter( */ kernel_assert(!ss_indirect->tracing); - uint lcg_state = lcg_state_init_addrspace(rng, state, 0x68bc21eb); + uint lcg_state = lcg_state_init(rng, state->rng_offset, state->sample, 0x68bc21eb); SubsurfaceIntersection ss_isect; float bssrdf_u, bssrdf_v; diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h index efa23038089..076c82f3853 100644 --- a/intern/cycles/kernel/kernel_path_surface.h +++ b/intern/cycles/kernel/kernel_path_surface.h @@ -16,12 +16,18 @@ CCL_NAMESPACE_BEGIN -#if (defined(__BRANCHED_PATH__) || defined(__SUBSURFACE__)) && !defined(__SPLIT_KERNEL__) - +#if defined(__BRANCHED_PATH__) || defined(__SUBSURFACE__) || defined(__SHADOW_TRICKS__) /* 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, PathState *state, float3 throughput, - float num_samples_adjust, PathRadiance *L, int sample_all_lights) +ccl_device_noinline void kernel_branched_path_surface_connect_light( + KernelGlobals *kg, + RNG *rng, + ShaderData *sd, + ShaderData *emission_sd, + ccl_addr_space PathState *state, + float3 throughput, + float num_samples_adjust, + PathRadiance *L, + int sample_all_lights) { #ifdef __EMISSION__ /* sample illumination from lights to find path contribution */ @@ -66,6 +72,9 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal /* accumulate */ path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp); } + else { + path_radiance_accum_total_light(L, throughput*num_samples_inv, &L_light); + } } } } @@ -100,6 +109,9 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal /* accumulate */ path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp); } + else { + path_radiance_accum_total_light(L, throughput*num_samples_inv, &L_light); + } } } } @@ -123,6 +135,9 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal /* accumulate */ path_radiance_accum_light(L, throughput*num_samples_adjust, &L_light, shadow, num_samples_adjust, state->bounce, is_lamp); } + else { + path_radiance_accum_total_light(L, throughput*num_samples_adjust, &L_light); + } } } } @@ -130,9 +145,17 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal } /* 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, - float3 *throughput, PathState *state, PathRadiance *L, Ray *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, + Ray *ray) { /* sample BSDF */ float bsdf_pdf; @@ -189,7 +212,7 @@ ccl_device bool kernel_branched_path_surface_bounce(KernelGlobals *kg, RNG *rng, #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, ccl_addr_space RNG *rng, +ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, RNG *rng, ShaderData *sd, ShaderData *emission_sd, float3 throughput, ccl_addr_space PathState *state, PathRadiance *L) { @@ -197,6 +220,21 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_ if(!(kernel_data.integrator.use_direct_light && (sd->flag & SD_BSDF_HAS_EVAL))) return; +#ifdef __SHADOW_TRICKS__ + if(state->flag & PATH_RAY_SHADOW_CATCHER) { + kernel_branched_path_surface_connect_light(kg, + rng, + sd, + emission_sd, + state, + throughput, + 1.0f, + L, + 1); + return; + } +#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; @@ -221,6 +259,9 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_ /* accumulate */ path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state->bounce, is_lamp); } + else { + path_radiance_accum_total_light(L, throughput, &L_light); + } } } #endif @@ -228,7 +269,7 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_ /* path tracing: bounce off or through surface to with new direction stored in ray */ ccl_device bool kernel_path_surface_bounce(KernelGlobals *kg, - ccl_addr_space RNG *rng, + RNG *rng, ShaderData *sd, ccl_addr_space float3 *throughput, ccl_addr_space PathState *state, diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h index 28e1b5ba98e..371f2c1c7cb 100644 --- a/intern/cycles/kernel/kernel_path_volume.h +++ b/intern/cycles/kernel/kernel_path_volume.h @@ -20,7 +20,7 @@ CCL_NAMESPACE_BEGIN ccl_device_inline void kernel_path_volume_connect_light( KernelGlobals *kg, - ccl_addr_space RNG *rng, + RNG *rng, ShaderData *sd, ShaderData *emission_sd, float3 throughput, @@ -69,7 +69,7 @@ ccl_device #endif bool kernel_path_volume_bounce( KernelGlobals *kg, - ccl_addr_space RNG *rng, + RNG *rng, ShaderData *sd, ccl_addr_space float3 *throughput, ccl_addr_space PathState *state, @@ -117,10 +117,18 @@ bool kernel_path_volume_bounce( return true; } -#ifdef __BRANCHED_PATH__ -ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG *rng, - ShaderData *sd, ShaderData *emission_sd, float3 throughput, PathState *state, PathRadiance *L, - bool sample_all_lights, Ray *ray, const VolumeSegment *segment) +#ifndef __SPLIT_KERNEL__ +ccl_device void kernel_branched_path_volume_connect_light( + KernelGlobals *kg, + RNG *rng, + ShaderData *sd, + ShaderData *emission_sd, + float3 throughput, + ccl_addr_space PathState *state, + PathRadiance *L, + bool sample_all_lights, + Ray *ray, + const VolumeSegment *segment) { #ifdef __EMISSION__ if(!kernel_data.integrator.use_direct_light) @@ -270,7 +278,7 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG } #endif /* __EMISSION__ */ } -#endif /* __BRANCHED_PATH__ */ +#endif /* __SPLIT_KERNEL__ */ #endif /* __VOLUME_SCATTER__ */ diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h index ad3fa32a809..d4f0caff5de 100644 --- a/intern/cycles/kernel/kernel_random.h +++ b/intern/cycles/kernel/kernel_random.h @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "kernel_jitter.h" +#include "kernel/kernel_jitter.h" CCL_NAMESPACE_BEGIN @@ -98,7 +98,7 @@ ccl_device uint sobol_lookup(const uint m, const uint frame, const uint ex, cons return index; } -ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, ccl_addr_space RNG *rng, int sample, int num_samples, int dimension) +ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, RNG *rng, int sample, int num_samples, int dimension) { #ifdef __CMJ__ if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) { @@ -130,7 +130,7 @@ ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, ccl_addr_space RNG * #endif } -ccl_device_forceinline void path_rng_2D(KernelGlobals *kg, ccl_addr_space RNG *rng, int sample, int num_samples, int dimension, float *fx, float *fy) +ccl_device_forceinline void path_rng_2D(KernelGlobals *kg, RNG *rng, int sample, int num_samples, int dimension, float *fx, float *fy) { #ifdef __CMJ__ if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) { @@ -147,7 +147,7 @@ ccl_device_forceinline void path_rng_2D(KernelGlobals *kg, ccl_addr_space RNG *r } } -ccl_device_inline void path_rng_init(KernelGlobals *kg, ccl_global uint *rng_state, int sample, int num_samples, ccl_addr_space RNG *rng, int x, int y, float *fx, float *fy) +ccl_device_inline 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) { #ifdef __SOBOL_FULL_SCREEN__ uint px, py; @@ -259,12 +259,12 @@ ccl_device uint lcg_init(uint seed) * For branches in the path we must be careful not to reuse the same number * in a sequence and offset accordingly. */ -ccl_device_inline float path_state_rng_1D(KernelGlobals *kg, ccl_addr_space RNG *rng, const ccl_addr_space PathState *state, int dimension) +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->sample, state->num_samples, state->rng_offset + dimension); } -ccl_device_inline float path_state_rng_1D_for_decision(KernelGlobals *kg, ccl_addr_space RNG *rng, const ccl_addr_space PathState *state, int 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 @@ -277,29 +277,29 @@ ccl_device_inline float path_state_rng_1D_for_decision(KernelGlobals *kg, ccl_ad return path_rng_1D(kg, rng, state->sample, state->num_samples, rng_offset + dimension); } -ccl_device_inline void path_state_rng_2D(KernelGlobals *kg, ccl_addr_space RNG *rng, const ccl_addr_space PathState *state, int dimension, float *fx, float *fy) +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->sample, state->num_samples, state->rng_offset + dimension, fx, fy); } -ccl_device_inline float path_branched_rng_1D(KernelGlobals *kg, ccl_addr_space RNG *rng, const PathState *state, int branch, int num_branches, int dimension) +ccl_device_inline float path_branched_rng_1D(KernelGlobals *kg, RNG *rng, const ccl_addr_space PathState *state, int branch, int num_branches, int dimension) { return path_rng_1D(kg, rng, 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, ccl_addr_space RNG *rng, const PathState *state, int branch, int num_branches, int 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) { 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, ccl_addr_space RNG *rng, const PathState *state, int branch, int num_branches, int dimension, float *fx, float *fy) +ccl_device_inline void path_branched_rng_2D(KernelGlobals *kg, RNG *rng, const ccl_addr_space PathState *state, int branch, int num_branches, int dimension, float *fx, float *fy) { path_rng_2D(kg, rng, state->sample*num_branches + branch, state->num_samples*num_branches, state->rng_offset + dimension, fx, fy); } /* Utitility functions to get light termination value, since it might not be needed in many cases. */ -ccl_device_inline float path_state_rng_light_termination(KernelGlobals *kg, ccl_addr_space RNG *rng, const ccl_addr_space PathState *state) +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); @@ -307,7 +307,7 @@ ccl_device_inline float path_state_rng_light_termination(KernelGlobals *kg, ccl_ return 0.0f; } -ccl_device_inline float path_branched_rng_light_termination(KernelGlobals *kg, ccl_addr_space RNG *rng, const PathState *state, int branch, int num_branches) +ccl_device_inline float path_branched_rng_light_termination(KernelGlobals *kg, RNG *rng, 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); @@ -315,7 +315,7 @@ ccl_device_inline float path_branched_rng_light_termination(KernelGlobals *kg, c return 0.0f; } -ccl_device_inline void path_state_branch(PathState *state, int branch, int num_branches) +ccl_device_inline void path_state_branch(ccl_addr_space PathState *state, int branch, int num_branches) { /* path is splitting into a branch, adjust so that each branch * still gets a unique sample from the same sequence */ @@ -324,18 +324,9 @@ ccl_device_inline void path_state_branch(PathState *state, int branch, int num_b state->num_samples = state->num_samples*num_branches; } -ccl_device_inline uint lcg_state_init(RNG *rng, const PathState *state, uint scramble) -{ - return lcg_init(*rng + state->rng_offset + state->sample*scramble); -} - -/* TODO(sergey): For until we can use generic address space from OpenCL 2.0. */ - -ccl_device_inline uint lcg_state_init_addrspace(ccl_addr_space RNG *rng, - const ccl_addr_space PathState *state, - uint scramble) +ccl_device_inline uint lcg_state_init(RNG *rng, int rng_offset, int sample, uint scramble) { - return lcg_init(*rng + state->rng_offset + state->sample*scramble); + return lcg_init(*rng + rng_offset + sample*scramble); } ccl_device float lcg_step_float_addrspace(ccl_addr_space uint *rng) diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 93a92c63a40..8c0c5e90a3e 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -24,12 +24,12 @@ * */ -#include "closure/alloc.h" -#include "closure/bsdf_util.h" -#include "closure/bsdf.h" -#include "closure/emissive.h" +#include "kernel/closure/alloc.h" +#include "kernel/closure/bsdf_util.h" +#include "kernel/closure/bsdf.h" +#include "kernel/closure/emissive.h" -#include "svm/svm.h" +#include "kernel/svm/svm.h" CCL_NAMESPACE_BEGIN @@ -516,7 +516,7 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, ShaderData *sd float3 eval = bsdf_eval(kg, sd, sc, omega_in, &bsdf_pdf); if(bsdf_pdf != 0.0f) { - bsdf_eval_accum(result_eval, sc->type, eval*sc->weight); + bsdf_eval_accum(result_eval, sc->type, eval*sc->weight, 1.0f); sum_pdf += bsdf_pdf*sc->sample_weight; } @@ -544,7 +544,8 @@ ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg, float mis_weight = use_mis? power_heuristic(light_pdf, bsdf_pdf): 1.0f; bsdf_eval_accum(result_eval, sc->type, - eval * sc->weight * mis_weight); + eval * sc->weight, + mis_weight); } } } @@ -576,7 +577,7 @@ void shader_bsdf_eval(KernelGlobals *kg, _shader_bsdf_multi_eval(kg, sd, omega_in, &pdf, -1, eval, 0.0f, 0.0f); if(use_mis) { float weight = power_heuristic(light_pdf, pdf); - bsdf_eval_mul(eval, weight); + bsdf_eval_mis(eval, weight); } } } @@ -862,7 +863,7 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd) /* Surface Evaluation */ -ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_addr_space RNG *rng, +ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, RNG *rng, ccl_addr_space PathState *state, float randb, int path_flag, ShaderContext ctx) { sd->num_closure = 0; @@ -887,7 +888,7 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_addr_ } if(rng && (sd->flag & SD_BSDF_NEEDS_LCG)) { - sd->lcg_state = lcg_state_init_addrspace(rng, state, 0xb4bc3953); + sd->lcg_state = lcg_state_init(rng, state->rng_offset, state->sample, 0xb4bc3953); } } @@ -944,7 +945,7 @@ ccl_device_inline void _shader_volume_phase_multi_eval(const ShaderData *sd, con float3 eval = volume_phase_eval(sd, sc, omega_in, &phase_pdf); if(phase_pdf != 0.0f) { - bsdf_eval_accum(result_eval, sc->type, eval); + bsdf_eval_accum(result_eval, sc->type, eval, 1.0f); sum_pdf += phase_pdf*sc->sample_weight; } diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h index 4efc6c8118d..db6f839d9ed 100644 --- a/intern/cycles/kernel/kernel_shadow.h +++ b/intern/cycles/kernel/kernel_shadow.h @@ -128,6 +128,7 @@ ccl_device bool shadow_blocked_opaque(KernelGlobals *kg, ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg, ShaderData *shadow_sd, ccl_addr_space PathState *state, + const int skip_object, Ray *ray, Intersection *hits, uint max_hits, @@ -140,6 +141,7 @@ ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg, const bool blocked = scene_intersect_shadow_all(kg, ray, hits, + skip_object, max_hits, &num_hits); /* If no opaque surface found but we did find transparent hits, @@ -216,6 +218,7 @@ ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg, ccl_device bool shadow_blocked_transparent_all(KernelGlobals *kg, ShaderData *shadow_sd, ccl_addr_space PathState *state, + const int skip_object, Ray *ray, uint max_hits, float3 *shadow) @@ -250,6 +253,7 @@ ccl_device bool shadow_blocked_transparent_all(KernelGlobals *kg, return shadow_blocked_transparent_all_loop(kg, shadow_sd, state, + skip_object, ray, hits, max_hits, @@ -274,13 +278,14 @@ ccl_device bool shadow_blocked_transparent_stepped_loop( KernelGlobals *kg, ShaderData *shadow_sd, ccl_addr_space PathState *state, + const int skip_object, Ray *ray, Intersection *isect, const bool blocked, const bool is_transparent_isect, float3 *shadow) { - if(blocked && is_transparent_isect) { + if((blocked && is_transparent_isect) || skip_object != OBJECT_NONE) { float3 throughput = make_float3(1.0f, 1.0f, 1.0f); float3 Pend = ray->P + ray->D*ray->t; int bounce = state->transparent_bounce; @@ -306,6 +311,23 @@ ccl_device bool shadow_blocked_transparent_stepped_loop( { 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; } @@ -351,22 +373,31 @@ ccl_device bool shadow_blocked_transparent_stepped( KernelGlobals *kg, ShaderData *shadow_sd, ccl_addr_space PathState *state, + const int skip_object, Ray *ray, Intersection *isect, float3 *shadow) { - const bool blocked = scene_intersect(kg, - *ray, - PATH_RAY_SHADOW_OPAQUE, - isect, - NULL, - 0.0f, 0.0f); - const bool is_transparent_isect = blocked - ? shader_transparent_shadow(kg, isect) - : false; + 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; + } return shadow_blocked_transparent_stepped_loop(kg, shadow_sd, state, + skip_object, ray, isect, blocked, @@ -390,12 +421,21 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, if(ray->t == 0.0f) { return false; } +#ifdef __SHADOW_TRICKS__ + const int skip_object = state->catcher_object; +#else + const int skip_object = OBJECT_NONE; +#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) + if(!kernel_data.integrator.transparent_shadows && + skip_object == OBJECT_NONE) #endif { return shadow_blocked_opaque(kg, @@ -440,6 +480,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, return shadow_blocked_transparent_stepped_loop(kg, shadow_sd, state, + skip_object, ray, &isect, blocked, @@ -450,6 +491,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, return shadow_blocked_transparent_all(kg, shadow_sd, state, + skip_object, ray, max_hits, shadow); @@ -458,6 +500,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, return shadow_blocked_transparent_stepped(kg, shadow_sd, state, + skip_object, ray, &isect, shadow); diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index fe88ba4ff05..f75e9337bdb 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -223,7 +223,7 @@ ccl_device_inline int subsurface_scatter_multi_intersect( SubsurfaceIntersection *ss_isect, ShaderData *sd, ShaderClosure *sc, - uint *lcg_state, + RNG *lcg_state, float disk_u, float disk_v, bool all) @@ -293,7 +293,7 @@ ccl_device_inline int subsurface_scatter_multi_intersect( /* intersect with the same object. if multiple intersections are found it * will use at most BSSRDF_MAX_HITS hits, a random subset of all hits */ scene_intersect_subsurface(kg, - ray, + *ray, ss_isect, sd->object, lcg_state, @@ -448,7 +448,7 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, PathS /* intersect with the same object. if multiple intersections are * found it will randomly pick one of them */ SubsurfaceIntersection ss_isect; - scene_intersect_subsurface(kg, &ray, &ss_isect, sd->object, lcg_state, 1); + scene_intersect_subsurface(kg, ray, &ss_isect, sd->object, lcg_state, 1); /* evaluate bssrdf */ if(ss_isect.num_hits > 0) { diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 245832ae163..623f3728c69 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -17,9 +17,9 @@ #ifndef __KERNEL_TYPES_H__ #define __KERNEL_TYPES_H__ -#include "kernel_math.h" -#include "svm/svm_types.h" -#include "util_static_assert.h" +#include "kernel/kernel_math.h" +#include "kernel/svm/svm_types.h" +#include "util/util_static_assert.h" #ifndef __KERNEL_GPU__ # define __KERNEL_CPU__ @@ -56,7 +56,13 @@ CCL_NAMESPACE_BEGIN #define VOLUME_STACK_SIZE 16 -#define WORK_POOL_SIZE 64 +#define WORK_POOL_SIZE_GPU 64 +#define WORK_POOL_SIZE_CPU 1 +#ifdef __KERNEL_GPU__ +# define WORK_POOL_SIZE WORK_POOL_SIZE_GPU +#else +# define WORK_POOL_SIZE WORK_POOL_SIZE_CPU +#endif /* device capabilities */ #ifdef __KERNEL_CPU__ @@ -157,6 +163,7 @@ CCL_NAMESPACE_BEGIN #define __INTERSECTION_REFINE__ #define __CLAMP_SAMPLE__ #define __PATCH_EVAL__ +#define __SHADOW_TRICKS__ #ifdef __KERNEL_SHADING__ # define __SVM__ @@ -212,6 +219,9 @@ CCL_NAMESPACE_BEGIN #ifdef __NO_TRANSPARENT__ # undef __TRANSPARENT_SHADOWS__ #endif +#ifdef __NO_SHADOW_TRICKS__ +#undef __SHADOW_TRICKS__ +#endif /* Random Numbers */ @@ -316,6 +326,8 @@ enum PathRayFlag { PATH_RAY_MIS_SKIP = 4096, PATH_RAY_DIFFUSE_ANCESTOR = 8192, PATH_RAY_SINGLE_PASS_DONE = 16384, + PATH_RAY_SHADOW_CATCHER = 32768, + PATH_RAY_SHADOW_CATCHER_ONLY = 65536, }; /* Closure Label */ @@ -445,6 +457,20 @@ typedef ccl_addr_space struct PathRadiance { float4 shadow; float mist; #endif + +#ifdef __SHADOW_TRICKS__ + /* Total light reachable across the path, ignoring shadow blocked queries. */ + float3 path_total; + /* Total light reachable across the path with shadow blocked queries + * applied here. + * + * Dividing this figure by path_total will give estimate of shadow pass. + */ + float3 path_total_shaded; + + /* Color of the background on which shadow is alpha-overed. */ + float3 shadow_color; +#endif } PathRadiance; typedef struct BsdfEval { @@ -460,6 +486,9 @@ typedef struct BsdfEval { float3 subsurface; float3 scatter; #endif +#ifdef __SHADOW_TRICKS__ + float3 sum_no_mis; +#endif } BsdfEval; /* Shader Flag */ @@ -805,13 +834,16 @@ enum ShaderDataObjectFlag { SD_OBJECT_INTERSECTS_VOLUME = (1 << 5), /* Has position for motion vertices. */ SD_OBJECT_HAS_VERTEX_MOTION = (1 << 6), + /* object is used to catch shadows */ + SD_OBJECT_SHADOW_CATCHER = (1 << 7), SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK | SD_OBJECT_MOTION | SD_OBJECT_TRANSFORM_APPLIED | SD_OBJECT_NEGATIVE_SCALE_APPLIED | SD_OBJECT_HAS_VOLUME | - SD_OBJECT_INTERSECTS_VOLUME) + SD_OBJECT_INTERSECTS_VOLUME | + SD_OBJECT_SHADOW_CATCHER) }; typedef ccl_addr_space struct ShaderData { @@ -930,6 +962,10 @@ typedef struct PathState { RNG rng_congruential; VolumeStack volume_stack[VOLUME_STACK_SIZE]; #endif + +#ifdef __SHADOW_TRICKS__ + int catcher_object; +#endif } PathState; /* Subsurface */ diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index dcab138dc84..9c0878249d4 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -360,7 +360,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous( ShaderData *sd, PathRadiance *L, ccl_addr_space float3 *throughput, - ccl_addr_space RNG *rng, + RNG *rng, bool probalistic_scatter) { VolumeShaderCoefficients coeff; @@ -469,7 +469,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance( ShaderData *sd, PathRadiance *L, ccl_addr_space float3 *throughput, - ccl_addr_space RNG *rng) + RNG *rng) { float3 tp = *throughput; const float tp_eps = 1e-6f; /* todo: this is likely not the right value */ @@ -610,7 +610,7 @@ ccl_device_noinline VolumeIntegrateResult kernel_volume_integrate( Ray *ray, PathRadiance *L, ccl_addr_space float3 *throughput, - ccl_addr_space RNG *rng, + RNG *rng, bool heterogeneous) { shader_setup_from_volume(kg, sd, ray); diff --git a/intern/cycles/kernel/kernels/cpu/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp index 72dbbd9a416..16992c681e6 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp @@ -56,9 +56,9 @@ /* do nothing */ #endif -#include "kernel.h" +#include "kernel/kernel.h" #define KERNEL_ARCH cpu -#include "kernel_cpu_impl.h" +#include "kernel/kernels/cpu/kernel_cpu_impl.h" CCL_NAMESPACE_BEGIN @@ -90,7 +90,7 @@ void kernel_tex_copy(KernelGlobals *kg, kg->tname.width = width; \ } #define KERNEL_IMAGE_TEX(type, ttype, tname) -#include "kernel_textures.h" +#include "kernel/kernel_textures.h" else if(strstr(name, "__tex_image_float4")) { texture_image_float4 *tex = NULL; diff --git a/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp b/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp index 1350d9e5c2e..2600d977972 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp @@ -28,10 +28,10 @@ # define __KERNEL_AVX__ #endif -#include "util_optimization.h" +#include "util/util_optimization.h" #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX -# include "kernel.h" +# include "kernel/kernel.h" # define KERNEL_ARCH cpu_avx -# include "kernel_cpu_impl.h" +# include "kernel/kernels/cpu/kernel_cpu_impl.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX */ diff --git a/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp b/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp index 1a416e771ee..dba15d037ac 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp @@ -29,10 +29,10 @@ # define __KERNEL_AVX2__ #endif -#include "util_optimization.h" +#include "util/util_optimization.h" #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 -# include "kernel.h" +# include "kernel/kernel.h" # define KERNEL_ARCH cpu_avx2 -# include "kernel_cpu_impl.h" +# include "kernel/kernels/cpu/kernel_cpu_impl.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 */ diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h index e220d857384..148b2eef568 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h +++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h @@ -20,39 +20,39 @@ * simply includes this file without worry of copying actual implementation over. */ -#include "kernel_compat_cpu.h" +#include "kernel/kernel_compat_cpu.h" #ifndef __SPLIT_KERNEL__ -# include "kernel_math.h" -# include "kernel_types.h" +# include "kernel/kernel_math.h" +# include "kernel/kernel_types.h" -# include "split/kernel_split_data.h" -# include "kernel_globals.h" +# include "kernel/split/kernel_split_data.h" +# include "kernel/kernel_globals.h" -# include "kernel_cpu_image.h" -# include "kernel_film.h" -# include "kernel_path.h" -# include "kernel_path_branched.h" -# include "kernel_bake.h" +# include "kernel/kernels/cpu/kernel_cpu_image.h" +# include "kernel/kernel_film.h" +# include "kernel/kernel_path.h" +# include "kernel/kernel_path_branched.h" +# include "kernel/kernel_bake.h" #else -# include "split/kernel_split_common.h" - -# include "split/kernel_data_init.h" -# include "split/kernel_path_init.h" -# include "split/kernel_scene_intersect.h" -# include "split/kernel_lamp_emission.h" -# include "split/kernel_do_volume.h" -# include "split/kernel_queue_enqueue.h" -# include "split/kernel_indirect_background.h" -# include "split/kernel_shader_eval.h" -# include "split/kernel_holdout_emission_blurring_pathtermination_ao.h" -# include "split/kernel_subsurface_scatter.h" -# include "split/kernel_direct_lighting.h" -# include "split/kernel_shadow_blocked_ao.h" -# include "split/kernel_shadow_blocked_dl.h" -# include "split/kernel_next_iteration_setup.h" -# include "split/kernel_indirect_subsurface.h" -# include "split/kernel_buffer_update.h" +# include "kernel/split/kernel_split_common.h" + +# include "kernel/split/kernel_data_init.h" +# include "kernel/split/kernel_path_init.h" +# include "kernel/split/kernel_scene_intersect.h" +# include "kernel/split/kernel_lamp_emission.h" +# include "kernel/split/kernel_do_volume.h" +# include "kernel/split/kernel_queue_enqueue.h" +# include "kernel/split/kernel_indirect_background.h" +# include "kernel/split/kernel_shader_eval.h" +# include "kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h" +# include "kernel/split/kernel_subsurface_scatter.h" +# include "kernel/split/kernel_direct_lighting.h" +# include "kernel/split/kernel_shadow_blocked_ao.h" +# include "kernel/split/kernel_shadow_blocked_dl.h" +# include "kernel/split/kernel_next_iteration_setup.h" +# include "kernel/split/kernel_indirect_subsurface.h" +# include "kernel/split/kernel_buffer_update.h" #endif CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/kernels/cpu/kernel_split.cpp b/intern/cycles/kernel/kernels/cpu/kernel_split.cpp index 30519dae53e..ca750e5a00d 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_split.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel_split.cpp @@ -57,7 +57,7 @@ /* do nothing */ #endif -#include "kernel.h" +#include "kernel/kernel.h" #define KERNEL_ARCH cpu -#include "kernel_cpu_impl.h" +#include "kernel/kernels/cpu/kernel_cpu_impl.h" diff --git a/intern/cycles/kernel/kernels/cpu/kernel_split_avx.cpp b/intern/cycles/kernel/kernels/cpu/kernel_split_avx.cpp index 335ad24bdc5..27a746a0799 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_split_avx.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel_split_avx.cpp @@ -29,10 +29,10 @@ #define __SPLIT_KERNEL__ -#include "util_optimization.h" +#include "util/util_optimization.h" #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX -# include "kernel.h" +# include "kernel/kernel.h" # define KERNEL_ARCH cpu_avx -# include "kernel_cpu_impl.h" +# include "kernel/kernels/cpu/kernel_cpu_impl.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX */ diff --git a/intern/cycles/kernel/kernels/cpu/kernel_split_avx2.cpp b/intern/cycles/kernel/kernels/cpu/kernel_split_avx2.cpp index 765ba96aba3..364d279a189 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_split_avx2.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel_split_avx2.cpp @@ -31,10 +31,10 @@ #define __SPLIT_KERNEL__ -#include "util_optimization.h" +#include "util/util_optimization.h" #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 -# include "kernel.h" +# include "kernel/kernel.h" # define KERNEL_ARCH cpu_avx2 -# include "kernel_cpu_impl.h" +# include "kernel/kernels/cpu/kernel_cpu_impl.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 */ diff --git a/intern/cycles/kernel/kernels/cpu/kernel_split_sse2.cpp b/intern/cycles/kernel/kernels/cpu/kernel_split_sse2.cpp index af244c03929..0afb481296f 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_split_sse2.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel_split_sse2.cpp @@ -25,10 +25,10 @@ #define __SPLIT_KERNEL__ -#include "util_optimization.h" +#include "util/util_optimization.h" #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 -# include "kernel.h" +# include "kernel/kernel.h" # define KERNEL_ARCH cpu_sse2 -# include "kernel_cpu_impl.h" +# include "kernel/kernels/cpu/kernel_cpu_impl.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 */ diff --git a/intern/cycles/kernel/kernels/cpu/kernel_split_sse3.cpp b/intern/cycles/kernel/kernels/cpu/kernel_split_sse3.cpp index d1b579eeac5..13d00813591 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_split_sse3.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel_split_sse3.cpp @@ -27,10 +27,10 @@ #define __SPLIT_KERNEL__ -#include "util_optimization.h" +#include "util/util_optimization.h" #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3 -# include "kernel.h" +# include "kernel/kernel.h" # define KERNEL_ARCH cpu_sse3 -# include "kernel_cpu_impl.h" +# include "kernel/kernels/cpu/kernel_cpu_impl.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE3 */ diff --git a/intern/cycles/kernel/kernels/cpu/kernel_split_sse41.cpp b/intern/cycles/kernel/kernels/cpu/kernel_split_sse41.cpp index 83d62de5aa5..a4312071edc 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_split_sse41.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel_split_sse41.cpp @@ -28,10 +28,10 @@ #define __SPLIT_KERNEL__ -#include "util_optimization.h" +#include "util/util_optimization.h" #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 -# include "kernel.h" +# include "kernel/kernel.h" # define KERNEL_ARCH cpu_sse41 -# include "kernel_cpu_impl.h" +# include "kernel/kernels/cpu/kernel_cpu_impl.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 */ diff --git a/intern/cycles/kernel/kernels/cpu/kernel_sse2.cpp b/intern/cycles/kernel/kernels/cpu/kernel_sse2.cpp index a5f2d6e7294..1acfaa91ac9 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_sse2.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel_sse2.cpp @@ -23,10 +23,10 @@ # define __KERNEL_SSE2__ #endif -#include "util_optimization.h" +#include "util/util_optimization.h" #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 -# include "kernel.h" +# include "kernel/kernel.h" # define KERNEL_ARCH cpu_sse2 -# include "kernel_cpu_impl.h" +# include "kernel/kernels/cpu/kernel_cpu_impl.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 */ diff --git a/intern/cycles/kernel/kernels/cpu/kernel_sse3.cpp b/intern/cycles/kernel/kernels/cpu/kernel_sse3.cpp index 86f9ce991f8..f7b6a2e21fe 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_sse3.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel_sse3.cpp @@ -25,10 +25,10 @@ # define __KERNEL_SSSE3__ #endif -#include "util_optimization.h" +#include "util/util_optimization.h" #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3 -# include "kernel.h" +# include "kernel/kernel.h" # define KERNEL_ARCH cpu_sse3 -# include "kernel_cpu_impl.h" +# include "kernel/kernels/cpu/kernel_cpu_impl.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE3 */ diff --git a/intern/cycles/kernel/kernels/cpu/kernel_sse41.cpp b/intern/cycles/kernel/kernels/cpu/kernel_sse41.cpp index c174406047d..1900c6e3012 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_sse41.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel_sse41.cpp @@ -26,10 +26,10 @@ # define __KERNEL_SSE41__ #endif -#include "util_optimization.h" +#include "util/util_optimization.h" #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 -# include "kernel.h" +# include "kernel/kernel.h" # define KERNEL_ARCH cpu_sse41 -# include "kernel_cpu_impl.h" +# include "kernel/kernels/cpu//kernel_cpu_impl.h" #endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 */ diff --git a/intern/cycles/kernel/kernels/cuda/kernel.cu b/intern/cycles/kernel/kernels/cuda/kernel.cu index 52e541321e3..dc343cb387a 100644 --- a/intern/cycles/kernel/kernels/cuda/kernel.cu +++ b/intern/cycles/kernel/kernels/cuda/kernel.cu @@ -18,15 +18,15 @@ #ifdef __CUDA_ARCH__ -#include "../../kernel_compat_cuda.h" +#include "kernel/kernel_compat_cuda.h" #include "kernel_config.h" -#include "../../kernel_math.h" -#include "../../kernel_types.h" -#include "../../kernel_globals.h" -#include "../../kernel_film.h" -#include "../../kernel_path.h" -#include "../../kernel_path_branched.h" -#include "../../kernel_bake.h" +#include "kernel/kernel_math.h" +#include "kernel/kernel_types.h" +#include "kernel/kernel_globals.h" +#include "kernel/kernel_film.h" +#include "kernel/kernel_path.h" +#include "kernel/kernel_path_branched.h" +#include "kernel/kernel_bake.h" /* kernels */ extern "C" __global__ void diff --git a/intern/cycles/kernel/kernels/cuda/kernel_split.cu b/intern/cycles/kernel/kernels/cuda/kernel_split.cu index 4479a044921..a679eff8409 100644 --- a/intern/cycles/kernel/kernels/cuda/kernel_split.cu +++ b/intern/cycles/kernel/kernels/cuda/kernel_split.cu @@ -20,28 +20,28 @@ #define __SPLIT_KERNEL__ -#include "../../kernel_compat_cuda.h" +#include "kernel/kernel_compat_cuda.h" #include "kernel_config.h" -#include "../../split/kernel_split_common.h" -#include "../../split/kernel_data_init.h" -#include "../../split/kernel_path_init.h" -#include "../../split/kernel_scene_intersect.h" -#include "../../split/kernel_lamp_emission.h" -#include "../../split/kernel_do_volume.h" -#include "../../split/kernel_queue_enqueue.h" -#include "../../split/kernel_indirect_background.h" -#include "../../split/kernel_shader_eval.h" -#include "../../split/kernel_holdout_emission_blurring_pathtermination_ao.h" -#include "../../split/kernel_subsurface_scatter.h" -#include "../../split/kernel_direct_lighting.h" -#include "../../split/kernel_shadow_blocked_ao.h" -#include "../../split/kernel_shadow_blocked_dl.h" -#include "../../split/kernel_next_iteration_setup.h" -#include "../../split/kernel_indirect_subsurface.h" -#include "../../split/kernel_buffer_update.h" - -#include "../../kernel_film.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_data_init.h" +#include "kernel/split/kernel_path_init.h" +#include "kernel/split/kernel_scene_intersect.h" +#include "kernel/split/kernel_lamp_emission.h" +#include "kernel/split/kernel_do_volume.h" +#include "kernel/split/kernel_queue_enqueue.h" +#include "kernel/split/kernel_indirect_background.h" +#include "kernel/split/kernel_shader_eval.h" +#include "kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h" +#include "kernel/split/kernel_subsurface_scatter.h" +#include "kernel/split/kernel_direct_lighting.h" +#include "kernel/split/kernel_shadow_blocked_ao.h" +#include "kernel/split/kernel_shadow_blocked_dl.h" +#include "kernel/split/kernel_next_iteration_setup.h" +#include "kernel/split/kernel_indirect_subsurface.h" +#include "kernel/split/kernel_buffer_update.h" + +#include "kernel/kernel_film.h" /* kernels */ extern "C" __global__ void diff --git a/intern/cycles/kernel/kernels/opencl/kernel.cl b/intern/cycles/kernel/kernels/opencl/kernel.cl index 52406d2f548..078acc1631e 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel.cl @@ -16,34 +16,34 @@ /* OpenCL kernel entry points - unfinished */ -#include "../../kernel_compat_opencl.h" -#include "../../kernel_math.h" -#include "../../kernel_types.h" -#include "../../kernel_globals.h" -#include "../../kernel_image_opencl.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/kernel_math.h" +#include "kernel/kernel_types.h" +#include "kernel/kernel_globals.h" +#include "kernel/kernel_image_opencl.h" -#include "../../kernel_film.h" +#include "kernel/kernel_film.h" #if defined(__COMPILE_ONLY_MEGAKERNEL__) || !defined(__NO_BAKING__) -# include "../../kernel_path.h" -# include "../../kernel_path_branched.h" +# include "kernel/kernel_path.h" +# include "kernel/kernel_path_branched.h" #else /* __COMPILE_ONLY_MEGAKERNEL__ */ /* Include only actually used headers for the case * when path tracing kernels are not needed. */ -# include "../../kernel_random.h" -# include "../../kernel_differential.h" -# include "../../kernel_montecarlo.h" -# include "../../kernel_projection.h" -# include "../../geom/geom.h" -# include "../../bvh/bvh.h" - -# include "../../kernel_accumulate.h" -# include "../../kernel_camera.h" -# include "../../kernel_shader.h" +# include "kernel/kernel_random.h" +# include "kernel/kernel_differential.h" +# include "kernel/kernel_montecarlo.h" +# include "kernel/kernel_projection.h" +# include "kernel/geom/geom.h" +# include "kernel/bvh/bvh.h" + +# include "kernel/kernel_accumulate.h" +# include "kernel/kernel_camera.h" +# include "kernel/kernel_shader.h" #endif /* defined(__COMPILE_ONLY_MEGAKERNEL__) || !defined(__NO_BAKING__) */ -#include "../../kernel_bake.h" +#include "kernel/kernel_bake.h" #ifdef __COMPILE_ONLY_MEGAKERNEL__ @@ -54,7 +54,7 @@ __kernel void kernel_ocl_path_trace( #define KERNEL_TEX(type, ttype, name) \ ccl_global type *name, -#include "../../kernel_textures.h" +#include "kernel/kernel_textures.h" int sample, int sx, int sy, int sw, int sh, int offset, int stride) @@ -65,7 +65,7 @@ __kernel void kernel_ocl_path_trace( #define KERNEL_TEX(type, ttype, name) \ kg->name = name; -#include "../../kernel_textures.h" +#include "kernel/kernel_textures.h" int x = sx + ccl_global_id(0); int y = sy + ccl_global_id(1); @@ -84,7 +84,7 @@ __kernel void kernel_ocl_shader( #define KERNEL_TEX(type, ttype, name) \ ccl_global type *name, -#include "../../kernel_textures.h" +#include "kernel/kernel_textures.h" int type, int sx, int sw, int offset, int sample) { @@ -94,7 +94,7 @@ __kernel void kernel_ocl_shader( #define KERNEL_TEX(type, ttype, name) \ kg->name = name; -#include "../../kernel_textures.h" +#include "kernel/kernel_textures.h" int x = sx + ccl_global_id(0); @@ -116,7 +116,7 @@ __kernel void kernel_ocl_bake( #define KERNEL_TEX(type, ttype, name) \ ccl_global type *name, -#include "../../kernel_textures.h" +#include "kernel/kernel_textures.h" int type, int filter, int sx, int sw, int offset, int sample) { @@ -126,7 +126,7 @@ __kernel void kernel_ocl_bake( #define KERNEL_TEX(type, ttype, name) \ kg->name = name; -#include "../../kernel_textures.h" +#include "kernel/kernel_textures.h" int x = sx + ccl_global_id(0); @@ -146,7 +146,7 @@ __kernel void kernel_ocl_convert_to_byte( #define KERNEL_TEX(type, ttype, name) \ ccl_global type *name, -#include "../../kernel_textures.h" +#include "kernel/kernel_textures.h" float sample_scale, int sx, int sy, int sw, int sh, int offset, int stride) @@ -157,7 +157,7 @@ __kernel void kernel_ocl_convert_to_byte( #define KERNEL_TEX(type, ttype, name) \ kg->name = name; -#include "../../kernel_textures.h" +#include "kernel/kernel_textures.h" int x = sx + ccl_global_id(0); int y = sy + ccl_global_id(1); @@ -173,7 +173,7 @@ __kernel void kernel_ocl_convert_to_half_float( #define KERNEL_TEX(type, ttype, name) \ ccl_global type *name, -#include "../../kernel_textures.h" +#include "kernel/kernel_textures.h" float sample_scale, int sx, int sy, int sw, int sh, int offset, int stride) @@ -184,7 +184,7 @@ __kernel void kernel_ocl_convert_to_half_float( #define KERNEL_TEX(type, ttype, name) \ kg->name = name; -#include "../../kernel_textures.h" +#include "kernel/kernel_textures.h" int x = sx + ccl_global_id(0); int y = sy + ccl_global_id(1); diff --git a/intern/cycles/kernel/kernels/opencl/kernel_buffer_update.cl b/intern/cycles/kernel/kernels/opencl/kernel_buffer_update.cl index b61f1cda330..db65c91baf7 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_buffer_update.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_buffer_update.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_buffer_update.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_buffer_update.h" __kernel void kernel_ocl_path_trace_buffer_update( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl b/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl index 54d4a577e10..8b85d362f8a 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_data_init.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_data_init.h" __kernel void kernel_ocl_path_trace_data_init( ccl_global char *kg, @@ -28,7 +28,7 @@ __kernel void kernel_ocl_path_trace_data_init( #define KERNEL_TEX(type, ttype, name) \ ccl_global type *name, -#include "../../kernel_textures.h" +#include "kernel/kernel_textures.h" int start_sample, int end_sample, @@ -48,7 +48,7 @@ __kernel void kernel_ocl_path_trace_data_init( rng_state, #define KERNEL_TEX(type, ttype, name) name, -#include "../../kernel_textures.h" +#include "kernel/kernel_textures.h" start_sample, end_sample, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl b/intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl index 374be6cbd05..eb34f750881 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_direct_lighting.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_direct_lighting.h" __kernel void kernel_ocl_path_trace_direct_lighting( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_do_volume.cl b/intern/cycles/kernel/kernels/opencl/kernel_do_volume.cl index 08187b0e03e..83ef5f5f3f2 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_do_volume.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_do_volume.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_do_volume.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_do_volume.h" __kernel void kernel_ocl_path_trace_do_volume( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl b/intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl index 351687e2036..d071b39aa6f 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_holdout_emission_blurring_pathtermination_ao.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h" __kernel void kernel_ocl_path_trace_holdout_emission_blurring_pathtermination_ao( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_indirect_background.cl b/intern/cycles/kernel/kernels/opencl/kernel_indirect_background.cl index b18fba4c01f..8c213ff5cb2 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_indirect_background.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_indirect_background.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_indirect_background.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_indirect_background.h" __kernel void kernel_ocl_path_trace_indirect_background( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_indirect_subsurface.cl b/intern/cycles/kernel/kernels/opencl/kernel_indirect_subsurface.cl index ce2e96ad789..998ebc4c0c3 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_indirect_subsurface.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_indirect_subsurface.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_indirect_subsurface.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_indirect_subsurface.h" __kernel void kernel_ocl_path_trace_indirect_subsurface( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl b/intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl index 830e4e373ac..822d2287715 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_lamp_emission.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_lamp_emission.h" __kernel void kernel_ocl_path_trace_lamp_emission( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl b/intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl index fd49ed5def8..6d207253a40 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_next_iteration_setup.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_next_iteration_setup.h" __kernel void kernel_ocl_path_trace_next_iteration_setup( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_path_init.cl b/intern/cycles/kernel/kernels/opencl/kernel_path_init.cl index 8194f5d22ca..bd9aa9538c8 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_path_init.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_path_init.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_path_init.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_path_init.h" __kernel void kernel_ocl_path_trace_path_init( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_queue_enqueue.cl b/intern/cycles/kernel/kernels/opencl/kernel_queue_enqueue.cl index 6dd9d39c4e2..9be154e3d75 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_queue_enqueue.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_queue_enqueue.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_queue_enqueue.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_queue_enqueue.h" __kernel void kernel_ocl_path_trace_queue_enqueue( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl b/intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl index c675640c599..eb4fb4d153a 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_scene_intersect.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_scene_intersect.h" __kernel void kernel_ocl_path_trace_scene_intersect( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl b/intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl index 71ac2886978..6baee460986 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_shader_eval.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_shader_eval.h" __kernel void kernel_ocl_path_trace_shader_eval( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked_ao.cl b/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked_ao.cl index 37824097031..6a8ef81b32a 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked_ao.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked_ao.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_shadow_blocked_ao.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_shadow_blocked_ao.h" __kernel void kernel_ocl_path_trace_shadow_blocked_ao( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked_dl.cl b/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked_dl.cl index 4889f49d8dc..b255cc5ef8b 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked_dl.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked_dl.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_shadow_blocked_dl.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_shadow_blocked_dl.h" __kernel void kernel_ocl_path_trace_shadow_blocked_dl( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_split.cl b/intern/cycles/kernel/kernels/opencl/kernel_split.cl index 2d9e64824e7..732cda30115 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_split.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_split.cl @@ -14,22 +14,22 @@ * limitations under the License. */ -#include "kernel_state_buffer_size.cl" -#include "kernel_data_init.cl" -#include "kernel_path_init.cl" +#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" -#include "kernel_scene_intersect.cl" -#include "kernel_lamp_emission.cl" -#include "kernel_do_volume.cl" -#include "kernel_indirect_background.cl" -#include "kernel_queue_enqueue.cl" -#include "kernel_shader_eval.cl" -#include "kernel_holdout_emission_blurring_pathtermination_ao.cl" -#include "kernel_subsurface_scatter.cl" -#include "kernel_direct_lighting.cl" -#include "kernel_shadow_blocked_ao.cl" -#include "kernel_shadow_blocked_dl.cl" -#include "kernel_next_iteration_setup.cl" -#include "kernel_indirect_subsurface.cl" -#include "kernel_buffer_update.cl" +#include "kernel/kernels/opencl/kernel_scene_intersect.cl" +#include "kernel/kernels/opencl/kernel_lamp_emission.cl" +#include "kernel/kernels/opencl/kernel_do_volume.cl" +#include "kernel/kernels/opencl/kernel_indirect_background.cl" +#include "kernel/kernels/opencl/kernel_queue_enqueue.cl" +#include "kernel/kernels/opencl/kernel_shader_eval.cl" +#include "kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl" +#include "kernel/kernels/opencl/kernel_subsurface_scatter.cl" +#include "kernel/kernels/opencl/kernel_direct_lighting.cl" +#include "kernel/kernels/opencl/kernel_shadow_blocked_ao.cl" +#include "kernel/kernels/opencl/kernel_shadow_blocked_dl.cl" +#include "kernel/kernels/opencl/kernel_next_iteration_setup.cl" +#include "kernel/kernels/opencl/kernel_indirect_subsurface.cl" +#include "kernel/kernels/opencl/kernel_buffer_update.cl" diff --git a/intern/cycles/kernel/kernels/opencl/kernel_state_buffer_size.cl b/intern/cycles/kernel/kernels/opencl/kernel_state_buffer_size.cl index b23ff33786d..c10ecc426c6 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_state_buffer_size.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_state_buffer_size.cl @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" __kernel void kernel_ocl_path_trace_state_buffer_size( ccl_global char *kg, diff --git a/intern/cycles/kernel/kernels/opencl/kernel_subsurface_scatter.cl b/intern/cycles/kernel/kernels/opencl/kernel_subsurface_scatter.cl index 853bba2efc5..7a1838e485f 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_subsurface_scatter.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel_subsurface_scatter.cl @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "kernel_compat_opencl.h" -#include "split/kernel_split_common.h" -#include "split/kernel_subsurface_scatter.h" +#include "kernel/kernel_compat_opencl.h" +#include "kernel/split/kernel_split_common.h" +#include "kernel/split/kernel_subsurface_scatter.h" __kernel void kernel_ocl_path_trace_subsurface_scatter( ccl_global char *kg, diff --git a/intern/cycles/kernel/osl/CMakeLists.txt b/intern/cycles/kernel/osl/CMakeLists.txt index 98de40e5a8a..d2eb89e0e0a 100644 --- a/intern/cycles/kernel/osl/CMakeLists.txt +++ b/intern/cycles/kernel/osl/CMakeLists.txt @@ -1,12 +1,6 @@ set(INC - . - .. - ../svm - ../../graph - ../../render - ../../util - ../../device + ../.. ) set(INC_SYS diff --git a/intern/cycles/kernel/osl/background.cpp b/intern/cycles/kernel/osl/background.cpp index d835f9be45c..2e73e7a601e 100644 --- a/intern/cycles/kernel/osl/background.cpp +++ b/intern/cycles/kernel/osl/background.cpp @@ -34,10 +34,10 @@ #include <OSL/genclosure.h> -#include "osl_closures.h" +#include "kernel/osl/osl_closures.h" -#include "kernel_compat_cpu.h" -#include "closure/alloc.h" +#include "kernel/kernel_compat_cpu.h" +#include "kernel/closure/alloc.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp index bc26f42b559..ea18f2c8c86 100644 --- a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp +++ b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp @@ -34,13 +34,13 @@ #include <OSL/genclosure.h> -#include "kernel_compat_cpu.h" -#include "osl_closures.h" +#include "kernel/kernel_compat_cpu.h" +#include "kernel/osl/osl_closures.h" -#include "kernel_types.h" -#include "kernel_montecarlo.h" -#include "closure/alloc.h" -#include "closure/bsdf_diffuse_ramp.h" +#include "kernel/kernel_types.h" +#include "kernel/kernel_montecarlo.h" +#include "kernel/closure/alloc.h" +#include "kernel/closure/bsdf_diffuse_ramp.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp index 14c7644936e..a26671eb09e 100644 --- a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp +++ b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp @@ -34,12 +34,12 @@ #include <OSL/genclosure.h> -#include "kernel_compat_cpu.h" -#include "osl_closures.h" +#include "kernel/kernel_compat_cpu.h" +#include "kernel/osl/osl_closures.h" -#include "kernel_types.h" -#include "closure/alloc.h" -#include "closure/bsdf_phong_ramp.h" +#include "kernel/kernel_types.h" +#include "kernel/closure/alloc.h" +#include "kernel/closure/bsdf_phong_ramp.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/osl/emissive.cpp b/intern/cycles/kernel/osl/emissive.cpp index 3f13e08b302..8843a196dad 100644 --- a/intern/cycles/kernel/osl/emissive.cpp +++ b/intern/cycles/kernel/osl/emissive.cpp @@ -34,12 +34,12 @@ #include <OSL/genclosure.h> -#include "osl_closures.h" +#include "kernel/osl/osl_closures.h" -#include "kernel_compat_cpu.h" -#include "kernel_types.h" -#include "closure/alloc.h" -#include "closure/emissive.h" +#include "kernel/kernel_compat_cpu.h" +#include "kernel/kernel_types.h" +#include "kernel/closure/alloc.h" +#include "kernel/closure/emissive.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/osl/osl_bssrdf.cpp b/intern/cycles/kernel/osl/osl_bssrdf.cpp index d3a69d39597..95beea01d25 100644 --- a/intern/cycles/kernel/osl/osl_bssrdf.cpp +++ b/intern/cycles/kernel/osl/osl_bssrdf.cpp @@ -32,15 +32,15 @@ #include <OSL/genclosure.h> -#include "kernel_compat_cpu.h" -#include "osl_closures.h" +#include "kernel/kernel_compat_cpu.h" +#include "kernel/osl/osl_closures.h" -#include "kernel_types.h" -#include "kernel_montecarlo.h" +#include "kernel/kernel_types.h" +#include "kernel/kernel_montecarlo.h" -#include "closure/alloc.h" -#include "closure/bsdf_diffuse.h" -#include "closure/bssrdf.h" +#include "kernel/closure/alloc.h" +#include "kernel/closure/bsdf_diffuse.h" +#include "kernel/closure/bssrdf.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp index fe61587d179..f44714c2150 100644 --- a/intern/cycles/kernel/osl/osl_closures.cpp +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -33,34 +33,34 @@ #include <OSL/genclosure.h> #include <OSL/oslclosure.h> -#include "osl_closures.h" -#include "osl_shader.h" - -#include "util_debug.h" -#include "util_math.h" -#include "util_param.h" - -#include "kernel_types.h" -#include "kernel_compat_cpu.h" -#include "split/kernel_split_data_types.h" -#include "kernel_globals.h" -#include "kernel_montecarlo.h" -#include "kernel_random.h" - -#include "closure/alloc.h" -#include "closure/bsdf_util.h" -#include "closure/bsdf_ashikhmin_velvet.h" -#include "closure/bsdf_diffuse.h" -#include "closure/bsdf_microfacet.h" -#include "closure/bsdf_microfacet_multi.h" -#include "closure/bsdf_oren_nayar.h" -#include "closure/bsdf_reflection.h" -#include "closure/bsdf_refraction.h" -#include "closure/bsdf_transparent.h" -#include "closure/bsdf_ashikhmin_shirley.h" -#include "closure/bsdf_toon.h" -#include "closure/bsdf_hair.h" -#include "closure/volume.h" +#include "kernel/osl/osl_closures.h" +#include "kernel/osl/osl_shader.h" + +#include "util/util_debug.h" +#include "util/util_math.h" +#include "util/util_param.h" + +#include "kernel/kernel_types.h" +#include "kernel/kernel_compat_cpu.h" +#include "kernel/split/kernel_split_data_types.h" +#include "kernel/kernel_globals.h" +#include "kernel/kernel_montecarlo.h" +#include "kernel/kernel_random.h" + +#include "kernel/closure/alloc.h" +#include "kernel/closure/bsdf_util.h" +#include "kernel/closure/bsdf_ashikhmin_velvet.h" +#include "kernel/closure/bsdf_diffuse.h" +#include "kernel/closure/bsdf_microfacet.h" +#include "kernel/closure/bsdf_microfacet_multi.h" +#include "kernel/closure/bsdf_oren_nayar.h" +#include "kernel/closure/bsdf_reflection.h" +#include "kernel/closure/bsdf_refraction.h" +#include "kernel/closure/bsdf_transparent.h" +#include "kernel/closure/bsdf_ashikhmin_shirley.h" +#include "kernel/closure/bsdf_toon.h" +#include "kernel/closure/bsdf_hair.h" +#include "kernel/closure/volume.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h index cd7b33703ff..929cf00a7e6 100644 --- a/intern/cycles/kernel/osl/osl_closures.h +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -33,8 +33,8 @@ #ifndef __OSL_CLOSURES_H__ #define __OSL_CLOSURES_H__ -#include "util_types.h" -#include "kernel_types.h" +#include "util/util_types.h" +#include "kernel/kernel_types.h" #include <OSL/oslclosure.h> #include <OSL/oslexec.h> diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h index 65cb7ecc6b4..02c083a83f8 100644 --- a/intern/cycles/kernel/osl/osl_globals.h +++ b/intern/cycles/kernel/osl/osl_globals.h @@ -21,10 +21,10 @@ #include <OSL/oslexec.h> -#include "util_map.h" -#include "util_param.h" -#include "util_thread.h" -#include "util_vector.h" +#include "util/util_map.h" +#include "util/util_param.h" +#include "util/util_thread.h" +#include "util/util_vector.h" #ifndef WIN32 using std::isfinite; diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index b08353e82d1..b767c60c617 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -25,34 +25,34 @@ #include <string.h> -#include "mesh.h" -#include "object.h" -#include "scene.h" - -#include "osl_closures.h" -#include "osl_globals.h" -#include "osl_services.h" -#include "osl_shader.h" - -#include "util_foreach.h" -#include "util_logging.h" -#include "util_string.h" - -#include "kernel_compat_cpu.h" -#include "split/kernel_split_data_types.h" -#include "kernel_globals.h" -#include "kernel_random.h" -#include "kernel_projection.h" -#include "kernel_differential.h" -#include "kernel_montecarlo.h" -#include "kernel_camera.h" -#include "kernels/cpu/kernel_cpu_image.h" -#include "geom/geom.h" -#include "bvh/bvh.h" - -#include "kernel_projection.h" -#include "kernel_accumulate.h" -#include "kernel_shader.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" + +#include "kernel/osl/osl_closures.h" +#include "kernel/osl/osl_globals.h" +#include "kernel/osl/osl_services.h" +#include "kernel/osl/osl_shader.h" + +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_string.h" + +#include "kernel/kernel_compat_cpu.h" +#include "kernel/split/kernel_split_data_types.h" +#include "kernel/kernel_globals.h" +#include "kernel/kernel_random.h" +#include "kernel/kernel_projection.h" +#include "kernel/kernel_differential.h" +#include "kernel/kernel_montecarlo.h" +#include "kernel/kernel_camera.h" +#include "kernel/kernels/cpu/kernel_cpu_image.h" +#include "kernel/geom/geom.h" +#include "kernel/bvh/bvh.h" + +#include "kernel/kernel_projection.h" +#include "kernel/kernel_accumulate.h" +#include "kernel/kernel_shader.h" #ifdef WITH_PTEX # include <Ptexture.h> diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index c7e9f57b18a..13b19d86eca 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -16,22 +16,22 @@ #include <OSL/oslexec.h> -#include "kernel_compat_cpu.h" -#include "kernel_montecarlo.h" -#include "kernel_types.h" -#include "split/kernel_split_data_types.h" -#include "kernel_globals.h" +#include "kernel/kernel_compat_cpu.h" +#include "kernel/kernel_montecarlo.h" +#include "kernel/kernel_types.h" +#include "kernel/split/kernel_split_data_types.h" +#include "kernel/kernel_globals.h" -#include "geom/geom_object.h" +#include "kernel/geom/geom_object.h" -#include "osl_closures.h" -#include "osl_globals.h" -#include "osl_services.h" -#include "osl_shader.h" +#include "kernel/osl/osl_closures.h" +#include "kernel/osl/osl_globals.h" +#include "kernel/osl/osl_services.h" +#include "kernel/osl/osl_shader.h" -#include "util_foreach.h" +#include "util/util_foreach.h" -#include "attribute.h" +#include "render/attribute.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h index ad06dd6929d..32121e940b4 100644 --- a/intern/cycles/kernel/osl/osl_shader.h +++ b/intern/cycles/kernel/osl/osl_shader.h @@ -29,7 +29,7 @@ * This means no thread state must be passed along in the kernel itself. */ -#include "kernel_types.h" +#include "kernel/kernel_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/split/kernel_buffer_update.h b/intern/cycles/kernel/split/kernel_buffer_update.h index f36899b884a..859c221d976 100644 --- a/intern/cycles/kernel/split/kernel_buffer_update.h +++ b/intern/cycles/kernel/split/kernel_buffer_update.h @@ -87,7 +87,7 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, 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]; - ccl_global uint *rng = &kernel_split_state.rng[ray_index]; + RNG rng = kernel_split_state.rng[ray_index]; ccl_global float *buffer = kernel_split_params.buffer; unsigned int work_index; @@ -111,7 +111,16 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, 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)) { - float3 L_sum = path_radiance_clamp_and_sum(kg, L); + float3 L_sum; +#ifdef __SHADOW_TRICKS__ + if(state->flag & PATH_RAY_SHADOW_CATCHER) { + L_sum = path_radiance_sum_shadowcatcher(kg, L, L_transparent); + } + else +#endif /* __SHADOW_TRICKS__ */ + { + L_sum = path_radiance_clamp_and_sum(kg, L); + } kernel_write_light_passes(kg, buffer, L, sample); #ifdef __KERNEL_DEBUG__ kernel_write_debug_passes(kg, buffer, state, debug_data, sample); @@ -120,7 +129,7 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, /* accumulate result in output buffer */ kernel_write_pass_float4(buffer, sample, L_rad); - path_rng_end(kg, rng_state, *rng); + path_rng_end(kg, rng_state, rng); ASSIGN_RAY_STATE(ray_state, ray_index, RAY_TO_REGENERATE); } @@ -146,7 +155,7 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, buffer += (kernel_split_params.offset + pixel_x + pixel_y*stride) * kernel_data.film.pass_stride; /* Initialize random numbers and ray. */ - kernel_path_trace_setup(kg, rng_state, sample, pixel_x, pixel_y, rng, ray); + kernel_path_trace_setup(kg, rng_state, sample, pixel_x, pixel_y, &rng, ray); if(ray->t != 0.0f) { /* Initialize throughput, L_transparent, Ray, PathState; @@ -155,7 +164,7 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, *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, sample, ray); #ifdef __SUBSURFACE__ kernel_path_subsurface_init_indirect(&kernel_split_state.ss_rays[ray_index]); #endif @@ -170,12 +179,13 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, float4 L_rad = make_float4(0.0f, 0.0f, 0.0f, 0.0f); /* Accumulate result in output buffer. */ kernel_write_pass_float4(buffer, sample, L_rad); - path_rng_end(kg, rng_state, *rng); + 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 ed447049e48..9d3d01fff75 100644 --- a/intern/cycles/kernel/split/kernel_data_init.h +++ b/intern/cycles/kernel/split/kernel_data_init.h @@ -54,7 +54,7 @@ void KERNEL_FUNCTION_FULL_NAME(data_init)( #ifdef __KERNEL_OPENCL__ #define KERNEL_TEX(type, ttype, name) \ ccl_global type *name, -#include "../kernel_textures.h" +#include "kernel/kernel_textures.h" #endif int start_sample, @@ -98,7 +98,7 @@ void KERNEL_FUNCTION_FULL_NAME(data_init)( #ifdef __KERNEL_OPENCL__ #define KERNEL_TEX(type, ttype, name) \ kg->name = name; -#include "../kernel_textures.h" +#include "kernel/kernel_textures.h" #endif int thread_index = ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0); diff --git a/intern/cycles/kernel/split/kernel_direct_lighting.h b/intern/cycles/kernel/split/kernel_direct_lighting.h index 3d062cf0e2b..bdbf7387b95 100644 --- a/intern/cycles/kernel/split/kernel_direct_lighting.h +++ b/intern/cycles/kernel/split/kernel_direct_lighting.h @@ -79,15 +79,32 @@ ccl_device void kernel_direct_lighting(KernelGlobals *kg, /* direct lighting */ #ifdef __EMISSION__ - if((kernel_data.integrator.use_direct_light && - (sd->flag & SD_BSDF_HAS_EVAL))) - { + RNG rng = kernel_split_state.rng[ray_index]; + bool flag = (kernel_data.integrator.use_direct_light && + (sd->flag & SD_BSDF_HAS_EVAL)); +# ifdef __SHADOW_TRICKS__ + if(flag && state->flag & PATH_RAY_SHADOW_CATCHER) { + flag = false; + ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index]; + float3 throughput = kernel_split_state.throughput[ray_index]; + PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; + kernel_branched_path_surface_connect_light(kg, + &rng, + sd, + emission_sd, + state, + throughput, + 1.0f, + L, + 1); + } +# endif /* __SHADOW_TRICKS__ */ + if(flag) { /* Sample illumination from lights to find path contribution. */ - ccl_global RNG* rng = &kernel_split_state.rng[ray_index]; - float light_t = path_state_rng_1D(kg, rng, state, PRNG_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); - float terminate = path_state_rng_light_termination(kg, rng, state); + path_state_rng_2D(kg, &rng, state, PRNG_LIGHT_U, &light_u, &light_v); + float terminate = path_state_rng_light_termination(kg, &rng, state); LightSample ls; if(light_sample(kg, @@ -98,9 +115,9 @@ ccl_device void kernel_direct_lighting(KernelGlobals *kg, &ls)) { Ray light_ray; -#ifdef __OBJECT_MOTION__ +# ifdef __OBJECT_MOTION__ light_ray.time = sd->time; -#endif +# endif BsdfEval L_light; bool is_lamp; @@ -117,6 +134,7 @@ 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 b1df45d6bb2..47d3c280831 100644 --- a/intern/cycles/kernel/split/kernel_do_volume.h +++ b/intern/cycles/kernel/split/kernel_do_volume.h @@ -50,7 +50,7 @@ ccl_device void kernel_do_volume(KernelGlobals *kg) ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index]; ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; - ccl_global RNG *rng = &kernel_split_state.rng[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 *sd_input = &kernel_split_state.sd_DL_shadow[ray_index]; @@ -69,15 +69,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, &rng, heterogeneous); # ifdef __VOLUME_SCATTER__ if(result == VOLUME_PATH_SCATTERED) { /* direct lighting */ - kernel_path_volume_connect_light(kg, rng, sd, sd_input, *throughput, state, L); + kernel_path_volume_connect_light(kg, &rng, sd, sd_input, *throughput, state, L); /* indirect light bounce */ - if(kernel_path_volume_bounce(kg, rng, sd, throughput, state, L, ray)) + if(kernel_path_volume_bounce(kg, &rng, sd, throughput, state, L, ray)) ASSIGN_RAY_STATE(kernel_split_state.ray_state, ray_index, RAY_REGENERATED); else ASSIGN_RAY_STATE(kernel_split_state.ray_state, ray_index, RAY_UPDATE_BUFFER); @@ -85,6 +85,7 @@ ccl_device void kernel_do_volume(KernelGlobals *kg) # endif } } + kernel_split_state.rng[ray_index] = rng; } #endif 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 1834a791b91..9fc853a84bf 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 @@ -98,7 +98,7 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( unsigned int tile_y; unsigned int sample; - ccl_global RNG *rng = 0x0; + RNG rng = kernel_split_state.rng[ray_index]; ccl_global PathState *state = 0x0; float3 throughput; @@ -110,7 +110,6 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( throughput = kernel_split_state.throughput[ray_index]; state = &kernel_split_state.path_state[ray_index]; - rng = &kernel_split_state.rng[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; @@ -121,6 +120,23 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( 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); + 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) || @@ -194,7 +210,7 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( 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); + float terminate = path_state_rng_1D_for_decision(kg, &rng, state, PRNG_TERMINATE); if(terminate >= probability) { ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER); enqueue_flag = 1; @@ -214,7 +230,7 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( { /* 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, &rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); float ao_factor = kernel_data.background.ao_factor; float3 ao_N; @@ -243,6 +259,8 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( } } #endif /* __AO__ */ + kernel_split_state.rng[ray_index] = rng; + #ifndef __COMPUTE_DEVICE_GPU__ } diff --git a/intern/cycles/kernel/split/kernel_indirect_background.h b/intern/cycles/kernel/split/kernel_indirect_background.h index 100f5996f83..8192528622e 100644 --- a/intern/cycles/kernel/split/kernel_indirect_background.h +++ b/intern/cycles/kernel/split/kernel_indirect_background.h @@ -70,7 +70,7 @@ ccl_device void kernel_indirect_background(KernelGlobals *kg) #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, (*throughput), L_background, state->bounce); + path_radiance_accum_background(L, state, (*throughput), L_background); #endif ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER); } diff --git a/intern/cycles/kernel/split/kernel_next_iteration_setup.h b/intern/cycles/kernel/split/kernel_next_iteration_setup.h index 056fb1d8c08..1bebc16e25b 100644 --- a/intern/cycles/kernel/split/kernel_next_iteration_setup.h +++ b/intern/cycles/kernel/split/kernel_next_iteration_setup.h @@ -117,6 +117,9 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg, shadow, state->bounce); } + else { + path_radiance_accum_total_ao(L, _throughput, kernel_split_state.ao_bsdf[ray_index]); + } REMOVE_RAY_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_AO); } @@ -124,8 +127,8 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg, float3 shadow = kernel_split_state.light_ray[ray_index].P; // TODO(mai): investigate correctness here char update_path_radiance = (char)kernel_split_state.light_ray[ray_index].t; + BsdfEval L_light = kernel_split_state.bsdf_eval[ray_index]; if(update_path_radiance) { - BsdfEval L_light = kernel_split_state.bsdf_eval[ray_index]; path_radiance_accum_light(L, _throughput, &L_light, @@ -134,6 +137,9 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg, state->bounce, kernel_split_state.is_lamp[ray_index]); } + else { + path_radiance_accum_total_light(L, _throughput, &L_light); + } REMOVE_RAY_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_DL); } } @@ -141,15 +147,16 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg, if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) { ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index]; ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; - ccl_global RNG *rng = &kernel_split_state.rng[ray_index]; + RNG rng = kernel_split_state.rng[ray_index]; state = &kernel_split_state.path_state[ray_index]; L = &kernel_split_state.path_radiance[ray_index]; /* Compute direct lighting and next bounce. */ - if(!kernel_path_surface_bounce(kg, rng, &kernel_split_state.sd[ray_index], throughput, state, L, ray)) { + if(!kernel_path_surface_bounce(kg, &rng, &kernel_split_state.sd[ray_index], throughput, state, L, ray)) { ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER); enqueue_flag = 1; } + kernel_split_state.rng[ray_index] = rng; } #ifndef __COMPUTE_DEVICE_GPU__ diff --git a/intern/cycles/kernel/split/kernel_path_init.h b/intern/cycles/kernel/split/kernel_path_init.h index f879fca5009..a7ecde7c80d 100644 --- a/intern/cycles/kernel/split/kernel_path_init.h +++ b/intern/cycles/kernel/split/kernel_path_init.h @@ -60,12 +60,14 @@ ccl_device void kernel_path_init(KernelGlobals *kg) { 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 rng = kernel_split_state.rng[ray_index]; + /* Initialize random numbers and ray. */ kernel_path_trace_setup(kg, rng_state, my_sample, pixel_x, pixel_y, - &kernel_split_state.rng[ray_index], + &rng, &kernel_split_state.ray[ray_index]); if(kernel_split_state.ray[ray_index].t != 0.0f) { @@ -78,7 +80,7 @@ ccl_device void kernel_path_init(KernelGlobals *kg) { path_state_init(kg, &kernel_split_state.sd_DL_shadow[ray_index], &kernel_split_state.path_state[ray_index], - &kernel_split_state.rng[ray_index], + &rng, my_sample, &kernel_split_state.ray[ray_index]); #ifdef __SUBSURFACE__ @@ -97,6 +99,7 @@ ccl_device void kernel_path_init(KernelGlobals *kg) { path_rng_end(kg, rng_state, kernel_split_state.rng[ray_index]); 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 66f549f59b7..5dc94caec85 100644 --- a/intern/cycles/kernel/split/kernel_scene_intersect.h +++ b/intern/cycles/kernel/split/kernel_scene_intersect.h @@ -59,6 +59,11 @@ ccl_device void kernel_scene_intersect(KernelGlobals *kg) /* 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; @@ -72,12 +77,7 @@ ccl_device void kernel_scene_intersect(KernelGlobals *kg) } extmax = kernel_data.curve.maximum_width; - lcg_state = lcg_state_init(&rng, &state, 0x51633e2d); - } - - if(state.bounce > kernel_data.integrator.ao_bounces) { - visibility = PATH_RAY_SHADOW; - ray.t = kernel_data.background.ao_distance; + lcg_state = lcg_state_init(&rng, state.rng_offset, state.sample, 0x51633e2d); } bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax); diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h index b739f86338c..0f1696e34a0 100644 --- a/intern/cycles/kernel/split/kernel_shader_eval.h +++ b/intern/cycles/kernel/split/kernel_shader_eval.h @@ -54,7 +54,7 @@ ccl_device void kernel_shader_eval(KernelGlobals *kg, /* Continue on with shader evaluation. */ if((ray_index != QUEUE_EMPTY_SLOT) && IS_STATE(kernel_split_state.ray_state, ray_index, RAY_ACTIVE)) { Intersection isect = kernel_split_state.isect[ray_index]; - ccl_global uint *rng = &kernel_split_state.rng[ray_index]; + RNG rng = kernel_split_state.rng[ray_index]; ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; Ray ray = kernel_split_state.ray[ray_index]; @@ -62,8 +62,9 @@ ccl_device void kernel_shader_eval(KernelGlobals *kg, &kernel_split_state.sd[ray_index], &isect, &ray); - 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); + 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); + kernel_split_state.rng[ray_index] = rng; } } diff --git a/intern/cycles/kernel/split/kernel_split_common.h b/intern/cycles/kernel/split/kernel_split_common.h index 5c12fe426ac..4303ba0a905 100644 --- a/intern/cycles/kernel/split/kernel_split_common.h +++ b/intern/cycles/kernel/split/kernel_split_common.h @@ -17,61 +17,61 @@ #ifndef __KERNEL_SPLIT_H__ #define __KERNEL_SPLIT_H__ -#include "kernel_math.h" -#include "kernel_types.h" +#include "kernel/kernel_math.h" +#include "kernel/kernel_types.h" -#include "kernel_split_data.h" +#include "kernel/split/kernel_split_data.h" -#include "kernel_globals.h" +#include "kernel/kernel_globals.h" #ifdef __OSL__ -# include "osl_shader.h" +# include "kernel/osl/osl_shader.h" #endif #ifdef __KERNEL_OPENCL__ -# include "kernel_image_opencl.h" +# include "kernel/kernel_image_opencl.h" #endif #ifdef __KERNEL_CPU__ -# include "../kernels/cpu/kernel_cpu_image.h" +# include "kernel/kernels/cpu/kernel_cpu_image.h" #endif -#include "util_atomic.h" +#include "util/util_atomic.h" -#include "kernel_random.h" -#include "kernel_projection.h" -#include "kernel_montecarlo.h" -#include "kernel_differential.h" -#include "kernel_camera.h" +#include "kernel/kernel_random.h" +#include "kernel/kernel_projection.h" +#include "kernel/kernel_montecarlo.h" +#include "kernel/kernel_differential.h" +#include "kernel/kernel_camera.h" -#include "geom/geom.h" -#include "bvh/bvh.h" +#include "kernel/geom/geom.h" +#include "kernel/bvh/bvh.h" -#include "kernel_accumulate.h" -#include "kernel_shader.h" -#include "kernel_light.h" -#include "kernel_passes.h" +#include "kernel/kernel_accumulate.h" +#include "kernel/kernel_shader.h" +#include "kernel/kernel_light.h" +#include "kernel/kernel_passes.h" #ifdef __SUBSURFACE__ -# include "kernel_subsurface.h" +# include "kernel/kernel_subsurface.h" #endif #ifdef __VOLUME__ -# include "kernel_volume.h" +# include "kernel/kernel_volume.h" #endif -#include "kernel_path_state.h" -#include "kernel_shadow.h" -#include "kernel_emission.h" -#include "kernel_path_common.h" -#include "kernel_path_surface.h" -#include "kernel_path_volume.h" -#include "kernel_path_subsurface.h" +#include "kernel/kernel_path_state.h" +#include "kernel/kernel_shadow.h" +#include "kernel/kernel_emission.h" +#include "kernel/kernel_path_common.h" +#include "kernel/kernel_path_surface.h" +#include "kernel/kernel_path_volume.h" +#include "kernel/kernel_path_subsurface.h" #ifdef __KERNEL_DEBUG__ -# include "kernel_debug.h" +# include "kernel/kernel_debug.h" #endif -#include "kernel_queues.h" -#include "kernel_work_stealing.h" +#include "kernel/kernel_queues.h" +#include "kernel/kernel_work_stealing.h" #endif /* __KERNEL_SPLIT_H__ */ diff --git a/intern/cycles/kernel/split/kernel_split_data.h b/intern/cycles/kernel/split/kernel_split_data.h index d319514c190..17e6587883a 100644 --- a/intern/cycles/kernel/split/kernel_split_data.h +++ b/intern/cycles/kernel/split/kernel_split_data.h @@ -17,8 +17,8 @@ #ifndef __KERNEL_SPLIT_DATA_H__ #define __KERNEL_SPLIT_DATA_H__ -#include "kernel_split_data_types.h" -#include "kernel_globals.h" +#include "kernel/split/kernel_split_data_types.h" +#include "kernel/kernel_globals.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/split/kernel_subsurface_scatter.h b/intern/cycles/kernel/split/kernel_subsurface_scatter.h index 4eaa7f56332..0b4d50c70ee 100644 --- a/intern/cycles/kernel/split/kernel_subsurface_scatter.h +++ b/intern/cycles/kernel/split/kernel_subsurface_scatter.h @@ -55,7 +55,7 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg, ccl_global char *ray_state = kernel_split_state.ray_state; ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; - ccl_global RNG *rng = &kernel_split_state.rng[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]; @@ -69,7 +69,7 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg, emission_sd, L, state, - rng, + &rng, ray, throughput, ss_indirect)) { @@ -77,6 +77,7 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg, enqueue_flag = 1; } } + kernel_split_state.rng[ray_index] = rng; } #ifndef __COMPUTE_DEVICE_GPU__ diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 57ec9f94a3d..d748e76fa80 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -39,7 +39,7 @@ * mostly taken care of in the SVM compiler. */ -#include "svm_types.h" +#include "kernel/svm/svm_types.h" CCL_NAMESPACE_BEGIN @@ -139,49 +139,49 @@ CCL_NAMESPACE_END /* Nodes */ -#include "svm_noise.h" +#include "kernel/svm/svm_noise.h" #include "svm_texture.h" -#include "svm_color_util.h" -#include "svm_math_util.h" - -#include "svm_attribute.h" -#include "svm_gradient.h" -#include "svm_blackbody.h" -#include "svm_closure.h" -#include "svm_noisetex.h" -#include "svm_convert.h" -#include "svm_displace.h" -#include "svm_fresnel.h" -#include "svm_wireframe.h" -#include "svm_wavelength.h" -#include "svm_camera.h" -#include "svm_geometry.h" -#include "svm_hsv.h" -#include "svm_image.h" -#include "svm_gamma.h" -#include "svm_brightness.h" -#include "svm_invert.h" -#include "svm_light_path.h" -#include "svm_magic.h" -#include "svm_mapping.h" -#include "svm_normal.h" -#include "svm_wave.h" -#include "svm_math.h" -#include "svm_mix.h" -#include "svm_ramp.h" -#include "svm_sepcomb_hsv.h" -#include "svm_sepcomb_vector.h" -#include "svm_musgrave.h" -#include "svm_sky.h" -#include "svm_tex_coord.h" -#include "svm_value.h" -#include "svm_voronoi.h" -#include "svm_checker.h" -#include "svm_brick.h" -#include "svm_vector_transform.h" -#include "svm_voxel.h" -#include "svm_bump.h" +#include "kernel/svm/svm_color_util.h" +#include "kernel/svm/svm_math_util.h" + +#include "kernel/svm/svm_attribute.h" +#include "kernel/svm/svm_gradient.h" +#include "kernel/svm/svm_blackbody.h" +#include "kernel/svm/svm_closure.h" +#include "kernel/svm/svm_noisetex.h" +#include "kernel/svm/svm_convert.h" +#include "kernel/svm/svm_displace.h" +#include "kernel/svm/svm_fresnel.h" +#include "kernel/svm/svm_wireframe.h" +#include "kernel/svm/svm_wavelength.h" +#include "kernel/svm/svm_camera.h" +#include "kernel/svm/svm_geometry.h" +#include "kernel/svm/svm_hsv.h" +#include "kernel/svm/svm_image.h" +#include "kernel/svm/svm_gamma.h" +#include "kernel/svm/svm_brightness.h" +#include "kernel/svm/svm_invert.h" +#include "kernel/svm/svm_light_path.h" +#include "kernel/svm/svm_magic.h" +#include "kernel/svm/svm_mapping.h" +#include "kernel/svm/svm_normal.h" +#include "kernel/svm/svm_wave.h" +#include "kernel/svm/svm_math.h" +#include "kernel/svm/svm_mix.h" +#include "kernel/svm/svm_ramp.h" +#include "kernel/svm/svm_sepcomb_hsv.h" +#include "kernel/svm/svm_sepcomb_vector.h" +#include "kernel/svm/svm_musgrave.h" +#include "kernel/svm/svm_sky.h" +#include "kernel/svm/svm_tex_coord.h" +#include "kernel/svm/svm_value.h" +#include "kernel/svm/svm_voronoi.h" +#include "kernel/svm/svm_checker.h" +#include "kernel/svm/svm_brick.h" +#include "kernel/svm/svm_vector_transform.h" +#include "kernel/svm/svm_voxel.h" +#include "kernel/svm/svm_bump.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/svm/svm_voxel.h b/intern/cycles/kernel/svm/svm_voxel.h index a8b3604a8a7..9e826c8c23f 100644 --- a/intern/cycles/kernel/svm/svm_voxel.h +++ b/intern/cycles/kernel/svm/svm_voxel.h @@ -46,7 +46,7 @@ ccl_device void svm_node_tex_voxel(KernelGlobals *kg, # if defined(__KERNEL_CUDA__) # if __CUDA_ARCH__ >= 300 CUtexObject tex = kernel_tex_fetch(__bindless_mapping, id); - if(id < 2048) /* TODO(dingto): Make this a variable */ + if(id < TEX_START_HALF4_CUDA_KEPLER) r = kernel_tex_image_interp_3d_float4(tex, co.x, co.y, co.z); else { float f = kernel_tex_image_interp_3d_float(tex, co.x, co.y, co.z); diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index 8eaa9de3874..17ac66644e2 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -1,14 +1,6 @@ set(INC - . - ../device - ../graph - ../kernel - ../kernel/svm - ../kernel/osl - ../bvh - ../subd - ../util + .. ../../glew-mx ) diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index c0d429a583c..e157a385904 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ -#include "image.h" -#include "mesh.h" -#include "attribute.h" +#include "render/image.h" +#include "render/mesh.h" +#include "render/attribute.h" -#include "util_debug.h" -#include "util_foreach.h" -#include "util_transform.h" +#include "util/util_debug.h" +#include "util/util_foreach.h" +#include "util/util_transform.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index f4538c76369..a64eb6542d5 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -17,12 +17,12 @@ #ifndef __ATTRIBUTE_H__ #define __ATTRIBUTE_H__ -#include "kernel_types.h" +#include "kernel/kernel_types.h" -#include "util_list.h" -#include "util_param.h" -#include "util_types.h" -#include "util_vector.h" +#include "util/util_list.h" +#include "util/util_param.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp index 8d7d7b847fd..930debe1e33 100644 --- a/intern/cycles/render/background.cpp +++ b/intern/cycles/render/background.cpp @@ -14,17 +14,17 @@ * limitations under the License. */ -#include "background.h" -#include "device.h" -#include "integrator.h" -#include "graph.h" -#include "nodes.h" -#include "scene.h" -#include "shader.h" - -#include "util_foreach.h" -#include "util_math.h" -#include "util_types.h" +#include "render/background.h" +#include "device/device.h" +#include "render/integrator.h" +#include "render/graph.h" +#include "render/nodes.h" +#include "render/scene.h" +#include "render/shader.h" + +#include "util/util_foreach.h" +#include "util/util_math.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/background.h b/intern/cycles/render/background.h index deb22c9c2f2..db20b6ebf87 100644 --- a/intern/cycles/render/background.h +++ b/intern/cycles/render/background.h @@ -17,9 +17,9 @@ #ifndef __BACKGROUND_H__ #define __BACKGROUND_H__ -#include "node.h" +#include "graph/node.h" -#include "util_types.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp index c2f6293a50b..c0fcd517390 100644 --- a/intern/cycles/render/bake.cpp +++ b/intern/cycles/render/bake.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "bake.h" -#include "integrator.h" +#include "render/bake.h" +#include "render/integrator.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/bake.h b/intern/cycles/render/bake.h index aed9c5a8e75..ceb94cfb682 100644 --- a/intern/cycles/render/bake.h +++ b/intern/cycles/render/bake.h @@ -17,11 +17,11 @@ #ifndef __BAKE_H__ #define __BAKE_H__ -#include "device.h" -#include "scene.h" +#include "device/device.h" +#include "render/scene.h" -#include "util_progress.h" -#include "util_vector.h" +#include "util/util_progress.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index e3ef4bf13fb..fe2c2e78926 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -16,17 +16,17 @@ #include <stdlib.h> -#include "buffers.h" -#include "device.h" - -#include "util_debug.h" -#include "util_foreach.h" -#include "util_hash.h" -#include "util_image.h" -#include "util_math.h" -#include "util_opengl.h" -#include "util_time.h" -#include "util_types.h" +#include "render/buffers.h" +#include "device/device.h" + +#include "util/util_debug.h" +#include "util/util_foreach.h" +#include "util/util_hash.h" +#include "util/util_image.h" +#include "util/util_math.h" +#include "util/util_opengl.h" +#include "util/util_time.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h index c9c2a21079a..5c78971678a 100644 --- a/intern/cycles/render/buffers.h +++ b/intern/cycles/render/buffers.h @@ -17,16 +17,16 @@ #ifndef __BUFFERS_H__ #define __BUFFERS_H__ -#include "device_memory.h" +#include "device/device_memory.h" -#include "film.h" +#include "render/film.h" -#include "kernel_types.h" +#include "kernel/kernel_types.h" -#include "util_half.h" -#include "util_string.h" -#include "util_thread.h" -#include "util_types.h" +#include "util/util_half.h" +#include "util/util_string.h" +#include "util/util_thread.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index c8c51ec96d2..83ff8a10618 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -14,18 +14,18 @@ * limitations under the License. */ -#include "camera.h" -#include "mesh.h" -#include "object.h" -#include "scene.h" -#include "tables.h" - -#include "device.h" - -#include "util_foreach.h" -#include "util_function.h" -#include "util_math_cdf.h" -#include "util_vector.h" +#include "render/camera.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" +#include "render/tables.h" + +#include "device/device.h" + +#include "util/util_foreach.h" +#include "util/util_function.h" +#include "util/util_math_cdf.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index 655d74e42d8..dd6b831b347 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -17,13 +17,13 @@ #ifndef __CAMERA_H__ #define __CAMERA_H__ -#include "kernel_types.h" +#include "kernel/kernel_types.h" -#include "node.h" +#include "graph/node.h" -#include "util_boundbox.h" -#include "util_transform.h" -#include "util_types.h" +#include "util/util_boundbox.h" +#include "util/util_transform.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp index b7f25663bc3..2569d9eec27 100644 --- a/intern/cycles/render/constant_fold.cpp +++ b/intern/cycles/render/constant_fold.cpp @@ -14,11 +14,11 @@ * limitations under the License. */ -#include "constant_fold.h" -#include "graph.h" +#include "render/constant_fold.h" +#include "render/graph.h" -#include "util_foreach.h" -#include "util_logging.h" +#include "util/util_foreach.h" +#include "util/util_logging.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h index 7962698319f..33f93b8c0ab 100644 --- a/intern/cycles/render/constant_fold.h +++ b/intern/cycles/render/constant_fold.h @@ -17,8 +17,8 @@ #ifndef __CONSTANT_FOLD_H__ #define __CONSTANT_FOLD_H__ -#include "util_types.h" -#include "svm_types.h" +#include "util/util_types.h" +#include "kernel/svm/svm_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/curves.cpp b/intern/cycles/render/curves.cpp index f671eb19cae..4c085b928fb 100644 --- a/intern/cycles/render/curves.cpp +++ b/intern/cycles/render/curves.cpp @@ -14,16 +14,16 @@ * limitations under the License. */ -#include "device.h" -#include "curves.h" -#include "mesh.h" -#include "object.h" -#include "scene.h" - -#include "util_foreach.h" -#include "util_map.h" -#include "util_progress.h" -#include "util_vector.h" +#include "device/device.h" +#include "render/curves.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" + +#include "util/util_foreach.h" +#include "util/util_map.h" +#include "util/util_progress.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h index e41967eebf5..8834764bd63 100644 --- a/intern/cycles/render/curves.h +++ b/intern/cycles/render/curves.h @@ -17,8 +17,8 @@ #ifndef __CURVES_H__ #define __CURVES_H__ -#include "util_types.h" -#include "util_vector.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index 923252bb375..7809f4345f1 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -14,19 +14,19 @@ * limitations under the License. */ -#include "camera.h" -#include "device.h" -#include "film.h" -#include "integrator.h" -#include "mesh.h" -#include "scene.h" -#include "tables.h" - -#include "util_algorithm.h" -#include "util_debug.h" -#include "util_foreach.h" -#include "util_math.h" -#include "util_math_cdf.h" +#include "render/camera.h" +#include "device/device.h" +#include "render/film.h" +#include "render/integrator.h" +#include "render/mesh.h" +#include "render/scene.h" +#include "render/tables.h" + +#include "util/util_algorithm.h" +#include "util/util_debug.h" +#include "util/util_foreach.h" +#include "util/util_math.h" +#include "util/util_math_cdf.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/film.h b/intern/cycles/render/film.h index d917057ed91..83c941d5c57 100644 --- a/intern/cycles/render/film.h +++ b/intern/cycles/render/film.h @@ -17,12 +17,12 @@ #ifndef __FILM_H__ #define __FILM_H__ -#include "util_string.h" -#include "util_vector.h" +#include "util/util_string.h" +#include "util/util_vector.h" -#include "kernel_types.h" +#include "kernel/kernel_types.h" -#include "node.h" +#include "graph/node.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index f6c83fb5c7e..12fff8e5587 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -14,17 +14,18 @@ * limitations under the License. */ -#include "attribute.h" -#include "graph.h" -#include "nodes.h" -#include "shader.h" -#include "constant_fold.h" - -#include "util_algorithm.h" -#include "util_debug.h" -#include "util_foreach.h" -#include "util_queue.h" -#include "util_logging.h" +#include "render/attribute.h" +#include "render/graph.h" +#include "render/nodes.h" +#include "render/scene.h" +#include "render/shader.h" +#include "render/constant_fold.h" + +#include "util/util_algorithm.h" +#include "util/util_debug.h" +#include "util/util_foreach.h" +#include "util/util_queue.h" +#include "util/util_logging.h" CCL_NAMESPACE_BEGIN @@ -195,6 +196,7 @@ bool ShaderNode::equals(const ShaderNode& other) ShaderGraph::ShaderGraph() { finalized = false; + simplified = false; num_node_ids = 0; add(new OutputNode()); } @@ -207,6 +209,8 @@ ShaderGraph::~ShaderGraph() ShaderNode *ShaderGraph::add(ShaderNode *node) { assert(!finalized); + simplified = false; + node->id = num_node_ids++; nodes.push_back(node); return node; @@ -234,6 +238,8 @@ ShaderGraph *ShaderGraph::copy() foreach(ShaderNode *node, nodes) newgraph->add(nodes_copy[node]); + newgraph->simplified = simplified; + return newgraph; } @@ -273,6 +279,7 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to) void ShaderGraph::disconnect(ShaderOutput *from) { assert(!finalized); + simplified = false; foreach(ShaderInput *sock, from->links) { sock->link = NULL; @@ -285,6 +292,7 @@ void ShaderGraph::disconnect(ShaderInput *to) { assert(!finalized); assert(to->link); + simplified = false; ShaderOutput *from = to->link; @@ -294,6 +302,8 @@ void ShaderGraph::disconnect(ShaderInput *to) void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to) { + simplified = false; + /* Copy because disconnect modifies this list */ vector<ShaderInput*> outputs = from->links; @@ -310,9 +320,19 @@ void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to) } } +void ShaderGraph::simplify(Scene *scene) +{ + if(!simplified) { + default_inputs(scene->shader_manager->use_osl()); + clean(scene); + refine_bump_nodes(); + + simplified = true; + } +} + void ShaderGraph::finalize(Scene *scene, bool do_bump, - bool do_osl, bool do_simplify, bool bump_in_object_space) { @@ -322,9 +342,7 @@ void ShaderGraph::finalize(Scene *scene, * modified afterwards. */ if(!finalized) { - default_inputs(do_osl); - clean(scene); - refine_bump_nodes(); + simplify(scene); if(do_bump) bump_from_displacement(bump_in_object_space); diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index 06524d3fa13..09932695d1f 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -17,17 +17,17 @@ #ifndef __GRAPH_H__ #define __GRAPH_H__ -#include "node.h" -#include "node_type.h" +#include "graph/node.h" +#include "graph/node_type.h" -#include "kernel_types.h" +#include "kernel/kernel_types.h" -#include "util_list.h" -#include "util_map.h" -#include "util_param.h" -#include "util_set.h" -#include "util_types.h" -#include "util_vector.h" +#include "util/util_list.h" +#include "util/util_map.h" +#include "util/util_param.h" +#include "util/util_set.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN @@ -240,6 +240,7 @@ public: list<ShaderNode*> nodes; size_t num_node_ids; bool finalized; + bool simplified; ShaderGraph(); ~ShaderGraph(); @@ -255,9 +256,9 @@ public: void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to); void remove_proxy_nodes(); + void simplify(Scene *scene); void finalize(Scene *scene, bool do_bump = false, - bool do_osl = false, bool do_simplify = false, bool bump_in_object_space = false); diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 438b2347499..a8c4f446bea 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -14,15 +14,15 @@ * limitations under the License. */ -#include "device.h" -#include "image.h" -#include "scene.h" - -#include "util_foreach.h" -#include "util_logging.h" -#include "util_path.h" -#include "util_progress.h" -#include "util_texture.h" +#include "device/device.h" +#include "render/image.h" +#include "render/scene.h" + +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_path.h" +#include "util/util_progress.h" +#include "util/util_texture.h" #ifdef WITH_OSL #include <OSL/oslexec.h> diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 494c74f0cdd..996b5a5b65f 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -17,13 +17,13 @@ #ifndef __IMAGE_H__ #define __IMAGE_H__ -#include "device.h" -#include "device_memory.h" +#include "device/device.h" +#include "device/device_memory.h" -#include "util_image.h" -#include "util_string.h" -#include "util_thread.h" -#include "util_vector.h" +#include "util/util_image.h" +#include "util/util_string.h" +#include "util/util_thread.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index 1ab0f9874f2..a004bb5b856 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -14,16 +14,16 @@ * limitations under the License. */ -#include "device.h" -#include "integrator.h" -#include "film.h" -#include "light.h" -#include "scene.h" -#include "shader.h" -#include "sobol.h" - -#include "util_foreach.h" -#include "util_hash.h" +#include "device/device.h" +#include "render/integrator.h" +#include "render/film.h" +#include "render/light.h" +#include "render/scene.h" +#include "render/shader.h" +#include "render/sobol.h" + +#include "util/util_foreach.h" +#include "util/util_hash.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h index 3ce41d5a185..9501d7f8416 100644 --- a/intern/cycles/render/integrator.h +++ b/intern/cycles/render/integrator.h @@ -17,9 +17,9 @@ #ifndef __INTEGRATOR_H__ #define __INTEGRATOR_H__ -#include "kernel_types.h" +#include "kernel/kernel_types.h" -#include "node.h" +#include "graph/node.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index fc6790dc022..4886dcd563f 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -14,19 +14,19 @@ * limitations under the License. */ -#include "background.h" -#include "device.h" -#include "integrator.h" -#include "film.h" -#include "light.h" -#include "mesh.h" -#include "object.h" -#include "scene.h" -#include "shader.h" - -#include "util_foreach.h" -#include "util_progress.h" -#include "util_logging.h" +#include "render/background.h" +#include "device/device.h" +#include "render/integrator.h" +#include "render/film.h" +#include "render/light.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" +#include "render/shader.h" + +#include "util/util_foreach.h" +#include "util/util_progress.h" +#include "util/util_logging.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h index f56530b6490..7e9014eb823 100644 --- a/intern/cycles/render/light.h +++ b/intern/cycles/render/light.h @@ -17,12 +17,12 @@ #ifndef __LIGHT_H__ #define __LIGHT_H__ -#include "kernel_types.h" +#include "kernel/kernel_types.h" -#include "node.h" +#include "graph/node.h" -#include "util_types.h" -#include "util_vector.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index b7660297f3e..a4dc06c4345 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -14,29 +14,29 @@ * limitations under the License. */ -#include "bvh.h" -#include "bvh_build.h" - -#include "camera.h" -#include "curves.h" -#include "device.h" -#include "graph.h" -#include "shader.h" -#include "light.h" -#include "mesh.h" -#include "nodes.h" -#include "object.h" -#include "scene.h" - -#include "osl_globals.h" - -#include "subd_split.h" -#include "subd_patch_table.h" - -#include "util_foreach.h" -#include "util_logging.h" -#include "util_progress.h" -#include "util_set.h" +#include "bvh/bvh.h" +#include "bvh/bvh_build.h" + +#include "render/camera.h" +#include "render/curves.h" +#include "device/device.h" +#include "render/graph.h" +#include "render/shader.h" +#include "render/light.h" +#include "render/mesh.h" +#include "render/nodes.h" +#include "render/object.h" +#include "render/scene.h" + +#include "kernel/osl/osl_globals.h" + +#include "subd/subd_split.h" +#include "subd/subd_patch_table.h" + +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_progress.h" +#include "util/util_set.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index 1f8b880c161..043ce9d0ffc 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -17,17 +17,18 @@ #ifndef __MESH_H__ #define __MESH_H__ -#include "attribute.h" -#include "node.h" -#include "shader.h" - -#include "util_boundbox.h" -#include "util_list.h" -#include "util_map.h" -#include "util_param.h" -#include "util_transform.h" -#include "util_types.h" -#include "util_vector.h" +#include "graph/node.h" + +#include "render/attribute.h" +#include "render/shader.h" + +#include "util/util_boundbox.h" +#include "util/util_list.h" +#include "util/util_map.h" +#include "util/util_param.h" +#include "util/util_transform.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp index 4acb7911560..cf28bb16bb7 100644 --- a/intern/cycles/render/mesh_displace.cpp +++ b/intern/cycles/render/mesh_displace.cpp @@ -14,15 +14,15 @@ * limitations under the License. */ -#include "device.h" +#include "device/device.h" -#include "mesh.h" -#include "object.h" -#include "scene.h" -#include "shader.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" +#include "render/shader.h" -#include "util_foreach.h" -#include "util_progress.h" +#include "util/util_foreach.h" +#include "util/util_progress.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp index 57c76a9f1c8..585ed77b026 100644 --- a/intern/cycles/render/mesh_subdivision.cpp +++ b/intern/cycles/render/mesh_subdivision.cpp @@ -14,16 +14,16 @@ * limitations under the License. */ -#include "mesh.h" -#include "attribute.h" -#include "camera.h" +#include "render/mesh.h" +#include "render/attribute.h" +#include "render/camera.h" -#include "subd_split.h" -#include "subd_patch.h" -#include "subd_patch_table.h" +#include "subd/subd_split.h" +#include "subd/subd_patch.h" +#include "subd/subd_patch_table.h" -#include "util_foreach.h" -#include "util_algorithm.h" +#include "util/util_foreach.h" +#include "util/util_algorithm.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 7052c03ed94..1070e05a03b 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -14,21 +14,21 @@ * limitations under the License. */ -#include "image.h" -#include "integrator.h" -#include "nodes.h" -#include "scene.h" -#include "svm.h" -#include "svm_color_util.h" -#include "svm_ramp_util.h" -#include "svm_math_util.h" -#include "osl.h" -#include "constant_fold.h" - -#include "util_sky_model.h" -#include "util_foreach.h" -#include "util_logging.h" -#include "util_transform.h" +#include "render/image.h" +#include "render/integrator.h" +#include "render/nodes.h" +#include "render/scene.h" +#include "render/svm.h" +#include "kernel/svm/svm_color_util.h" +#include "kernel/svm/svm_ramp_util.h" +#include "kernel/svm/svm_math_util.h" +#include "render/osl.h" +#include "render/constant_fold.h" + +#include "util/util_sky_model.h" +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_transform.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index d159c801810..a755b653a5b 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -17,10 +17,10 @@ #ifndef __NODES_H__ #define __NODES_H__ -#include "graph.h" -#include "node.h" +#include "render/graph.h" +#include "graph/node.h" -#include "util_string.h" +#include "util/util_string.h" CCL_NAMESPACE_BEGIN @@ -324,7 +324,7 @@ private: class BsdfNode : public ShaderNode { public: explicit BsdfNode(const NodeType *node_type); - SHADER_NODE_BASE_CLASS(BsdfNode); + 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); @@ -641,7 +641,7 @@ public: class MixClosureWeightNode : public ShaderNode { public: - SHADER_NODE_CLASS(MixClosureWeightNode); + SHADER_NODE_CLASS(MixClosureWeightNode) float weight; float fac; @@ -887,7 +887,7 @@ public: class CurvesNode : public ShaderNode { public: explicit CurvesNode(const NodeType *node_type); - SHADER_NODE_BASE_CLASS(CurvesNode); + SHADER_NODE_BASE_CLASS(CurvesNode) virtual int get_group() { return NODE_GROUP_LEVEL_3; } diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 8342f376836..375abfeb27a 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -14,22 +14,22 @@ * limitations under the License. */ -#include "camera.h" -#include "device.h" -#include "light.h" -#include "mesh.h" -#include "curves.h" -#include "object.h" -#include "particles.h" -#include "scene.h" - -#include "util_foreach.h" -#include "util_logging.h" -#include "util_map.h" -#include "util_progress.h" -#include "util_vector.h" - -#include "subd_patch_table.h" +#include "render/camera.h" +#include "device/device.h" +#include "render/light.h" +#include "render/mesh.h" +#include "render/curves.h" +#include "render/object.h" +#include "render/particles.h" +#include "render/scene.h" + +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_map.h" +#include "util/util_progress.h" +#include "util/util_vector.h" + +#include "subd/subd_patch_table.h" CCL_NAMESPACE_BEGIN @@ -49,6 +49,8 @@ NODE_DEFINE(Object) SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f)); SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f)); + SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false); + return type; } @@ -597,6 +599,12 @@ void ObjectManager::device_update_flags(Device *device, else { object_flag[object_index] &= ~SD_OBJECT_HAS_VOLUME; } + if(object->is_shadow_catcher) { + object_flag[object_index] |= SD_OBJECT_SHADOW_CATCHER; + } + else { + object_flag[object_index] &= ~SD_OBJECT_SHADOW_CATCHER; + } if(bounds_valid) { foreach(Object *volume_object, volume_objects) { diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 3495849d149..12d7b2c81cf 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -17,14 +17,14 @@ #ifndef __OBJECT_H__ #define __OBJECT_H__ -#include "node.h" -#include "scene.h" +#include "graph/node.h" +#include "render/scene.h" -#include "util_boundbox.h" -#include "util_param.h" -#include "util_transform.h" -#include "util_thread.h" -#include "util_types.h" +#include "util/util_boundbox.h" +#include "util/util_param.h" +#include "util/util_transform.h" +#include "util/util_thread.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN @@ -53,6 +53,7 @@ public: bool use_motion; bool hide_on_missing_motion; bool use_holdout; + bool is_shadow_catcher; float3 dupli_generated; float2 dupli_uv; diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index 67b68e63cb2..6bff29d1c76 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -14,26 +14,26 @@ * limitations under the License. */ -#include "device.h" +#include "device/device.h" -#include "graph.h" -#include "light.h" -#include "osl.h" -#include "scene.h" -#include "shader.h" -#include "nodes.h" +#include "render/graph.h" +#include "render/light.h" +#include "render/osl.h" +#include "render/scene.h" +#include "render/shader.h" +#include "render/nodes.h" #ifdef WITH_OSL -#include "osl_globals.h" -#include "osl_services.h" -#include "osl_shader.h" +#include "kernel/osl/osl_globals.h" +#include "kernel/osl/osl_services.h" +#include "kernel/osl/osl_shader.h" -#include "util_foreach.h" -#include "util_logging.h" -#include "util_md5.h" -#include "util_path.h" -#include "util_progress.h" +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_md5.h" +#include "util/util_path.h" +#include "util/util_progress.h" #endif @@ -1096,12 +1096,10 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader) /* finalize */ shader->graph->finalize(scene, false, - true, shader->has_integrator_dependency); if(shader->graph_bump) { shader->graph_bump->finalize(scene, true, - true, shader->has_integrator_dependency, shader->displacement_method == DISPLACE_BOTH); } diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h index b131b672b8c..2be1126fdd3 100644 --- a/intern/cycles/render/osl.h +++ b/intern/cycles/render/osl.h @@ -17,13 +17,13 @@ #ifndef __OSL_H__ #define __OSL_H__ -#include "util_set.h" -#include "util_string.h" -#include "util_thread.h" +#include "util/util_set.h" +#include "util/util_string.h" +#include "util/util_thread.h" -#include "graph.h" -#include "nodes.h" -#include "shader.h" +#include "render/graph.h" +#include "render/nodes.h" +#include "render/shader.h" #ifdef WITH_OSL #include <OSL/oslcomp.h> diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp index 1a35d60fb4b..a51822a08be 100644 --- a/intern/cycles/render/particles.cpp +++ b/intern/cycles/render/particles.cpp @@ -14,15 +14,15 @@ * limitations under the License. */ -#include "device.h" -#include "particles.h" -#include "scene.h" - -#include "util_foreach.h" -#include "util_logging.h" -#include "util_map.h" -#include "util_progress.h" -#include "util_vector.h" +#include "device/device.h" +#include "render/particles.h" +#include "render/scene.h" + +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_map.h" +#include "util/util_progress.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/particles.h b/intern/cycles/render/particles.h index 2509e27b44b..66d46114b3e 100644 --- a/intern/cycles/render/particles.h +++ b/intern/cycles/render/particles.h @@ -17,8 +17,8 @@ #ifndef __PARTICLES_H__ #define __PARTICLES_H__ -#include "util_types.h" -#include "util_vector.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 68124e78cb5..4db20338744 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -16,27 +16,27 @@ #include <stdlib.h> -#include "background.h" -#include "bake.h" -#include "camera.h" -#include "curves.h" -#include "device.h" -#include "film.h" -#include "integrator.h" -#include "light.h" -#include "mesh.h" -#include "object.h" -#include "osl.h" -#include "particles.h" -#include "scene.h" -#include "shader.h" -#include "svm.h" -#include "tables.h" - -#include "util_foreach.h" -#include "util_guarded_allocator.h" -#include "util_logging.h" -#include "util_progress.h" +#include "render/background.h" +#include "render/bake.h" +#include "render/camera.h" +#include "render/curves.h" +#include "device/device.h" +#include "render/film.h" +#include "render/integrator.h" +#include "render/light.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/osl.h" +#include "render/particles.h" +#include "render/scene.h" +#include "render/shader.h" +#include "render/svm.h" +#include "render/tables.h" + +#include "util/util_foreach.h" +#include "util/util_guarded_allocator.h" +#include "util/util_logging.h" +#include "util/util_progress.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 9f398c444f4..2b5267642a2 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -17,18 +17,18 @@ #ifndef __SCENE_H__ #define __SCENE_H__ -#include "image.h" -#include "shader.h" - -#include "device_memory.h" - -#include "util_param.h" -#include "util_string.h" -#include "util_system.h" -#include "util_texture.h" -#include "util_thread.h" -#include "util_types.h" -#include "util_vector.h" +#include "render/image.h" +#include "render/shader.h" + +#include "device/device_memory.h" + +#include "util/util_param.h" +#include "util/util_string.h" +#include "util/util_system.h" +#include "util/util_texture.h" +#include "util/util_thread.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index e7050f9ef37..c9b5547b407 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -17,24 +17,24 @@ #include <string.h> #include <limits.h> -#include "buffers.h" -#include "camera.h" -#include "device.h" -#include "graph.h" -#include "integrator.h" -#include "mesh.h" -#include "object.h" -#include "scene.h" -#include "session.h" -#include "bake.h" - -#include "util_foreach.h" -#include "util_function.h" -#include "util_logging.h" -#include "util_math.h" -#include "util_opengl.h" -#include "util_task.h" -#include "util_time.h" +#include "render/buffers.h" +#include "render/camera.h" +#include "device/device.h" +#include "render/graph.h" +#include "render/integrator.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" +#include "render/session.h" +#include "render/bake.h" + +#include "util/util_foreach.h" +#include "util/util_function.h" +#include "util/util_logging.h" +#include "util/util_math.h" +#include "util/util_opengl.h" +#include "util/util_task.h" +#include "util/util_time.h" CCL_NAMESPACE_BEGIN @@ -637,6 +637,9 @@ DeviceRequestedFeatures Session::get_requested_device_features() requested_features.use_patch_evaluation = true; } #endif + if(object->is_shadow_catcher) { + requested_features.use_shadow_tricks = true; + } } BakeManager *bake_manager = scene->bake_manager; diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index c7ff1446171..a7e5f78a64d 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -17,15 +17,15 @@ #ifndef __SESSION_H__ #define __SESSION_H__ -#include "buffers.h" -#include "device.h" -#include "shader.h" -#include "tile.h" - -#include "util_progress.h" -#include "util_stats.h" -#include "util_thread.h" -#include "util_vector.h" +#include "render/buffers.h" +#include "device/device.h" +#include "render/shader.h" +#include "render/tile.h" + +#include "util/util_progress.h" +#include "util/util_stats.h" +#include "util/util_thread.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 335edcbe609..23eee1916bd 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -14,22 +14,22 @@ * limitations under the License. */ -#include "background.h" -#include "camera.h" -#include "device.h" -#include "graph.h" -#include "integrator.h" -#include "light.h" -#include "mesh.h" -#include "nodes.h" -#include "object.h" -#include "osl.h" -#include "scene.h" -#include "shader.h" -#include "svm.h" -#include "tables.h" - -#include "util_foreach.h" +#include "render/background.h" +#include "render/camera.h" +#include "device/device.h" +#include "render/graph.h" +#include "render/integrator.h" +#include "render/light.h" +#include "render/mesh.h" +#include "render/nodes.h" +#include "render/object.h" +#include "render/osl.h" +#include "render/scene.h" +#include "render/shader.h" +#include "render/svm.h" +#include "render/tables.h" + +#include "util/util_foreach.h" CCL_NAMESPACE_BEGIN @@ -332,6 +332,8 @@ ShaderManager *ShaderManager::create(Scene *scene, int shadingsystem) uint ShaderManager::get_attribute_id(ustring name) { + thread_scoped_spin_lock lock(attribute_lock_); + /* get a unique id for each name, for SVM attribute lookup */ AttributeIDMap::iterator it = unique_attribute_id.find(name); diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h index 490c3f1c95d..a8018231f1a 100644 --- a/intern/cycles/render/shader.h +++ b/intern/cycles/render/shader.h @@ -19,20 +19,20 @@ #ifdef WITH_OSL /* So no context pollution happens from indirectly included windows.h */ -# include "util_windows.h" +# include "util/util_windows.h" # include <OSL/oslexec.h> #endif -#include "attribute.h" -#include "kernel_types.h" +#include "render/attribute.h" +#include "kernel/kernel_types.h" -#include "node.h" +#include "graph/node.h" -#include "util_map.h" -#include "util_param.h" -#include "util_string.h" -#include "util_thread.h" -#include "util_types.h" +#include "util/util_map.h" +#include "util/util_param.h" +#include "util/util_string.h" +#include "util/util_thread.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN @@ -202,6 +202,8 @@ protected: void get_requested_graph_features(ShaderGraph *graph, DeviceRequestedFeatures *requested_features); + + thread_spin_lock attribute_lock_; }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/sobol.cpp b/intern/cycles/render/sobol.cpp index e3c2e802067..ce93dc8c5d5 100644 --- a/intern/cycles/render/sobol.cpp +++ b/intern/cycles/render/sobol.cpp @@ -46,10 +46,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "util_debug.h" -#include "util_types.h" +#include "util/util_debug.h" +#include "util/util_types.h" -#include "sobol.h" +#include "render/sobol.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/sobol.h b/intern/cycles/render/sobol.h index 574f148b9a2..9fbce4e14a5 100644 --- a/intern/cycles/render/sobol.h +++ b/intern/cycles/render/sobol.h @@ -17,7 +17,7 @@ #ifndef __SOBOL_H__ #define __SOBOL_H__ -#include "util_types.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 955b892f4c3..48287d872d4 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -14,20 +14,20 @@ * limitations under the License. */ -#include "device.h" -#include "graph.h" -#include "light.h" -#include "mesh.h" -#include "nodes.h" -#include "scene.h" -#include "shader.h" -#include "svm.h" - -#include "util_debug.h" -#include "util_logging.h" -#include "util_foreach.h" -#include "util_progress.h" -#include "util_task.h" +#include "device/device.h" +#include "render/graph.h" +#include "render/light.h" +#include "render/mesh.h" +#include "render/nodes.h" +#include "render/scene.h" +#include "render/shader.h" +#include "render/svm.h" + +#include "util/util_debug.h" +#include "util/util_logging.h" +#include "util/util_foreach.h" +#include "util/util_progress.h" +#include "util/util_task.h" CCL_NAMESPACE_BEGIN @@ -67,6 +67,7 @@ void SVMShaderManager::device_update_shader(Scene *scene, << "Shader name: " << shader->name << "\n" << summary.full_report(); + nodes_lock_.lock(); if(shader->use_mis && shader->has_surface_emission) { scene->light_manager->need_update = true; } @@ -74,7 +75,6 @@ void SVMShaderManager::device_update_shader(Scene *scene, /* The copy needs to be done inside the lock, if another thread resizes the array * while memcpy is running, it'll be copying into possibly invalid/freed ram. */ - nodes_lock_.lock(); size_t global_nodes_size = global_svm_nodes->size(); global_svm_nodes->resize(global_nodes_size + svm_nodes.size()); @@ -813,7 +813,6 @@ void SVMCompiler::compile(Scene *scene, scoped_timer timer((summary != NULL)? &summary->time_finalize: NULL); shader->graph->finalize(scene, false, - false, shader->has_integrator_dependency); } @@ -821,7 +820,6 @@ void SVMCompiler::compile(Scene *scene, scoped_timer timer((summary != NULL)? &summary->time_finalize_bump: NULL); shader->graph_bump->finalize(scene, true, - false, shader->has_integrator_dependency, shader->displacement_method == DISPLACE_BOTH); } diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h index a501b6bc8b1..abbd9e50610 100644 --- a/intern/cycles/render/svm.h +++ b/intern/cycles/render/svm.h @@ -17,13 +17,13 @@ #ifndef __SVM_H__ #define __SVM_H__ -#include "attribute.h" -#include "graph.h" -#include "shader.h" +#include "render/attribute.h" +#include "render/graph.h" +#include "render/shader.h" -#include "util_set.h" -#include "util_string.h" -#include "util_thread.h" +#include "util/util_set.h" +#include "util/util_string.h" +#include "util/util_thread.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/tables.cpp b/intern/cycles/render/tables.cpp index dfafd99961b..bf1ef12d602 100644 --- a/intern/cycles/render/tables.cpp +++ b/intern/cycles/render/tables.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "device.h" -#include "scene.h" -#include "tables.h" +#include "device/device.h" +#include "render/scene.h" +#include "render/tables.h" -#include "util_debug.h" -#include "util_logging.h" +#include "util/util_debug.h" +#include "util/util_logging.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/tables.h b/intern/cycles/render/tables.h index 1bb70b22762..bc261c2a74d 100644 --- a/intern/cycles/render/tables.h +++ b/intern/cycles/render/tables.h @@ -17,7 +17,7 @@ #ifndef __TABLES_H__ #define __TABLES_H__ -#include <util_list.h> +#include "util/util_list.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp index a493c3fa1cd..944e746ca2d 100644 --- a/intern/cycles/render/tile.cpp +++ b/intern/cycles/render/tile.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#include "tile.h" +#include "render/tile.h" -#include "util_algorithm.h" -#include "util_types.h" +#include "util/util_algorithm.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN @@ -131,7 +131,6 @@ void TileManager::reset(BufferParams& params_, int num_samples_) state.buffer = BufferParams(); state.sample = range_start_sample - 1; state.num_tiles = 0; - state.num_rendered_tiles = 0; state.num_samples = 0; state.resolution_divider = get_divider(params.width, params.height, start_resolution); state.tiles.clear(); @@ -343,7 +342,6 @@ bool TileManager::next_tile(Tile& tile, int device) tile = Tile(state.tiles[logical_device].front()); state.tiles[logical_device].pop_front(); - state.num_rendered_tiles++; return true; } diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h index 5d92ebac355..622b89f7670 100644 --- a/intern/cycles/render/tile.h +++ b/intern/cycles/render/tile.h @@ -19,8 +19,8 @@ #include <limits.h> -#include "buffers.h" -#include "util_list.h" +#include "render/buffers.h" +#include "util/util_list.h" CCL_NAMESPACE_BEGIN @@ -63,7 +63,6 @@ public: int num_samples; int resolution_divider; int num_tiles; - int num_rendered_tiles; /* Total samples over all pixels: Generally num_samples*num_pixels, * but can be higher due to the initial resolution division for previews. */ diff --git a/intern/cycles/subd/CMakeLists.txt b/intern/cycles/subd/CMakeLists.txt index dafb807bdf3..fe0c221ab0d 100644 --- a/intern/cycles/subd/CMakeLists.txt +++ b/intern/cycles/subd/CMakeLists.txt @@ -1,11 +1,6 @@ set(INC - . - ../graph - ../kernel - ../kernel/svm - ../render - ../util + .. ) set(INC_SYS diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp index a1bd349b167..fae815901ee 100644 --- a/intern/cycles/subd/subd_dice.cpp +++ b/intern/cycles/subd/subd_dice.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ -#include "camera.h" -#include "mesh.h" +#include "render/camera.h" +#include "render/mesh.h" -#include "subd_dice.h" -#include "subd_patch.h" +#include "subd/subd_dice.h" +#include "subd/subd_patch.h" -#include "util_debug.h" +#include "util/util_debug.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/subd/subd_dice.h b/intern/cycles/subd/subd_dice.h index 33d13a4ab3a..c0e32be18c4 100644 --- a/intern/cycles/subd/subd_dice.h +++ b/intern/cycles/subd/subd_dice.h @@ -22,8 +22,8 @@ * DiagSplit. For more algorithm details, see the DiagSplit paper or the * ARB_tessellation_shader OpenGL extension, Section 2.X.2. */ -#include "util_types.h" -#include "util_vector.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/subd/subd_patch.cpp b/intern/cycles/subd/subd_patch.cpp index d3319c5ccf5..fa2fe2bf113 100644 --- a/intern/cycles/subd/subd_patch.cpp +++ b/intern/cycles/subd/subd_patch.cpp @@ -16,12 +16,12 @@ /* Parts adapted from code in the public domain in NVidia Mesh Tools. */ -#include "mesh.h" +#include "render/mesh.h" -#include "subd_patch.h" +#include "subd/subd_patch.h" -#include "util_math.h" -#include "util_types.h" +#include "util/util_math.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/subd/subd_patch.h b/intern/cycles/subd/subd_patch.h index 360c1abf27b..1bb81588835 100644 --- a/intern/cycles/subd/subd_patch.h +++ b/intern/cycles/subd/subd_patch.h @@ -17,8 +17,8 @@ #ifndef __SUBD_PATCH_H__ #define __SUBD_PATCH_H__ -#include "util_boundbox.h" -#include "util_types.h" +#include "util/util_boundbox.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/subd/subd_patch_table.cpp b/intern/cycles/subd/subd_patch_table.cpp index d437b045c07..63bf673a90b 100644 --- a/intern/cycles/subd/subd_patch_table.cpp +++ b/intern/cycles/subd/subd_patch_table.cpp @@ -25,10 +25,10 @@ * */ -#include "subd_patch_table.h" -#include "kernel_types.h" +#include "subd/subd_patch_table.h" +#include "kernel/kernel_types.h" -#include "util_math.h" +#include "util/util_math.h" #ifdef WITH_OPENSUBDIV #include <opensubdiv/far/patchTable.h> diff --git a/intern/cycles/subd/subd_patch_table.h b/intern/cycles/subd/subd_patch_table.h index 3166a1691d8..907f2dd6c28 100644 --- a/intern/cycles/subd/subd_patch_table.h +++ b/intern/cycles/subd/subd_patch_table.h @@ -17,8 +17,8 @@ #ifndef __SUBD_PATCH_TABLE_H__ #define __SUBD_PATCH_TABLE_H__ -#include "util_types.h" -#include "util_vector.h" +#include "util/util_types.h" +#include "util/util_vector.h" #ifdef WITH_OPENSUBDIV #ifdef _MSC_VER diff --git a/intern/cycles/subd/subd_split.cpp b/intern/cycles/subd/subd_split.cpp index 3c91ad8ab0d..9dbfc1c4e2f 100644 --- a/intern/cycles/subd/subd_split.cpp +++ b/intern/cycles/subd/subd_split.cpp @@ -14,16 +14,16 @@ * limitations under the License. */ -#include "camera.h" -#include "mesh.h" +#include "render/camera.h" +#include "render/mesh.h" -#include "subd_dice.h" -#include "subd_patch.h" -#include "subd_split.h" +#include "subd/subd_dice.h" +#include "subd/subd_patch.h" +#include "subd/subd_split.h" -#include "util_debug.h" -#include "util_math.h" -#include "util_types.h" +#include "util/util_debug.h" +#include "util/util_math.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/subd/subd_split.h b/intern/cycles/subd/subd_split.h index a2f76dd2e03..f869cc6a48e 100644 --- a/intern/cycles/subd/subd_split.h +++ b/intern/cycles/subd/subd_split.h @@ -22,10 +22,10 @@ * evaluation at arbitrary points is required for this to work. See the paper * for more details. */ -#include "subd_dice.h" +#include "subd/subd_dice.h" -#include "util_types.h" -#include "util_vector.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index d8abf671bd6..a015fef8284 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -1,6 +1,6 @@ set(INC - . + .. ../../glew-mx ) @@ -52,6 +52,7 @@ set(SRC_HEADERS util_math.h util_math_cdf.h util_math_fast.h + util_math_intersect.h util_md5.h util_opengl.h util_optimization.h diff --git a/intern/cycles/util/util_aligned_malloc.cpp b/intern/cycles/util/util_aligned_malloc.cpp index 15d2eb3271b..cc7252dcc58 100644 --- a/intern/cycles/util/util_aligned_malloc.cpp +++ b/intern/cycles/util/util_aligned_malloc.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "util_aligned_malloc.h" -#include "util_guarded_allocator.h" +#include "util/util_aligned_malloc.h" +#include "util/util_guarded_allocator.h" #include <cassert> diff --git a/intern/cycles/util/util_aligned_malloc.h b/intern/cycles/util/util_aligned_malloc.h index ecc0f28c376..cf1e86ca916 100644 --- a/intern/cycles/util/util_aligned_malloc.h +++ b/intern/cycles/util/util_aligned_malloc.h @@ -17,7 +17,7 @@ #ifndef __UTIL_ALIGNED_MALLOC_H__ #define __UTIL_ALIGNED_MALLOC_H__ -#include "util_types.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h index dfe4977aef3..ed94ca20211 100644 --- a/intern/cycles/util/util_boundbox.h +++ b/intern/cycles/util/util_boundbox.h @@ -20,10 +20,10 @@ #include <math.h> #include <float.h> -#include "util_math.h" -#include "util_string.h" -#include "util_transform.h" -#include "util_types.h" +#include "util/util_math.h" +#include "util/util_string.h" +#include "util/util_transform.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_color.h b/intern/cycles/util/util_color.h index d3598f84b94..4d673dc34d8 100644 --- a/intern/cycles/util/util_color.h +++ b/intern/cycles/util/util_color.h @@ -17,11 +17,11 @@ #ifndef __UTIL_COLOR_H__ #define __UTIL_COLOR_H__ -#include "util_math.h" -#include "util_types.h" +#include "util/util_math.h" +#include "util/util_types.h" #ifdef __KERNEL_SSE2__ -#include "util_simd.h" +#include "util/util_simd.h" #endif CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_debug.cpp b/intern/cycles/util/util_debug.cpp index da3ccae45bf..9cfa57dd741 100644 --- a/intern/cycles/util/util_debug.cpp +++ b/intern/cycles/util/util_debug.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "util_debug.h" +#include "util/util_debug.h" #include <stdlib.h> -#include "util_logging.h" -#include "util_string.h" +#include "util/util_logging.h" +#include "util/util_string.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_debug.h b/intern/cycles/util/util_debug.h index 5aa0d911884..4505d584490 100644 --- a/intern/cycles/util/util_debug.h +++ b/intern/cycles/util/util_debug.h @@ -20,7 +20,7 @@ #include <cassert> #include <iostream> -#include "util_static_assert.h" +#include "util/util_static_assert.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_guarded_allocator.cpp b/intern/cycles/util/util_guarded_allocator.cpp index 615ac95f324..54fa6a80df5 100644 --- a/intern/cycles/util/util_guarded_allocator.cpp +++ b/intern/cycles/util/util_guarded_allocator.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "util_guarded_allocator.h" -#include "util_stats.h" +#include "util/util_guarded_allocator.h" +#include "util/util_stats.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_guarded_allocator.h b/intern/cycles/util/util_guarded_allocator.h index 78453d214be..5f9dcfb2481 100644 --- a/intern/cycles/util/util_guarded_allocator.h +++ b/intern/cycles/util/util_guarded_allocator.h @@ -20,8 +20,8 @@ #include <cstddef> #include <memory> -#include "util_debug.h" -#include "util_types.h" +#include "util/util_debug.h" +#include "util/util_types.h" #ifdef WITH_BLENDER_GUARDEDALLOC # include "../../guardedalloc/MEM_guardedalloc.h" diff --git a/intern/cycles/util/util_half.h b/intern/cycles/util/util_half.h index c1a47d58c55..612228dd1c1 100644 --- a/intern/cycles/util/util_half.h +++ b/intern/cycles/util/util_half.h @@ -17,11 +17,11 @@ #ifndef __UTIL_HALF_H__ #define __UTIL_HALF_H__ -#include "util_types.h" -#include "util_math.h" +#include "util/util_types.h" +#include "util/util_math.h" #ifdef __KERNEL_SSE2__ -#include "util_simd.h" +#include "util/util_simd.h" #endif CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_hash.h b/intern/cycles/util/util_hash.h index 98c3a681ff2..a30b7fe288e 100644 --- a/intern/cycles/util/util_hash.h +++ b/intern/cycles/util/util_hash.h @@ -17,7 +17,7 @@ #ifndef __UTIL_HASH_H__ #define __UTIL_HASH_H__ -#include "util_types.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_image.h b/intern/cycles/util/util_image.h index c8efc551d97..18876841b5b 100644 --- a/intern/cycles/util/util_image.h +++ b/intern/cycles/util/util_image.h @@ -21,7 +21,7 @@ #include <OpenImageIO/imageio.h> -#include "util_vector.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN @@ -42,4 +42,4 @@ CCL_NAMESPACE_END #endif /* __UTIL_IMAGE_H__ */ -#include "util_image_impl.h" +#include "util/util_image_impl.h" diff --git a/intern/cycles/util/util_image_impl.h b/intern/cycles/util/util_image_impl.h index 4daf1eaac22..a0f9c66f979 100644 --- a/intern/cycles/util/util_image_impl.h +++ b/intern/cycles/util/util_image_impl.h @@ -17,10 +17,10 @@ #ifndef __UTIL_IMAGE_IMPL_H__ #define __UTIL_IMAGE_IMPL_H__ -#include "util_algorithm.h" -#include "util_debug.h" -#include "util_half.h" -#include "util_image.h" +#include "util/util_algorithm.h" +#include "util/util_debug.h" +#include "util/util_half.h" +#include "util/util_image.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_logging.cpp b/intern/cycles/util/util_logging.cpp index 6824f1ff83c..a5a3bd34fff 100644 --- a/intern/cycles/util/util_logging.cpp +++ b/intern/cycles/util/util_logging.cpp @@ -14,9 +14,9 @@ * limitations under the License. */ -#include <util_logging.h> +#include "util/util_logging.h" -#include "util_math.h" +#include "util/util_math.h" #include <stdio.h> #ifdef _MSC_VER diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 27d4ae510c7..77781ed4574 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -35,7 +35,7 @@ #endif -#include "util_types.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN @@ -606,7 +606,7 @@ ccl_device_inline float3 normalize(const float3& a) { #if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) __m128 norm = _mm_sqrt_ps(_mm_dp_ps(a.m128, a.m128, 0x7F)); - return _mm_div_ps(a.m128, norm); + return float3(_mm_div_ps(a.m128, norm)); #else return a/len(a); #endif @@ -657,7 +657,7 @@ ccl_device_inline bool operator!=(const float3& a, const float3& b) ccl_device_inline float3 min(const float3& a, const float3& b) { #ifdef __KERNEL_SSE__ - return _mm_min_ps(a.m128, b.m128); + return float3(_mm_min_ps(a.m128, b.m128)); #else return make_float3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)); #endif @@ -666,7 +666,7 @@ ccl_device_inline float3 min(const float3& a, const float3& b) ccl_device_inline float3 max(const float3& a, const float3& b) { #ifdef __KERNEL_SSE__ - return _mm_max_ps(a.m128, b.m128); + return float3(_mm_max_ps(a.m128, b.m128)); #else return make_float3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)); #endif @@ -681,7 +681,7 @@ ccl_device_inline float3 fabs(const float3& a) { #ifdef __KERNEL_SSE__ __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); - return _mm_and_ps(a.m128, mask); + return float3(_mm_and_ps(a.m128, mask)); #else return make_float3(fabsf(a.x), fabsf(a.y), fabsf(a.z)); #endif @@ -714,8 +714,9 @@ ccl_device_inline void print_float3(const char *label, const float3& a) ccl_device_inline float3 rcp(const float3& a) { #ifdef __KERNEL_SSE__ - float4 r = _mm_rcp_ps(a.m128); - return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a)); + 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))); #else return make_float3(1.0f/a.x, 1.0f/a.y, 1.0f/a.z); #endif @@ -769,24 +770,29 @@ ccl_device_inline bool isequal_float3(const float3 a, const float3 b) #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& b) { - return _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(b), _MM_SHUFFLE(index_3, index_2, index_1, index_0))); + return float4(_mm_castsi128_ps( + _mm_shuffle_epi32(_mm_castps_si128(b), + _MM_SHUFFLE(index_3, index_2, index_1, index_0)))); } +#if defined(__KERNEL_SSE3__) template<> __forceinline const float4 shuffle<0, 0, 2, 2>(const float4& b) { - return _mm_moveldup_ps(b); + return float4(_mm_moveldup_ps(b)); } template<> __forceinline const float4 shuffle<1, 1, 3, 3>(const float4& b) { - return _mm_movehdup_ps(b); + return float4(_mm_movehdup_ps(b)); } +#endif template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4& b) { - return _mm_castpd_ps(_mm_movedup_pd(_mm_castps_pd(b))); + return float4(_mm_castpd_ps(_mm_movedup_pd(_mm_castps_pd(b)))); } #endif @@ -797,7 +803,7 @@ ccl_device_inline float4 operator-(const float4& a) { #ifdef __KERNEL_SSE__ __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000)); - return _mm_xor_ps(a.m128, mask); + return float4(_mm_xor_ps(a.m128, mask)); #else return make_float4(-a.x, -a.y, -a.z, -a.w); #endif @@ -806,7 +812,7 @@ ccl_device_inline float4 operator-(const float4& a) ccl_device_inline float4 operator*(const float4& a, const float4& b) { #ifdef __KERNEL_SSE__ - return _mm_mul_ps(a.m128, b.m128); + return float4(_mm_mul_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 @@ -829,8 +835,9 @@ ccl_device_inline float4 operator*(float f, const float4& a) ccl_device_inline float4 rcp(const float4& a) { #ifdef __KERNEL_SSE__ - float4 r = _mm_rcp_ps(a.m128); - return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a)); + 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))); #else return make_float4(1.0f/a.x, 1.0f/a.y, 1.0f/a.z, 1.0f/a.w); #endif @@ -854,7 +861,7 @@ ccl_device_inline float4 operator/(const float4& a, const float4& b) ccl_device_inline float4 operator+(const float4& a, const float4& b) { #ifdef __KERNEL_SSE__ - return _mm_add_ps(a.m128, b.m128); + return float4(_mm_add_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 @@ -863,7 +870,7 @@ ccl_device_inline float4 operator+(const float4& a, const float4& b) ccl_device_inline float4 operator-(const float4& a, const float4& b) { #ifdef __KERNEL_SSE__ - return _mm_sub_ps(a.m128, b.m128); + return float4(_mm_sub_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 @@ -887,7 +894,8 @@ ccl_device_inline float4 operator/=(float4& a, float f) ccl_device_inline int4 operator<(const float4& a, const float4& b) { #ifdef __KERNEL_SSE__ - return _mm_cvtps_epi32(_mm_cmplt_ps(a.m128, b.m128)); /* todo: avoid cvt */ + /* TODO(sergey): avoid cvt. */ + return int4(_mm_cvtps_epi32(_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 @@ -896,7 +904,8 @@ 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__ - return _mm_cvtps_epi32(_mm_cmpge_ps(a.m128, b.m128)); /* todo: avoid cvt */ + /* TODO(sergey): avoid cvt. */ + return int4(_mm_cvtps_epi32(_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 @@ -905,7 +914,8 @@ 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__ - return _mm_cvtps_epi32(_mm_cmple_ps(a.m128, b.m128)); /* todo: avoid cvt */ + /* TODO(sergey): avoid cvt. */ + return int4(_mm_cvtps_epi32(_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 @@ -941,8 +951,9 @@ ccl_device_inline bool is_zero(const float4& a) ccl_device_inline float reduce_add(const float4& a) { #ifdef __KERNEL_SSE__ - float4 h = shuffle<1,0,3,2>(a) + a; - return _mm_cvtss_f32(shuffle<2,3,0,1>(h) + h); /* todo: efficiency? */ + float4 h(shuffle<1,0,3,2>(a) + a); + /* TODO(sergey): Investigate efficiency. */ + return _mm_cvtss_f32(shuffle<2,3,0,1>(h) + h); #else return ((a.x + a.y) + (a.z + a.w)); #endif @@ -972,7 +983,7 @@ ccl_device_inline float4 safe_normalize(const float4& a) ccl_device_inline float4 min(const float4& a, const float4& b) { #ifdef __KERNEL_SSE__ - return _mm_min_ps(a.m128, b.m128); + return float4(_mm_min_ps(a.m128, b.m128)); #else return make_float4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w)); #endif @@ -981,7 +992,7 @@ ccl_device_inline float4 min(const float4& a, const float4& b) ccl_device_inline float4 max(const float4& a, const float4& b) { #ifdef __KERNEL_SSE__ - return _mm_max_ps(a.m128, b.m128); + return float4(_mm_max_ps(a.m128, b.m128)); #else return make_float4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w)); #endif @@ -994,7 +1005,9 @@ ccl_device_inline float4 max(const float4& a, const float4& b) ccl_device_inline float4 select(const int4& mask, const float4& a, const float4& b) { #ifdef __KERNEL_SSE__ - return _mm_or_ps(_mm_and_ps(_mm_cvtepi32_ps(mask), a), _mm_andnot_ps(_mm_cvtepi32_ps(mask), b)); /* todo: avoid cvt */ + /* 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))); #else return make_float4((mask.x)? a.x: b.x, (mask.y)? a.y: b.y, (mask.z)? a.z: b.z, (mask.w)? a.w: b.w); #endif @@ -1077,7 +1090,7 @@ ccl_device_inline int2 operator/(const int2 &a, const int2 &b) ccl_device_inline int3 min(int3 a, int3 b) { #if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__) - return _mm_min_epi32(a.m128, b.m128); + return int3(_mm_min_epi32(a.m128, b.m128)); #else return make_int3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)); #endif @@ -1086,7 +1099,7 @@ ccl_device_inline int3 min(int3 a, int3 b) ccl_device_inline int3 max(int3 a, int3 b) { #if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__) - return _mm_max_epi32(a.m128, b.m128); + return int3(_mm_max_epi32(a.m128, b.m128)); #else return make_int3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)); #endif @@ -1128,7 +1141,7 @@ ccl_device_inline void print_int3(const char *label, const int3& a) ccl_device_inline int4 operator+(const int4& a, const int4& b) { #ifdef __KERNEL_SSE__ - return _mm_add_epi32(a.m128, b.m128); + return int4(_mm_add_epi32(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 @@ -1142,7 +1155,7 @@ ccl_device_inline int4 operator+=(int4& a, const int4& b) ccl_device_inline int4 operator>>(const int4& a, int i) { #ifdef __KERNEL_SSE__ - return _mm_srai_epi32(a.m128, i); + return int4(_mm_srai_epi32(a.m128, i)); #else return make_int4(a.x >> i, a.y >> i, a.z >> i, a.w >> i); #endif @@ -1151,7 +1164,7 @@ ccl_device_inline int4 operator>>(const int4& a, int i) ccl_device_inline int4 min(int4 a, int4 b) { #if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__) - return _mm_min_epi32(a.m128, b.m128); + return int4(_mm_min_epi32(a.m128, b.m128)); #else return make_int4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w)); #endif @@ -1160,7 +1173,7 @@ ccl_device_inline int4 min(int4 a, int4 b) ccl_device_inline int4 max(int4 a, int4 b) { #if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__) - return _mm_max_epi32(a.m128, b.m128); + return int4(_mm_max_epi32(a.m128, b.m128)); #else return make_int4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w)); #endif @@ -1174,8 +1187,10 @@ ccl_device_inline int4 clamp(const int4& a, const int4& mn, const int4& mx) ccl_device_inline int4 select(const int4& mask, const int4& a, const int4& b) { #ifdef __KERNEL_SSE__ - __m128 m = _mm_cvtepi32_ps(mask); - return _mm_castps_si128(_mm_or_ps(_mm_and_ps(m, _mm_castsi128_ps(a)), _mm_andnot_ps(m, _mm_castsi128_ps(b)))); /* todo: avoid cvt */ + const __m128 m = _mm_cvtepi32_ps(mask); + /* TODO(sergey): avoid cvt. */ + return int4(_mm_castps_si128(_mm_or_ps(_mm_and_ps(m, _mm_castsi128_ps(a)), + _mm_andnot_ps(m, _mm_castsi128_ps(b))))); #else return make_int4((mask.x)? a.x: b.x, (mask.y)? a.y: b.y, (mask.z)? a.z: b.z, (mask.w)? a.w: b.w); #endif @@ -1241,19 +1256,6 @@ ccl_device_inline float __uint_as_float(uint i) return u.f; } -/* Versions of functions which are safe for fast math. */ -ccl_device_inline bool isnan_safe(float f) -{ - unsigned int x = __float_as_uint(f); - return (x << 1) > 0xff000000u; -} - -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)); -} /* Interpolation */ @@ -1271,6 +1273,20 @@ ccl_device_inline float triangle_area(const float3& v1, const float3& v2, const #endif +/* Versions of functions which are safe for fast math. */ +ccl_device_inline bool isnan_safe(float f) +{ + unsigned int x = __float_as_uint(f); + return (x << 1) > 0xff000000u; +} + +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); +} + /* Orthonormal vectors */ ccl_device_inline void make_orthonormals(const float3 N, float3 *a, float3 *b) @@ -1451,181 +1467,9 @@ ccl_device_inline float beta(float x, float y) #endif } -/* Ray Intersection */ - -ccl_device bool ray_sphere_intersect( - float3 ray_P, float3 ray_D, float ray_t, - float3 sphere_P, float sphere_radius, - float3 *isect_P, float *isect_t) -{ - float3 d = sphere_P - ray_P; - float radiussq = sphere_radius*sphere_radius; - float tsq = dot(d, d); - - if(tsq > radiussq) { /* ray origin outside sphere */ - float tp = dot(d, ray_D); - - if(tp < 0.0f) /* dir points away from sphere */ - return false; - - float dsq = tsq - tp*tp; /* pythagoras */ - - if(dsq > radiussq) /* closest point on ray outside sphere */ - return false; - - float t = tp - sqrtf(radiussq - dsq); /* pythagoras */ - - if(t < ray_t) { - *isect_t = t; - *isect_P = ray_P + ray_D*t; - return true; - } - } - - return false; -} - -ccl_device bool ray_aligned_disk_intersect( - float3 ray_P, float3 ray_D, float ray_t, - float3 disk_P, float disk_radius, - float3 *isect_P, float *isect_t) -{ - /* aligned disk normal */ - float disk_t; - float3 disk_N = normalize_len(ray_P - disk_P, &disk_t); - float div = dot(ray_D, disk_N); - - if(UNLIKELY(div == 0.0f)) - return false; - - /* compute t to intersection point */ - float t = -disk_t/div; - if(t < 0.0f || t > ray_t) - return false; - - /* test if within radius */ - float3 P = ray_P + ray_D*t; - if(len_squared(P - disk_P) > disk_radius*disk_radius) - return false; - - *isect_P = P; - *isect_t = t; - - return true; -} - -ccl_device bool ray_triangle_intersect( - float3 ray_P, float3 ray_D, float ray_t, - float3 v0, float3 v1, float3 v2, - float3 *isect_P, float *isect_t) +ccl_device_inline float xor_signmask(float x, int y) { - /* Calculate intersection */ - float3 e1 = v1 - v0; - float3 e2 = v2 - v0; - float3 s1 = cross(ray_D, e2); - - const float divisor = dot(s1, e1); - if(UNLIKELY(divisor == 0.0f)) - return false; - - const float invdivisor = 1.0f/divisor; - - /* compute first barycentric coordinate */ - const float3 d = ray_P - v0; - const float u = dot(d, s1)*invdivisor; - if(u < 0.0f) - return false; - - /* Compute second barycentric coordinate */ - const float3 s2 = cross(d, e1); - const float v = dot(ray_D, s2)*invdivisor; - if(v < 0.0f) - return false; - - const float b0 = 1.0f - u - v; - if(b0 < 0.0f) - return false; - - /* compute t to intersection point */ - const float t = dot(e2, s2)*invdivisor; - if(t < 0.0f || t > ray_t) - return false; - - *isect_t = t; - *isect_P = ray_P + ray_D*t; - - return true; -} - -ccl_device_inline bool ray_triangle_intersect_uv( - float3 ray_P, float3 ray_D, float ray_t, - float3 v0, float3 v1, float3 v2, - float *isect_u, float *isect_v, float *isect_t) -{ - /* Calculate intersection */ - float3 e1 = v1 - v0; - float3 e2 = v2 - v0; - float3 s1 = cross(ray_D, e2); - - const float divisor = dot(s1, e1); - if(UNLIKELY(divisor == 0.0f)) - return false; - - const float invdivisor = 1.0f/divisor; - - /* compute first barycentric coordinate */ - const float3 d = ray_P - v0; - const float u = dot(d, s1)*invdivisor; - if(u < 0.0f) - return false; - - /* Compute second barycentric coordinate */ - const float3 s2 = cross(d, e1); - const float v = dot(ray_D, s2)*invdivisor; - if(v < 0.0f) - return false; - - const float b0 = 1.0f - u - v; - if(b0 < 0.0f) - return false; - - /* compute t to intersection point */ - const float t = dot(e2, s2)*invdivisor; - if(t < 0.0f || t > ray_t) - return false; - - *isect_u = u; - *isect_v = v; - *isect_t = t; - - return true; -} - -ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_mint, float ray_maxt, - float3 quad_P, float3 quad_u, float3 quad_v, float3 quad_n, - float3 *isect_P, float *isect_t, float *isect_u, float *isect_v) -{ - float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n); - if(t < ray_mint || t > ray_maxt) - return false; - - float3 hit = ray_P + t*ray_D; - float3 inplane = hit - quad_P; - - float u = dot(inplane, quad_u) / dot(quad_u, quad_u) + 0.5f; - if(u < 0.0f || u > 1.0f) - return false; - - float v = dot(inplane, quad_v) / dot(quad_v, quad_v) + 0.5f; - if(v < 0.0f || v > 1.0f) - return false; - - if(isect_P) *isect_P = hit; - if(isect_t) *isect_t = t; - if(isect_u) *isect_u = u; - if(isect_v) *isect_v = v; - - return true; + return __int_as_float(__float_as_int(x) ^ y); } /* projections */ @@ -1662,32 +1506,6 @@ ccl_device_inline float2 map_to_sphere(const float3 co) return make_float2(u, v); } -ccl_device_inline int util_max_axis(float3 vec) -{ -#ifdef __KERNEL_SSE__ - __m128 a = shuffle<0,0,1,1>(vec.m128); - __m128 b = shuffle<1,2,2,1>(vec.m128); - __m128 c = _mm_cmpgt_ps(a, b); - int mask = _mm_movemask_ps(c) & 0x7; - static const char tab[8] = {2, 2, 2, 0, 1, 2, 1, 0}; - return tab[mask]; -#else - if(vec.x > vec.y) { - if(vec.x > vec.z) - return 0; - else - return 2; - } - else { - if(vec.y > vec.z) - return 1; - else - return 2; - } -#endif -} - CCL_NAMESPACE_END #endif /* __UTIL_MATH_H__ */ - diff --git a/intern/cycles/util/util_math_cdf.cpp b/intern/cycles/util/util_math_cdf.cpp index ec78ca15d88..c14d4793ea1 100644 --- a/intern/cycles/util/util_math_cdf.cpp +++ b/intern/cycles/util/util_math_cdf.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#include "util_math_cdf.h" +#include "util/util_math_cdf.h" -#include "util_algorithm.h" -#include "util_math.h" +#include "util/util_algorithm.h" +#include "util/util_math.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_math_cdf.h b/intern/cycles/util/util_math_cdf.h index 47dfb68ba44..79643fe26e3 100644 --- a/intern/cycles/util/util_math_cdf.h +++ b/intern/cycles/util/util_math_cdf.h @@ -17,9 +17,9 @@ #ifndef __UTIL_MATH_CDF_H__ #define __UTIL_MATH_CDF_H__ -#include "util_algorithm.h" -#include "util_math.h" -#include "util_vector.h" +#include "util/util_algorithm.h" +#include "util/util_math.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_math_intersect.h b/intern/cycles/util/util_math_intersect.h new file mode 100644 index 00000000000..2b65a0dfa48 --- /dev/null +++ b/intern/cycles/util/util_math_intersect.h @@ -0,0 +1,221 @@ +/* + * 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_MATH_INTERSECT_H__ +#define __UTIL_MATH_INTERSECT_H__ + +CCL_NAMESPACE_BEGIN + +/* Ray Intersection */ + +ccl_device bool ray_sphere_intersect( + float3 ray_P, float3 ray_D, float ray_t, + float3 sphere_P, float sphere_radius, + float3 *isect_P, float *isect_t) +{ + const float3 d = sphere_P - ray_P; + const float radiussq = sphere_radius*sphere_radius; + const float tsq = dot(d, d); + + if(tsq > radiussq) { + /* Ray origin outside sphere. */ + const float tp = dot(d, ray_D); + if(tp < 0.0f) { + /* Ray points away from sphere. */ + return false; + } + const float dsq = tsq - tp*tp; /* pythagoras */ + if(dsq > radiussq) { + /* Closest point on ray outside sphere. */ + return false; + } + const float t = tp - sqrtf(radiussq - dsq); /* pythagoras */ + if(t < ray_t) { + *isect_t = t; + *isect_P = ray_P + ray_D*t; + return true; + } + } + return false; +} + +ccl_device bool ray_aligned_disk_intersect( + float3 ray_P, float3 ray_D, float ray_t, + float3 disk_P, float disk_radius, + float3 *isect_P, float *isect_t) +{ + /* Aligned disk normal. */ + float disk_t; + const float3 disk_N = normalize_len(ray_P - disk_P, &disk_t); + const float div = dot(ray_D, disk_N); + if(UNLIKELY(div == 0.0f)) { + return false; + } + /* Compute t to intersection point. */ + const float t = -disk_t/div; + if(t < 0.0f || t > ray_t) { + return false; + } + /* Test if within radius. */ + float3 P = ray_P + ray_D*t; + if(len_squared(P - disk_P) > disk_radius*disk_radius) { + return false; + } + *isect_P = P; + *isect_t = t; + return true; +} + +#if defined(__KERNEL_CUDA__) && __CUDA_ARCH__ < 300 +ccl_device_inline +#else +ccl_device_forceinline +#endif +bool ray_triangle_intersect( + float3 ray_P, float3 ray_dir, float ray_t, +#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) + const ssef *ssef_verts, +#else + const float3 tri_a, const float3 tri_b, const float3 tri_c, +#endif + float *isect_u, float *isect_v, float *isect_t) +{ +#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) + typedef ssef float3; + const float3 tri_a(ssef_verts[0]); + const float3 tri_b(ssef_verts[1]); + const float3 tri_c(ssef_verts[2]); + const float3 P(ray_P); + const float3 dir(ray_dir); +#else +# define dot3(a, b) dot(a, b) + const float3 P = ray_P; + const float3 dir = ray_dir; +#endif + + /* Calculate vertices relative to ray origin. */ + const float3 v0 = tri_c - P; + const float3 v1 = tri_a - P; + const float3 v2 = tri_b - P; + + /* Calculate triangle edges. */ + const float3 e0 = v2 - v0; + const float3 e1 = v0 - v1; + const float3 e2 = v1 - v2; + + /* Perform edge tests. */ +#ifdef __KERNEL_SSE2__ + const float3 crossU = cross(v2 + v0, e0); + const float3 crossV = cross(v0 + v1, e1); + const float3 crossW = cross(v1 + v2, e2); +# ifndef __KERNEL_SSE__ + const ssef crossX(crossU.x, crossV.x, crossW.x, crossW.x); + const ssef crossY(crossU.y, crossV.y, crossW.y, crossW.y); + const ssef crossZ(crossU.z, crossV.z, crossW.z, crossW.z); +# else + ssef crossX(crossU); + ssef crossY(crossV); + ssef crossZ(crossW); + ssef zero = _mm_setzero_ps(); + _MM_TRANSPOSE4_PS(crossX, crossY, crossZ, zero); +# endif + const ssef dirX(ray_dir.x); + const ssef dirY(ray_dir.y); + const ssef dirZ(ray_dir.z); + /*const*/ ssef UVWW = crossX*dirX + crossY*dirY + crossZ*dirZ; + const float minUVW = reduce_min(UVWW); + const float maxUVW = reduce_max(UVWW); +#else /* __KERNEL_SSE2__ */ + const float U = dot(cross(v2 + v0, e0), ray_dir); + const float V = dot(cross(v0 + v1, e1), ray_dir); + const float W = dot(cross(v1 + v2, e2), ray_dir); + const float minUVW = min(U, min(V, W)); + const float maxUVW = max(U, max(V, W)); +#endif /* __KERNEL_SSE2__ */ + + if(minUVW < 0.0f && maxUVW > 0.0f) { + return false; + } + + /* Calculate geometry normal and denominator. */ + const float3 Ng1 = cross(e1, e0); + //const Vec3vfM Ng1 = stable_triangle_normal(e2,e1,e0); + const float3 Ng = Ng1 + Ng1; + const float den = dot3(Ng, dir); + /* Avoid division by 0. */ + if(UNLIKELY(den == 0.0f)) { + return false; + } + + /* Perform depth test. */ + const float T = dot3(v0, Ng); + const int sign_den = (__float_as_int(den) & 0x80000000); + const float sign_T = xor_signmask(T, sign_den); + if((sign_T < 0.0f) || + (sign_T > ray_t * xor_signmask(den, sign_den))) + { + return false; + } + + const float inv_den = 1.0f / den; +#ifdef __KERNEL_SSE2__ + UVWW *= inv_den; + _mm_store_ss(isect_u, UVWW); + _mm_store_ss(isect_v, shuffle<1,1,3,3>(UVWW)); +#else + *isect_u = U * inv_den; + *isect_v = V * inv_den; +#endif + *isect_t = T * inv_den; + return true; + +#undef dot3 +} + +ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, + float ray_mint, float ray_maxt, + float3 quad_P, + float3 quad_u, float3 quad_v, float3 quad_n, + float3 *isect_P, float *isect_t, + float *isect_u, float *isect_v) +{ + /* Perform intersection test. */ + float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n); + if(t < ray_mint || t > ray_maxt) { + return false; + } + const float3 hit = ray_P + t*ray_D; + const float3 inplane = hit - quad_P; + const float u = dot(inplane, quad_u) / dot(quad_u, quad_u) + 0.5f; + if(u < 0.0f || u > 1.0f) { + return false; + } + const float v = dot(inplane, quad_v) / dot(quad_v, quad_v) + 0.5f; + if(v < 0.0f || v > 1.0f) { + return false; + } + /* Store the result. */ + /* TODO(sergey): Check whether we can avoid some checks here. */ + if(isect_P != NULL) *isect_P = hit; + if(isect_t != NULL) *isect_t = t; + if(isect_u != NULL) *isect_u = u; + if(isect_v != NULL) *isect_v = v; + return true; +} + +CCL_NAMESPACE_END + +#endif /* __UTIL_MATH_INTERSECT_H__ */ diff --git a/intern/cycles/util/util_md5.h b/intern/cycles/util/util_md5.h index d0af9fdb004..e4cd66c85b0 100644 --- a/intern/cycles/util/util_md5.h +++ b/intern/cycles/util/util_md5.h @@ -30,8 +30,8 @@ #ifndef __UTIL_MD5_H__ #define __UTIL_MD5_H__ -#include "util_string.h" -#include "util_types.h" +#include "util/util_string.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_optimization.h b/intern/cycles/util/util_optimization.h index adc141a7b28..6f70a474fe7 100644 --- a/intern/cycles/util/util_optimization.h +++ b/intern/cycles/util/util_optimization.h @@ -111,7 +111,7 @@ /* 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_windows.h" +#include "util/util_windows.h" #endif diff --git a/intern/cycles/util/util_path.cpp b/intern/cycles/util/util_path.cpp index 1b2e8aace5b..cd3067f7650 100644 --- a/intern/cycles/util/util_path.cpp +++ b/intern/cycles/util/util_path.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#include "util_debug.h" -#include "util_md5.h" -#include "util_path.h" -#include "util_string.h" +#include "util/util_debug.h" +#include "util/util_md5.h" +#include "util/util_path.h" +#include "util/util_string.h" #include <OpenImageIO/filesystem.h> #include <OpenImageIO/strutil.h> @@ -45,7 +45,7 @@ OIIO_NAMESPACE_USING # include <shlwapi.h> #endif -#include "util_windows.h" +#include "util/util_windows.h" CCL_NAMESPACE_BEGIN @@ -320,17 +320,18 @@ static char *path_specials(const string& sub) { static bool env_init = false; static char *env_shader_path; - static char *env_kernel_path; + static char *env_source_path; if(!env_init) { env_shader_path = getenv("CYCLES_SHADER_PATH"); - env_kernel_path = getenv("CYCLES_KERNEL_PATH"); + /* NOTE: It is KERNEL in env variable for compatibility reasons. */ + env_source_path = getenv("CYCLES_KERNEL_PATH"); env_init = true; } if(env_shader_path != NULL && sub == "shader") { return env_shader_path; } - else if(env_shader_path != NULL && sub == "kernel") { - return env_kernel_path; + else if(env_shader_path != NULL && sub == "source") { + return env_source_path; } return NULL; } diff --git a/intern/cycles/util/util_path.h b/intern/cycles/util/util_path.h index 70dbb5ae403..0e5e2d2c837 100644 --- a/intern/cycles/util/util_path.h +++ b/intern/cycles/util/util_path.h @@ -24,10 +24,10 @@ #include <stdio.h> -#include "util_set.h" -#include "util_string.h" -#include "util_types.h" -#include "util_vector.h" +#include "util/util_set.h" +#include "util/util_string.h" +#include "util/util_types.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_progress.h b/intern/cycles/util/util_progress.h index 14215056840..39c1eed04e7 100644 --- a/intern/cycles/util/util_progress.h +++ b/intern/cycles/util/util_progress.h @@ -23,10 +23,10 @@ * update notifications from a job running in another thread. All methods * except for the constructor/destructor are thread safe. */ -#include "util_function.h" -#include "util_string.h" -#include "util_time.h" -#include "util_thread.h" +#include "util/util_function.h" +#include "util/util_string.h" +#include "util/util_time.h" +#include "util/util_thread.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_simd.cpp b/intern/cycles/util/util_simd.cpp index de2df612578..f90439c188b 100644 --- a/intern/cycles/util/util_simd.cpp +++ b/intern/cycles/util/util_simd.cpp @@ -19,7 +19,7 @@ (defined(WITH_KERNEL_NATIVE) && defined(__SSE2__)) #define __KERNEL_SSE2__ -#include "util_simd.h" +#include "util/util_simd.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_simd.h b/intern/cycles/util/util_simd.h index 756bd15ed25..557809a5719 100644 --- a/intern/cycles/util/util_simd.h +++ b/intern/cycles/util/util_simd.h @@ -20,8 +20,8 @@ #include <limits> -#include "util_debug.h" -#include "util_types.h" +#include "util/util_debug.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN @@ -451,11 +451,11 @@ ccl_device_inline int bitscan(int value) CCL_NAMESPACE_END -#include "util_math.h" -#include "util_sseb.h" -#include "util_ssei.h" -#include "util_ssef.h" -#include "util_avxf.h" +#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 /* __UTIL_SIMD_TYPES_H__ */ diff --git a/intern/cycles/util/util_sky_model.cpp b/intern/cycles/util/util_sky_model.cpp index 5730986cc4f..6dda8469907 100644 --- a/intern/cycles/util/util_sky_model.cpp +++ b/intern/cycles/util/util_sky_model.cpp @@ -97,8 +97,8 @@ All instructions on how to use this code are in the accompanying header file. */ -#include "util_sky_model.h" -#include "util_sky_model_data.h" +#include "util/util_sky_model.h" +#include "util/util_sky_model_data.h" #include <assert.h> #include <stdio.h> diff --git a/intern/cycles/util/util_stack_allocator.h b/intern/cycles/util/util_stack_allocator.h index d7aab5b250c..2f1799a739e 100644 --- a/intern/cycles/util/util_stack_allocator.h +++ b/intern/cycles/util/util_stack_allocator.h @@ -20,8 +20,8 @@ #include <cstddef> #include <memory> -#include "util_debug.h" -#include "util_types.h" +#include "util/util_debug.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_stats.h b/intern/cycles/util/util_stats.h index c21a8488c81..baba549753d 100644 --- a/intern/cycles/util/util_stats.h +++ b/intern/cycles/util/util_stats.h @@ -17,7 +17,7 @@ #ifndef __UTIL_STATS_H__ #define __UTIL_STATS_H__ -#include "util_atomic.h" +#include "util/util_atomic.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp index 5594aa8edb6..a1008d510d1 100644 --- a/intern/cycles/util/util_string.cpp +++ b/intern/cycles/util/util_string.cpp @@ -17,9 +17,9 @@ #include <stdarg.h> #include <stdio.h> -#include "util_foreach.h" -#include "util_string.h" -#include "util_windows.h" +#include "util/util_foreach.h" +#include "util/util_string.h" +#include "util/util_windows.h" #ifdef _WIN32 # ifndef vsnprintf diff --git a/intern/cycles/util/util_string.h b/intern/cycles/util/util_string.h index 7aeed96f00b..e2c105db9c1 100644 --- a/intern/cycles/util/util_string.h +++ b/intern/cycles/util/util_string.h @@ -21,7 +21,7 @@ #include <string> #include <sstream> -#include "util_vector.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp index 87d885c44cf..a942d738b8a 100644 --- a/intern/cycles/util/util_system.cpp +++ b/intern/cycles/util/util_system.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "util_system.h" +#include "util/util_system.h" -#include "util_debug.h" -#include "util_logging.h" -#include "util_types.h" -#include "util_string.h" +#include "util/util_debug.h" +#include "util/util_logging.h" +#include "util/util_types.h" +#include "util/util_string.h" #ifdef _WIN32 # if(!defined(FREE_WINDOWS)) diff --git a/intern/cycles/util/util_system.h b/intern/cycles/util/util_system.h index ff61b260bed..db7a45b2d59 100644 --- a/intern/cycles/util/util_system.h +++ b/intern/cycles/util/util_system.h @@ -17,7 +17,7 @@ #ifndef __UTIL_SYSTEM_H__ #define __UTIL_SYSTEM_H__ -#include "util_string.h" +#include "util/util_string.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp index 0d1fed3ebbf..fb0c34e1dc4 100644 --- a/intern/cycles/util/util_task.cpp +++ b/intern/cycles/util/util_task.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "util_debug.h" -#include "util_foreach.h" -#include "util_logging.h" -#include "util_system.h" -#include "util_task.h" -#include "util_time.h" +#include "util/util_debug.h" +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_system.h" +#include "util/util_task.h" +#include "util/util_time.h" //#define THREADING_DEBUG_ENABLED diff --git a/intern/cycles/util/util_task.h b/intern/cycles/util/util_task.h index 0b82f14f66f..3ebfb007e40 100644 --- a/intern/cycles/util/util_task.h +++ b/intern/cycles/util/util_task.h @@ -17,10 +17,10 @@ #ifndef __UTIL_TASK_H__ #define __UTIL_TASK_H__ -#include "util_list.h" -#include "util_string.h" -#include "util_thread.h" -#include "util_vector.h" +#include "util/util_list.h" +#include "util/util_string.h" +#include "util/util_thread.h" +#include "util/util_vector.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_thread.cpp b/intern/cycles/util/util_thread.cpp index 3db8b4bd197..3dcb09804b0 100644 --- a/intern/cycles/util/util_thread.cpp +++ b/intern/cycles/util/util_thread.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#include "util_thread.h" +#include "util/util_thread.h" -#include "util_system.h" -#include "util_windows.h" +#include "util/util_system.h" +#include "util/util_windows.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_thread.h b/intern/cycles/util/util_thread.h index 427c633d2ce..1e91fb8a706 100644 --- a/intern/cycles/util/util_thread.h +++ b/intern/cycles/util/util_thread.h @@ -32,7 +32,7 @@ # include <libkern/OSAtomic.h> #endif -#include "util_function.h" +#include "util/util_function.h" CCL_NAMESPACE_BEGIN @@ -106,6 +106,23 @@ protected: #endif }; +class thread_scoped_spin_lock { +public: + explicit thread_scoped_spin_lock(thread_spin_lock& lock) + : lock_(lock) { + lock_.lock(); + } + + ~thread_scoped_spin_lock() { + lock_.unlock(); + } + + /* TODO(sergey): Implement manual control over lock/unlock. */ + +protected: + thread_spin_lock& lock_; +}; + CCL_NAMESPACE_END #endif /* __UTIL_THREAD_H__ */ diff --git a/intern/cycles/util/util_time.cpp b/intern/cycles/util/util_time.cpp index 59c963cfafb..7c39aa294bf 100644 --- a/intern/cycles/util/util_time.cpp +++ b/intern/cycles/util/util_time.cpp @@ -16,8 +16,8 @@ #include <stdlib.h> -#include "util_time.h" -#include "util_windows.h" +#include "util/util_time.h" +#include "util/util_windows.h" #ifdef _WIN32 diff --git a/intern/cycles/util/util_transform.cpp b/intern/cycles/util/util_transform.cpp index 2f10540c94e..b8f182ae962 100644 --- a/intern/cycles/util/util_transform.cpp +++ b/intern/cycles/util/util_transform.cpp @@ -46,10 +46,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "util_transform.h" +#include "util/util_transform.h" -#include "util_boundbox.h" -#include "util_math.h" +#include "util/util_boundbox.h" +#include "util/util_math.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index a0695f20488..aef168ca64d 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -21,8 +21,8 @@ #include <string.h> #endif -#include "util_math.h" -#include "util_types.h" +#include "util/util_math.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h index dcd0b78e4a4..5a8f11694a7 100644 --- a/intern/cycles/util/util_types.h +++ b/intern/cycles/util/util_types.h @@ -55,6 +55,7 @@ #endif #define ccl_may_alias #define ccl_always_inline __forceinline +#define ccl_never_inline __declspec(noinline) #define ccl_maybe_unused #else @@ -68,6 +69,7 @@ #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 @@ -85,7 +87,7 @@ /* SIMD Types */ -#include "util_optimization.h" +#include "util/util_optimization.h" #endif @@ -180,7 +182,7 @@ struct ccl_try_align(16) int3 { }; __forceinline int3() {} - __forceinline int3(const __m128i a) : m128(a) {} + __forceinline explicit int3(const __m128i& a) : m128(a) {} __forceinline operator const __m128i&(void) const { return m128; } __forceinline operator __m128i&(void) { return m128; } @@ -202,7 +204,7 @@ struct ccl_try_align(16) int4 { }; __forceinline int4() {} - __forceinline int4(const __m128i a) : m128(a) {} + __forceinline explicit int4(const __m128i& a) : m128(a) {} __forceinline operator const __m128i&(void) const { return m128; } __forceinline operator __m128i&(void) { return m128; } @@ -252,7 +254,7 @@ struct ccl_try_align(16) float3 { }; __forceinline float3() {} - __forceinline float3(const __m128& a) : m128(a) {} + __forceinline explicit float3(const __m128& a) : m128(a) {} __forceinline operator const __m128&(void) const { return m128; } __forceinline operator __m128&(void) { return m128; } @@ -274,7 +276,7 @@ struct ccl_try_align(16) float4 { }; __forceinline float4() {} - __forceinline float4(const __m128 a) : m128(a) {} + __forceinline explicit float4(const __m128& a) : m128(a) {} __forceinline operator const __m128&(void) const { return m128; } __forceinline operator __m128&(void) { return m128; } diff --git a/intern/cycles/util/util_vector.h b/intern/cycles/util/util_vector.h index 546b17570bb..4add91a3368 100644 --- a/intern/cycles/util/util_vector.h +++ b/intern/cycles/util/util_vector.h @@ -23,9 +23,9 @@ #include <cstring> #include <vector> -#include "util_aligned_malloc.h" -#include "util_guarded_allocator.h" -#include "util_types.h" +#include "util/util_aligned_malloc.h" +#include "util/util_guarded_allocator.h" +#include "util/util_types.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/util/util_view.cpp b/intern/cycles/util/util_view.cpp index 9796a5f896d..10d86167921 100644 --- a/intern/cycles/util/util_view.cpp +++ b/intern/cycles/util/util_view.cpp @@ -17,11 +17,11 @@ #include <stdio.h> #include <stdlib.h> -#include "util_opengl.h" -#include "util_string.h" -#include "util_time.h" -#include "util_version.h" -#include "util_view.h" +#include "util/util_opengl.h" +#include "util/util_string.h" +#include "util/util_time.h" +#include "util/util_version.h" +#include "util/util_view.h" #ifdef __APPLE__ #include <GLUT/glut.h> diff --git a/intern/cycles/util/util_windows.cpp b/intern/cycles/util/util_windows.cpp index 4de8483564b..073db2a27db 100644 --- a/intern/cycles/util/util_windows.cpp +++ b/intern/cycles/util/util_windows.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "util_windows.h" +#include "util/util_windows.h" #ifdef _WIN32 diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index ff1922af4f3..6887063eae9 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -908,6 +908,11 @@ extern int GHOST_UseNativePixels(void); extern float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle); /** + * Returns the suggested DPI for this window. + */ +extern GHOST_TUns16 GHOST_GetDPIHint(GHOST_WindowHandle windowhandle); + +/** * Enable IME attached to the given window, i.e. allows user-input * events to be dispatched to the IME. * \param windowhandle Window handle of the caller diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index 688ebecf557..4a4d6be5ced 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -332,6 +332,12 @@ public: virtual float getNativePixelSize(void) = 0; + /** + * Returns the recommended DPI for this window. + * \return The recommended DPI for this window. + */ + virtual GHOST_TUns16 getDPIHint() = 0; + #ifdef WITH_INPUT_IME /** * Enable IME attached to the given window, i.e. allows user-input diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 9ee4599a4a6..02b5063e515 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -189,6 +189,7 @@ typedef enum { GHOST_kEventWindowUpdate, GHOST_kEventWindowSize, GHOST_kEventWindowMove, + GHOST_kEventWindowDPIHintChanged, GHOST_kEventDraggingEntered, GHOST_kEventDraggingUpdated, diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 41bc735e1e2..ce653188760 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -914,6 +914,12 @@ float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle) return 1.0f; } +GHOST_TUns16 GHOST_GetDPIHint(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow *window = (GHOST_IWindow *)windowhandle; + return window->getDPIHint(); +} + #ifdef WITH_INPUT_IME void GHOST_BeginIME(GHOST_WindowHandle windowhandle, diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 7d55a973f91..240d7ccd2fe 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -111,6 +111,11 @@ #define VK_MEDIA_PLAY_PAUSE 0xB3 #endif // VK_MEDIA_PLAY_PAUSE +// Window message newer than Windows 7 +#ifndef WM_DPICHANGED +#define WM_DPICHANGED 0x02E0 +#endif // WM_DPICHANGED + /* Workaround for some laptop touchpads, some of which seems to * have driver issues which makes it so window function receives * the message, but PeekMessage doesn't pick those messages for @@ -152,6 +157,27 @@ static void initRawInput() #undef DEVICE_COUNT } +#ifndef DPI_ENUMS_DECLARED +typedef enum PROCESS_DPI_AWARENESS { + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 +} PROCESS_DPI_AWARENESS; + +typedef enum MONITOR_DPI_TYPE { + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI +} MONITOR_DPI_TYPE; + +#define USER_DEFAULT_SCREEN_DPI 96 + +#define DPI_ENUMS_DECLARED +#endif +typedef HRESULT(API * GHOST_WIN32_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); +typedef BOOL(API * GHOST_WIN32_EnableNonClientDpiScaling)(HWND); + GHOST_SystemWin32::GHOST_SystemWin32() : m_hasPerformanceCounter(false), m_freq(0), m_start(0) { @@ -161,6 +187,18 @@ GHOST_SystemWin32::GHOST_SystemWin32() m_consoleStatus = 1; + // Tell Windows we are per monitor DPI aware. This disables the default + // blurry scaling and enables WM_DPICHANGED to allow us to draw at proper DPI. + HMODULE m_shcore = ::LoadLibrary("Shcore.dll"); + if (m_shcore) { + GHOST_WIN32_SetProcessDpiAwareness fpSetProcessDpiAwareness = + (GHOST_WIN32_SetProcessDpiAwareness) ::GetProcAddress(m_shcore, "SetProcessDpiAwareness"); + + if (fpSetProcessDpiAwareness) { + fpSetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); + } + } + // Check if current keyboard layout uses AltGr and save keylayout ID for // specialized handling if keys like VK_OEM_*. I.e. french keylayout // generates VK_OEM_8 for their exclamation key (key left of right shift) @@ -922,6 +960,20 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized"); if (hwnd) { + if(msg == WM_NCCREATE) { + // Tell Windows to automatically handle scaling of non-client areas + // such as the caption bar. EnableNonClientDpiScaling was introduced in Windows 10 + HMODULE m_user32 = ::LoadLibrary("User32.dll"); + if (m_user32) { + GHOST_WIN32_EnableNonClientDpiScaling fpEnableNonClientDpiScaling = + (GHOST_WIN32_EnableNonClientDpiScaling) ::GetProcAddress(m_user32, "EnableNonClientDpiScaling"); + + if (fpEnableNonClientDpiScaling) { + fpEnableNonClientDpiScaling(hwnd); + } + } + } + GHOST_WindowWin32 *window = (GHOST_WindowWin32 *)::GetWindowLongPtr(hwnd, GWLP_USERDATA); if (window) { switch (msg) { @@ -1294,6 +1346,32 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } break; + case WM_DPICHANGED: + /* The WM_DPICHANGED message is sent when the effective dots per inch (dpi) for a window has changed. + * The DPI is the scale factor for a window. There are multiple events that can cause the DPI to + * change such as when the window is moved to a monitor with a different DPI. + */ + { + WORD newYAxisDPI = HIWORD(wParam); + WORD newXAxisDPI = LOWORD(wParam); + // The suggested new size and position of the window. + RECT* const suggestedWindowRect = (RECT*)lParam; + + // Push DPI change event first + system->pushEvent(processWindowEvent(GHOST_kEventWindowDPIHintChanged, window)); + system->dispatchEvents(); + eventHandled = true; + + // Then move and resize window + SetWindowPos(hwnd, + NULL, + suggestedWindowRect->left, + suggestedWindowRect->top, + suggestedWindowRect->right - suggestedWindowRect->left, + suggestedWindowRect->bottom - suggestedWindowRect->top, + SWP_NOZORDER | SWP_NOACTIVATE); + } + break; //////////////////////////////////////////////////////////////////////// // Window events, ignored //////////////////////////////////////////////////////////////////////// diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index d778628ea37..2798bdf72f3 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -295,6 +295,15 @@ public: return 1.0f; } + /** + * Returns the recommended DPI for this window. + * \return The recommended DPI for this window. + */ + virtual inline GHOST_TUns16 getDPIHint() + { + return 96; + } + #ifdef WITH_INPUT_IME virtual void beginIME(GHOST_TInt32 x, GHOST_TInt32 y, diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp index 1335c38d977..aeb6188daef 100644 --- a/intern/ghost/intern/GHOST_WindowSDL.cpp +++ b/intern/ghost/intern/GHOST_WindowSDL.cpp @@ -563,3 +563,19 @@ GHOST_WindowSDL::setWindowCursorVisibility(bool visible) SDL_ShowCursor(visible); return GHOST_kSuccess; } + +GHOST_TUns16 +GHOST_WindowSDL::getDPIHint() +{ + int displayIndex = SDL_GetWindowDisplayIndex(m_sdl_win); + if (displayIndex < 0) { + return 96; + } + + float ddpi; + if (SDL_GetDisplayDPI(displayIndex, &ddpi, NULL, NULL) != 0) { + return 96; + } + + return (int)ddpi; +} diff --git a/intern/ghost/intern/GHOST_WindowSDL.h b/intern/ghost/intern/GHOST_WindowSDL.h index 5f658e8ad01..96104ec28b4 100644 --- a/intern/ghost/intern/GHOST_WindowSDL.h +++ b/intern/ghost/intern/GHOST_WindowSDL.h @@ -168,6 +168,8 @@ protected: GHOST_TSuccess beginFullScreen() const { return GHOST_kFailure; } GHOST_TSuccess endFullScreen() const { return GHOST_kFailure; } + + GHOST_TUns16 getDPIHint(); }; diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 7d80aa43a40..fc46164c135 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -92,6 +92,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_tablet(0), m_maxPressure(0), m_normal_state(GHOST_kWindowStateNormal), + m_user32(NULL), m_parentWindowHwnd(parentwindowhwnd), m_debug_context(is_debug) { @@ -965,6 +966,23 @@ void GHOST_WindowWin32::bringTabletContextToFront() } } +GHOST_TUns16 GHOST_WindowWin32::getDPIHint() +{ + if (!m_user32) { + m_user32 = ::LoadLibrary("user32.dll"); + } + + if (m_user32) { + GHOST_WIN32_GetDpiForWindow fpGetDpiForWindow = (GHOST_WIN32_GetDpiForWindow) ::GetProcAddress(m_user32, "GetDpiForWindow"); + + if (fpGetDpiForWindow) { + return fpGetDpiForWindow(this->m_hWnd); + } + } + + return USER_DEFAULT_SCREEN_DPI; +} + /** Reverse the bits in a GHOST_TUns8 */ static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch) { diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index a1cf58c9ceb..75a33951ff4 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -58,6 +58,12 @@ typedef BOOL (API * GHOST_WIN32_WTClose)(HCTX); typedef BOOL (API * GHOST_WIN32_WTPacket)(HCTX, UINT, LPVOID); typedef BOOL (API * GHOST_WIN32_WTOverlap)(HCTX, BOOL); +// typedefs for user32 functions to allow dynamic loading of Windows 10 DPI scaling functions +typedef UINT(API * GHOST_WIN32_GetDpiForWindow)(HWND); +#ifndef USER_DEFAULT_SCREEN_DPI +#define USER_DEFAULT_SCREEN_DPI 96 +#endif // USER_DEFAULT_SCREEN_DPI + /** * GHOST window on M$ Windows OSs. * \author Maarten Gribnau @@ -251,6 +257,8 @@ public: GHOST_TSuccess endFullScreen() const {return GHOST_kFailure;} + GHOST_TUns16 getDPIHint() override; + /** if the window currently resizing */ bool m_inLiveResize; @@ -351,6 +359,9 @@ private: GHOST_TWindowState m_normal_state; + /** user32 dll handle*/ + HMODULE m_user32; + /** Hwnd to parent window */ GHOST_TEmbedderWindowID m_parentWindowHwnd; diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 47fbe1256b1..2019f58251f 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -56,6 +56,9 @@ # include <X11/extensions/XInput2.h> #endif +//For DPI value +#include <X11/Xresource.h> + #if defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__) || defined(_AIX) # include <strings.h> #endif @@ -68,6 +71,7 @@ #include <algorithm> #include <string> +#include <math.h> /* For obscure full screen mode stuff * lifted verbatim from blut. */ @@ -1672,3 +1676,44 @@ endFullScreen() const return GHOST_kSuccess; } + +GHOST_TUns16 +GHOST_WindowX11:: +getDPIHint() +{ + /* Try to read DPI setting set using xrdb */ + char* resMan = XResourceManagerString(m_display); + if (resMan) { + XrmDatabase xrdb = XrmGetStringDatabase(resMan); + if (xrdb) { + char* type = NULL; + XrmValue val; + + int success = XrmGetResource(xrdb, "Xft.dpi", "Xft.Dpi", &type, &val); + if (success && type) { + if (strcmp(type, "String") == 0) { + return atoi((char*)val.addr); + } + } + } + } + + /* Fallback to calculating DPI using X reported DPI, set using xrandr --dpi */ + XWindowAttributes attr; + if (!XGetWindowAttributes(m_display, m_window, &attr)) { + /* Failed to get window attributes, return X11 default DPI */ + return 96; + } + + Screen* screen = attr.screen; + int pixelWidth = WidthOfScreen(screen); + int pixelHeight = HeightOfScreen(screen); + int mmWidth = WidthMMOfScreen(screen); + int mmHeight = HeightMMOfScreen(screen); + + double pixelDiagonal = sqrt((pixelWidth * pixelWidth) + (pixelHeight * pixelHeight)); + double mmDiagonal = sqrt((mmWidth * mmWidth) + (mmHeight * mmHeight)); + float inchDiagonal = mmDiagonal * 0.039f; + int dpi = pixelDiagonal / inchDiagonal; + return dpi; +} diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 9380aa9d631..5c54c1e8162 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -235,6 +235,8 @@ public: GHOST_TSuccess endFullScreen() const; + GHOST_TUns16 getDPIHint(); + protected: /** * \param type The type of rendering context create. diff --git a/intern/libmv/libmv/multiview/homography.cc b/intern/libmv/libmv/multiview/homography.cc index ce533a3ead2..69177743f94 100644 --- a/intern/libmv/libmv/multiview/homography.cc +++ b/intern/libmv/libmv/multiview/homography.cc @@ -209,6 +209,8 @@ class HomographySymmetricGeometricCostFunctor { return true; } + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + const Vec2 x_; const Vec2 y_; }; diff --git a/intern/locale/msgfmt.cc b/intern/locale/msgfmt.cc index 4779450bd1b..02c58ebc5bc 100644 --- a/intern/locale/msgfmt.cc +++ b/intern/locale/msgfmt.cc @@ -27,42 +27,36 @@ namespace { std::map<std::string, std::string> MESSAGES; -bool starts_with(const std::string &string, +bool starts_with(const std::string &str, const std::string &prefix) { - return prefix.size() <= string.size() && - string.compare(0, prefix.size(), prefix) == 0; -} - -std::string ltrim(const std::string &s) { - std::string result = s; - result.erase(result.begin(), - std::find_if(result.begin(), - result.end(), - std::not1(std::ptr_fun<int, int>(std::isspace)))); - return result; + const size_t prefix_length = prefix.length(); + if (prefix_length == 0) { + return true; + } + // TODO(sergey): Could be optimized if we calculate str.length() + // to maximum of prefix_length characters. + if (prefix_length > str.length()) { + return false; + } else { + return str.compare(0, prefix_length, prefix) == 0; + } } -std::string rtrim(const std::string &s) { - std::string result = s; - result.erase( - std::find_if(result.rbegin(), - result.rend(), - std::not1(std::ptr_fun<int, int>(std::isspace))).base(), - result.end()); +std::string trim(const std::string &str) { + std::string result = str; + result.erase(0, result.find_first_not_of(" \t\r\n")); + result.erase(result.find_last_not_of(" \t\r\n") + 1); return result; } -std::string trim(const std::string &s) { - return ltrim(rtrim(s)); -} - -std::string unescape(const std::string &s) { +std::string unescape(const std::string &str) { std::string result; - std::string::const_iterator it = s.begin(); - while (it != s.end()) { - char current_char = *it++; - if (current_char == '\\' && it != s.end()) { - char next_char = *it++; + const size_t str_length = str.length(); + size_t i = 0; + while (i < str_length) { + char current_char = str[i++]; + if (current_char == '\\' && i < str_length - 1) { + char next_char = str[i++]; if (next_char == '\\') { current_char = '\\'; } else if (next_char == 'n') { @@ -76,8 +70,9 @@ std::string unescape(const std::string &s) { result += current_char; } - if (result[0] == '"' && result[result.size() - 1] == '"') { - result = result.substr(1, result.size() - 2); + const size_t result_length = result.length(); + if (result[0] == '"' && result[result_length - 1] == '"') { + result = result.substr(1, result_length - 2); } return result; @@ -100,6 +95,7 @@ void add(const std::string &msgctxt, template<typename TKey, typename TValue> void get_keys(std::map<TKey, TValue> map, std::vector<TKey> *keys) { + keys->reserve(map.size()); for (typename std::map<TKey, TValue>::iterator it = map.begin(); it != map.end(); it++) { @@ -136,6 +132,7 @@ std::string generate(void) { std::sort(keys.begin(), keys.end()); std::vector<Offset> offsets; + offsets.reserve(keys.size()); std::string ids = "", strs = ""; for (std::vector<std::string>::iterator it = keys.begin(); it != keys.end(); @@ -160,6 +157,8 @@ std::string generate(void) { int valuestart = keystart + ids.size(); std::vector<int> koffsets; std::vector<int> voffsets; + koffsets.reserve(offsets.size() * 2); + voffsets.reserve(offsets.size() * 2); // The string table first has the list of keys, then the list of values. // Each entry has first the size of the string, then the file offset. for (std::vector<Offset>::iterator it = offsets.begin(); diff --git a/release/scripts/freestyle/modules/freestyle/utils.py b/release/scripts/freestyle/modules/freestyle/utils.py index d3eba187f70..2d47995d474 100644 --- a/release/scripts/freestyle/modules/freestyle/utils.py +++ b/release/scripts/freestyle/modules/freestyle/utils.py @@ -318,7 +318,7 @@ class BoundingBox: class StrokeCollector(StrokeShader): - "Collects and Stores stroke objects" + """Collects and Stores stroke objects""" def __init__(self): StrokeShader.__init__(self) self.strokes = [] diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py index 886f078f046..51e3e65b78c 100644 --- a/release/scripts/modules/addon_utils.py +++ b/release/scripts/modules/addon_utils.py @@ -24,6 +24,7 @@ __all__ = ( "check", "enable", "disable", + "disable_all", "reset_all", "module_bl_info", ) @@ -444,6 +445,13 @@ def reset_all(*, reload_scripts=False): disable(mod_name) +def disable_all(): + import sys + for mod_name, mod in sys.modules.items(): + if getattr(mod, "__addon_enabled__", False): + disable(mod_name) + + def module_bl_info(mod, info_basis=None): if info_basis is None: info_basis = { diff --git a/release/scripts/modules/bl_app_override/__init__.py b/release/scripts/modules/bl_app_override/__init__.py new file mode 100644 index 00000000000..89cc8a0eb28 --- /dev/null +++ b/release/scripts/modules/bl_app_override/__init__.py @@ -0,0 +1,202 @@ +# ##### 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 ##### + +# <pep8-80 compliant> + +""" +Module to manage overriding various parts of Blender. + +Intended for use with 'app_templates', though it can be used from anywhere. +""" + + +# TODO, how to check these aren't from add-ons. +# templates might need to un-register while filtering. +def class_filter(cls_parent, **kw): + whitelist = kw.pop("whitelist", None) + blacklist = kw.pop("blacklist", None) + kw_items = tuple(kw.items()) + for cls in cls_parent.__subclasses__(): + # same as is_registered() + if "bl_rna" in cls.__dict__: + if blacklist is not None and cls.__name__ in blacklist: + continue + if ((whitelist is not None and cls.__name__ is whitelist) or + all((getattr(cls, attr) in expect) for attr, expect in kw_items)): + yield cls + + +def ui_draw_filter_register( + *, + ui_ignore_classes=None, + ui_ignore_operator=None, + ui_ignore_property=None, + ui_ignore_menu=None, + ui_ignore_label=None +): + import bpy + + UILayout = bpy.types.UILayout + + if ui_ignore_classes is None: + ui_ignore_classes = ( + bpy.types.Panel, + bpy.types.Menu, + bpy.types.Header, + ) + + class OperatorProperties_Fake: + pass + + class UILayout_Fake(bpy.types.UILayout): + __slots__ = () + + def __getattribute__(self, attr): + # ensure we always pass down UILayout_Fake instances + if attr in {"row", "split", "column", "box", "column_flow"}: + real_func = UILayout.__getattribute__(self, attr) + + def dummy_func(*args, **kw): + # print("wrapped", attr) + ret = real_func(*args, **kw) + return UILayout_Fake(ret) + return dummy_func + + elif attr in {"operator", "operator_menu_enum", "operator_enum"}: + if ui_ignore_operator is None: + return UILayout.__getattribute__(self, attr) + + real_func = UILayout.__getattribute__(self, attr) + + def dummy_func(*args, **kw): + # print("wrapped", attr) + if not ui_ignore_operator(args[0]): + ret = real_func(*args, **kw) + else: + # UILayout.__getattribute__(self, "label")() + # may need to be set + ret = OperatorProperties_Fake() + return ret + return dummy_func + + elif attr in {"prop", "prop_enum"}: + if ui_ignore_property is None: + return UILayout.__getattribute__(self, attr) + + real_func = UILayout.__getattribute__(self, attr) + + def dummy_func(*args, **kw): + # print("wrapped", attr) + if not ui_ignore_property(args[0].__class__.__name__, args[1]): + ret = real_func(*args, **kw) + else: + ret = None + return ret + return dummy_func + + elif attr == "menu": + if ui_ignore_menu is None: + return UILayout.__getattribute__(self, attr) + + real_func = UILayout.__getattribute__(self, attr) + + def dummy_func(*args, **kw): + # print("wrapped", attr) + if not ui_ignore_menu(args[0]): + ret = real_func(*args, **kw) + else: + ret = None + return ret + return dummy_func + + elif attr == "label": + if ui_ignore_label is None: + return UILayout.__getattribute__(self, attr) + + real_func = UILayout.__getattribute__(self, attr) + + def dummy_func(*args, **kw): + # print("wrapped", attr) + if not ui_ignore_label(args[0] if args else kw.get("text", "")): + ret = real_func(*args, **kw) + else: + # ret = real_func() + ret = None + return ret + return dummy_func + else: + return UILayout.__getattribute__(self, attr) + # print(self, attr) + + def operator(*args, **kw): + return super().operator(*args, **kw) + + def draw_override(func_orig, self_real, context): + cls_real = self_real.__class__ + if cls_real is super: + # simple, no wrapping + return func_orig(self_real, context) + + class Wrapper(cls_real): + __slots__ = () + def __getattribute__(self, attr): + if attr == "layout": + return UILayout_Fake(self_real.layout) + else: + cls = super() + try: + return cls.__getattr__(self, attr) + except AttributeError: + # class variable + try: + return getattr(cls, attr) + except AttributeError: + # for preset bl_idname access + return getattr(UILayout(self), attr) + + @property + def layout(self): + # print("wrapped") + return self_real.layout + + return func_orig(Wrapper(self_real), context) + + ui_ignore_store = [] + + for cls in ui_ignore_classes: + for subcls in list(cls.__subclasses__()): + if "draw" in subcls.__dict__: # don't want to get parents draw() + + def replace_draw(): + # function also serves to hold draw_old in a local name-space + draw_orig = subcls.draw + + def draw(self, context): + return draw_override(draw_orig, self, context) + subcls.draw = draw + + ui_ignore_store.append((subcls, "draw", subcls.draw)) + + replace_draw() + + return ui_ignore_store + + +def ui_draw_filter_unregister(ui_ignore_store): + for (obj, attr, value) in ui_ignore_store: + setattr(obj, attr, value) diff --git a/release/scripts/modules/bl_app_override/helpers.py b/release/scripts/modules/bl_app_override/helpers.py new file mode 100644 index 00000000000..981039e8ddc --- /dev/null +++ b/release/scripts/modules/bl_app_override/helpers.py @@ -0,0 +1,167 @@ +# ##### 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 ##### + +# <pep8-80 compliant> + +# ----------------------------------------------------------------------------- +# AppOverrideState + + +class AppOverrideState: + """ + Utility class to encapsulate overriding the application state + so that settings can be restored afterwards. + """ + __slots__ = ( + # setup_classes + "_class_store", + # setup_ui_ignore + "_ui_ignore_store", + # setup_addons + "_addon_store", + ) + + # --------- + # Callbacks + # + # Set as None, to make it simple to check if they're being overridden. + + # setup/teardown classes + class_ignore = None + + # setup/teardown ui_ignore + ui_ignore_classes = None + ui_ignore_operator = None + ui_ignore_property = None + ui_ignore_menu = None + ui_ignore_label = None + + addon_paths = None + addons = None + + # End callbacks + + def __init__(self): + self._class_store = None + self._addon_store = None + self._ui_ignore_store = None + + def _setup_classes(self): + import bpy + assert(self._class_store is None) + self._class_store = self.class_ignore() + from bpy.utils import unregister_class + for cls in self._class_store: + unregister_class(cls) + + def _teardown_classes(self): + assert(self._class_store is not None) + + from bpy.utils import register_class + for cls in self._class_store: + register_class(cls) + self._class_store = None + + def _setup_ui_ignore(self): + import bl_app_override + + self._ui_ignore_store = bl_app_override.ui_draw_filter_register( + ui_ignore_classes=( + None if self.ui_ignore_classes is None + else self.ui_ignore_classes() + ), + ui_ignore_operator=self.ui_ignore_operator, + ui_ignore_property=self.ui_ignore_property, + ui_ignore_menu=self.ui_ignore_menu, + ui_ignore_label=self.ui_ignore_label, + ) + + def _teardown_ui_ignore(self): + import bl_app_override + bl_app_override.ui_draw_filter_unregister( + self._ui_ignore_store + ) + self._ui_ignore_store = None + + def _setup_addons(self): + import sys + import os + + sys_path = [] + if self.addon_paths is not None: + for path in self.addon_paths(): + if path not in sys.path: + sys.path.append(path) + + import addon_utils + addons = [] + if self.addons is not None: + addons.extend(self.addons()) + for addon in addons: + addon_utils.enable(addon) + + self._addon_store = { + "sys_path": sys_path, + "addons": addons, + } + + def _teardown_addons(self): + import sys + + sys_path = self._addon_store["sys_path"] + for path in sys_path: + # should always succeed, but if not it doesn't matter + # (someone else was changing the sys.path), ignore! + try: + sys.path.remove(path) + except: + pass + + addons = self._addon_store["addons"] + import addon_utils + for addon in addons: + addon_utils.disable(addon) + + self._addon_store.clear() + self._addon_store = None + + def setup(self): + if self.class_ignore is not None: + self._setup_classes() + + if any((self.addon_paths, + self.addons, + )): + self._setup_addons() + + if any((self.ui_ignore_operator, + self.ui_ignore_property, + self.ui_ignore_menu, + self.ui_ignore_label, + )): + self._setup_ui_ignore() + + def teardown(self): + if self._class_store is not None: + self._teardown_classes() + + if self._addon_store is not None: + self._teardown_addons() + + if self._ui_ignore_store is not None: + self._teardown_ui_ignore() diff --git a/release/scripts/modules/bl_app_template_utils.py b/release/scripts/modules/bl_app_template_utils.py new file mode 100644 index 00000000000..b3a4824aa7b --- /dev/null +++ b/release/scripts/modules/bl_app_template_utils.py @@ -0,0 +1,198 @@ +# ##### 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 ##### + +# <pep8-80 compliant> + +""" +Similar to ``addon_utils``, except we can only have one active at a time. + +In most cases users of this module will simply call 'activate'. +""" + +__all__ = ( + "activate", + "import_from_path", + "import_from_id", + "reset", +) + +import bpy as _bpy + +# Normally matches 'user_preferences.app_template_id', +# but loading new preferences will get us out of sync. +_app_template = { + "id": "", +} + +# instead of sys.modules +# note that we only ever have one template enabled at a time +# so it may not seem necessary to use this. +# +# However, templates may want to share between each-other, +# so any loaded modules are stored here? +# +# Note that the ID here is the app_template_id , not the modules __name__. +_modules = {} + + +def _enable(template_id, *, handle_error=None, ignore_not_found=False): + import os + import sys + from bpy_restrict_state import RestrictBlend + + if handle_error is None: + def handle_error(ex): + import traceback + traceback.print_exc() + + # Split registering up into 2 steps so we can undo + # if it fails par way through. + + # disable the context, using the context at all is + # really bad while loading an template, don't do it! + with RestrictBlend(): + + # 1) try import + try: + mod = import_from_id(template_id, ignore_not_found=ignore_not_found) + if mod is None: + return None + mod.__template_enabled__ = False + _modules[template_id] = mod + except Exception as ex: + handle_error(ex) + return None + + # 2) try run the modules register function + try: + mod.register() + except Exception as ex: + print("Exception in module register(): %r" % + getattr(mod, "__file__", template_id)) + handle_error(ex) + del _modules[template_id] + return None + + # * OK loaded successfully! * + mod.__template_enabled__ = True + + if _bpy.app.debug_python: + print("\tapp_template_utils.enable", mod.__name__) + + return mod + + +def _disable(template_id, *, handle_error=None): + """ + Disables a template by name. + + :arg template_id: The name of the template and module. + :type template_id: string + :arg handle_error: Called in the case of an error, + taking an exception argument. + :type handle_error: function + """ + import sys + + if handle_error is None: + def handle_error(ex): + import traceback + traceback.print_exc() + + mod = _modules.get(template_id) + + if mod and getattr(mod, "__template_enabled__", False) is not False: + mod.__template_enabled__ = False + + try: + mod.unregister() + except Exception as ex: + print("Exception in module unregister(): %r" % + getattr(mod, "__file__", template_id)) + handle_error(ex) + else: + print("\tapp_template_utils.disable: %s not %s." % + (template_id, "disabled" if mod is None else "loaded")) + + if _bpy.app.debug_python: + print("\tapp_template_utils.disable", template_id) + + +def import_from_path(path, ignore_not_found=False): + import os + from importlib import import_module + base_module, template_id = path.rsplit(os.sep, 2)[-2:] + module_name = base_module + "." + template_id + + try: + return import_module(module_name) + except ModuleNotFoundError as ex: + if ignore_not_found and ex.name == module_name: + return None + raise ex + + +def import_from_id(template_id, ignore_not_found=False): + import os + path = next(iter(_bpy.utils.app_template_paths(template_id)), None) + if path is None: + if ignore_not_found: + return None + else: + raise Exception("%r template not found!" % template_id) + else: + if ignore_not_found: + if not os.path.exists(os.path.join(path, "__init__.py")): + return None + return import_from_path(path, ignore_not_found=ignore_not_found) + + +def activate(template_id=None): + template_id_prev = _app_template["id"] + + # not needed but may as well avoid activating same template + # ... in fact keep this, it will show errors early on! + """ + if template_id_prev == template_id: + return + """ + + if template_id_prev: + _disable(template_id_prev) + + # Disable all addons, afterwards caller must reset. + import addon_utils + addon_utils.disable_all() + + # ignore_not_found so modules that don't contain scripts don't raise errors + mod = _enable(template_id, ignore_not_found=True) if template_id else None + + _app_template["id"] = template_id + + +def reset(*, reload_scripts=False): + """ + Sets default state. + """ + template_id = _bpy.context.user_preferences.app_template + if _bpy.app.debug_python: + print("bl_app_template_utils.reset('%s')" % template_id) + + # TODO reload_scripts + + activate(template_id) diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py index 26fdbc8cc56..545b891505f 100644 --- a/release/scripts/modules/bpy/__init__.py +++ b/release/scripts/modules/bpy/__init__.py @@ -48,11 +48,11 @@ def main(): import sys # Possibly temp. addons path - from os.path import join, dirname, normpath - sys.path.append(normpath(join(dirname(__file__), - "..", "..", "addons", "modules"))) - sys.path.append(join(utils.user_resource('SCRIPTS'), - "addons", "modules")) + from os.path import join, dirname + sys.path.extend([ + join(dirname(dirname(dirname(__file__))), "addons", "modules"), + join(utils.user_resource('SCRIPTS'), "addons", "modules"), + ]) # fake module to allow: # from bpy.types import Panel diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py index a864a86eba7..e17d710068c 100644 --- a/release/scripts/modules/bpy/path.py +++ b/release/scripts/modules/bpy/path.py @@ -204,7 +204,9 @@ def display_name(name): name = name.replace("_colon_", ":") name = name.replace("_plus_", "+") - name = name.replace("_", " ") + # strip to allow underscore prefix + # (when paths can't start with numbers for eg). + name = name.replace("_", " ").lstrip(" ") if name.islower(): name = name.lower().title() diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py index 31dd836e034..1d555ae7123 100644 --- a/release/scripts/modules/bpy/utils/__init__.py +++ b/release/scripts/modules/bpy/utils/__init__.py @@ -32,6 +32,7 @@ __all__ = ( "preset_find", "preset_paths", "refresh_script_paths", + "app_template_paths", "register_class", "register_module", "register_manual_map", @@ -49,18 +50,18 @@ __all__ = ( "unregister_class", "unregister_module", "user_resource", - ) +) from _bpy import ( - _utils_units as units, - blend_paths, - escape_identifier, - register_class, - resource_path, - script_paths as _bpy_script_paths, - unregister_class, - user_resource as _user_resource, - ) + _utils_units as units, + blend_paths, + escape_identifier, + register_class, + resource_path, + script_paths as _bpy_script_paths, + unregister_class, + user_resource as _user_resource, +) import bpy as _bpy import os as _os @@ -142,7 +143,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): as modules. :type refresh_scripts: bool """ - use_time = _bpy.app.debug_python + use_time = use_class_register_check = _bpy.app.debug_python if use_time: import time @@ -161,7 +162,8 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): for module_name in [ext.module for ext in _user_preferences.addons]: _addon_utils.disable(module_name) - # *AFTER* unregistering all add-ons, otherwise all calls to unregister_module() will silently fail (do nothing). + # *AFTER* unregistering all add-ons, otherwise all calls to + # unregister_module() will silently fail (do nothing). _bpy_types.TypeMap.clear() def register_module_call(mod): @@ -245,6 +247,12 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): for mod in modules_from_path(path, loaded_modules): test_register(mod) + # load template (if set) + if any(_bpy.utils.app_template_paths()): + import bl_app_template_utils + bl_app_template_utils.reset(reload_scripts=reload_scripts) + del bl_app_template_utils + # deal with addons separately _initialize = getattr(_addon_utils, "_initialize", None) if _initialize is not None: @@ -269,13 +277,21 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): if use_time: print("Python Script Load Time %.4f" % (time.time() - t_main)) + if use_class_register_check: + for cls in _bpy.types.bpy_struct.__subclasses__(): + if getattr(cls, "is_registered", False): + for subcls in cls.__subclasses__(): + if not subcls.is_registered: + print( + "Warning, unregistered class: %s(%s)" % + (subcls.__name__, cls.__name__) + ) + # base scripts -_scripts = _os.path.join(_os.path.dirname(__file__), - _os.path.pardir, - _os.path.pardir, - ) -_scripts = (_os.path.normpath(_scripts), ) +_scripts = ( + _os.path.dirname(_os.path.dirname(_os.path.dirname(__file__))), +) def script_path_user(): @@ -356,6 +372,38 @@ def refresh_script_paths(): _sys_path_ensure(path) +def app_template_paths(subdir=None): + """ + Returns valid application template paths. + + :arg subdir: Optional subdir. + :type subdir: string + :return: app template paths. + :rtype: generator + """ + + # 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 + + def preset_paths(subdir): """ Returns a list of paths for a specific preset. diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py index 6ecdd0c5e13..3203bc41b76 100644 --- a/release/scripts/modules/bpy_extras/keyconfig_utils.py +++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py @@ -141,6 +141,78 @@ KM_HIERARCHY = [ # ----------------------------------------------------------------------------- +# Add-on helpers to properly (un)register their own keymaps. + +# Example of keymaps_description: +keymaps_description_doc = """ +keymaps_description is a tuple (((keymap_description), (tuple of keymap_item_descriptions))). +keymap_description is a tuple (name, space_type, region_type, is_modal). +keymap_item_description is a tuple ({kw_args_for_keymap_new}, (tuple of properties)). +kw_args_for_keymap_new is a mapping which keywords match parameters of keymap.new() function. +tuple of properties is a tuple of pairs (prop_name, prop_value) (properties being those of called operator). + +Example: + +KEYMAPS = ( + # First, keymap identifiers (last bool is True for modal km). + (('Sequencer', 'SEQUENCE_EDITOR', 'WINDOW', False), ( + # Then a tuple of keymap items, defined by a dict of kwargs for the km new func, and a tuple of tuples (name, val) + # for ops properties, if needing non-default values. + ({"idname": export_strips.SEQExportStrip.bl_idname, "type": 'P', "value": 'PRESS', "shift": True, "ctrl": True}, + ()), + )), +) +""" + + +def addon_keymap_register(wm, keymaps_description): + """ + Register a set of keymaps for addons. + + """ + keymaps_description_doc + kconf = wm.keyconfigs.addon + if not kconf: + return # happens in background mode... + for km_info, km_items in keymaps_description: + km_name, km_sptype, km_regtype, km_ismodal = km_info + kmap = [k for k in kconf.keymaps + if k.name == km_name and k.region_type == km_regtype and + k.space_type == km_sptype and k.is_modal == km_ismodal] + if kmap: + kmap = kmap[0] + else: + kmap = kconf.keymaps.new(km_name, region_type=km_regtype, space_type=km_sptype, modal=km_ismodal) + for kmi_kwargs, props in km_items: + kmi = kmap.keymap_items.new(**kmi_kwargs) + kmi.active = True + for prop, val in props: + setattr(kmi.properties, prop, val) + + +def addon_keymap_unregister(wm, keymaps_description): + """ + Unregister a set of keymaps for addons. + + """ + keymaps_description_doc + # NOTE: We must also clean up user keyconfig, else, if user has customized one of add-on's shortcut, this + # customization remains in memory, and comes back when re-enabling the addon, causing a segfault... :/ + kconfs = wm.keyconfigs + for kconf in (kconfs.user, kconfs.addon): + for km_info, km_items in keymaps_description: + km_name, km_sptype, km_regtype, km_ismodal = km_info + kmaps = (k for k in kconf.keymaps + if k.name == km_name and k.region_type == km_regtype and + k.space_type == km_sptype and k.is_modal == km_ismodal) + for kmap in kmaps: + for kmi_kwargs, props in km_items: + idname = kmi_kwargs["idname"] + for kmi in kmap.keymap_items: + if kmi.idname == idname: + kmap.keymap_items.remove(kmi) + # NOTE: We won't remove addons keymaps themselves, other addons might also use them! + + +# ----------------------------------------------------------------------------- # Utility functions def km_exists_in(km, export_keymaps): diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 5eb8b946568..600b29a6b2b 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -683,6 +683,10 @@ class _GenericUI: return draw_funcs @classmethod + def is_extended(cls): + return bool(getattr(cls.draw, "_draw_funcs", None)) + + @classmethod def append(cls, draw_func): """ Append a draw function to this menu, diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py index c28c1461003..1e0dbe6925e 100644 --- a/release/scripts/startup/bl_operators/__init__.py +++ b/release/scripts/startup/bl_operators/__init__.py @@ -21,8 +21,7 @@ # support reloading sub-modules if "bpy" in locals(): from importlib import reload - for val in _modules_loaded: - reload(val) + _modules_loaded[:] = [reload(val) for val in _modules_loaded] del reload _modules = [ @@ -73,4 +72,5 @@ def unregister(): from bpy.utils import unregister_class for mod in reversed(_modules_loaded): for cls in reversed(mod.classes): - unregister_class(cls) + if cls.is_registered: + unregister_class(cls) diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py index 78fcf0dd124..02fb05e29eb 100644 --- a/release/scripts/startup/bl_operators/anim.py +++ b/release/scripts/startup/bl_operators/anim.py @@ -36,7 +36,7 @@ from bpy.props import ( class ANIM_OT_keying_set_export(Operator): - "Export Keying Set to a python script" + """Export Keying Set to a python script""" bl_idname = "anim.keying_set_export" bl_label = "Export Keying Set..." @@ -102,15 +102,13 @@ class ANIM_OT_keying_set_export(Operator): if ksp.id in id_to_paths_cache: continue - """ - - idtype_list is used to get the list of id-datablocks from - bpy.data.* since this info isn't available elsewhere - - id.bl_rna.name gives a name suitable for UI, - with a capitalised first letter, but we need - the plural form that's all lower case - - special handling is needed for "nested" ID-blocks - (e.g. nodetree in Material) - """ + # - idtype_list is used to get the list of id-datablocks from + # bpy.data.* since this info isn't available elsewhere + # - id.bl_rna.name gives a name suitable for UI, + # with a capitalised first letter, but we need + # the plural form that's all lower case + # - special handling is needed for "nested" ID-blocks + # (e.g. nodetree in Material) if ksp.id.bl_rna.identifier.startswith("ShaderNodeTree"): # Find material or lamp using this node tree... id_bpy_path = "bpy.data.nodes[\"%s\"]" diff --git a/release/scripts/startup/bl_operators/clip.py b/release/scripts/startup/bl_operators/clip.py index e82bc0bf2de..e52d577b900 100644 --- a/release/scripts/startup/bl_operators/clip.py +++ b/release/scripts/startup/bl_operators/clip.py @@ -21,7 +21,10 @@ import bpy import os from bpy.types import Operator from bpy.props import FloatProperty -from mathutils import Vector, Matrix +from mathutils import ( + Vector, + Matrix, +) def CLIP_spaces_walk(context, all_screens, tarea, tspace, callback, *args): @@ -1084,4 +1087,4 @@ classes = ( CLIP_OT_track_settings_as_default, CLIP_OT_track_settings_to_track, CLIP_OT_track_to_empty, -)
\ No newline at end of file +) diff --git a/release/scripts/startup/bl_operators/freestyle.py b/release/scripts/startup/bl_operators/freestyle.py index d8cffb7f0ff..2e46160aeeb 100644 --- a/release/scripts/startup/bl_operators/freestyle.py +++ b/release/scripts/startup/bl_operators/freestyle.py @@ -16,13 +16,15 @@ # # ##### END GPL LICENSE BLOCK ##### +# <pep8 compliant> + import bpy from bpy.props import ( - BoolProperty, - EnumProperty, - StringProperty, - ) + BoolProperty, + EnumProperty, + StringProperty, +) class SCENE_OT_freestyle_fill_range_by_selection(bpy.types.Operator): diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py index bce38a6bf3a..4edefd7bf9b 100644 --- a/release/scripts/startup/bl_operators/mesh.py +++ b/release/scripts/startup/bl_operators/mesh.py @@ -21,7 +21,10 @@ import bpy from bpy.types import Operator -from bpy.props import EnumProperty, IntProperty +from bpy.props import ( + EnumProperty, + IntProperty, +) class MeshMirrorUV(Operator): @@ -254,4 +257,4 @@ classes = ( MeshMirrorUV, MeshSelectNext, MeshSelectPrev, -)
\ No newline at end of file +) diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py index 7b280507bbb..40876e2b069 100644 --- a/release/scripts/startup/bl_operators/node.py +++ b/release/scripts/startup/bl_operators/node.py @@ -21,16 +21,16 @@ import bpy import nodeitems_utils from bpy.types import ( - Operator, - PropertyGroup, - ) + Operator, + PropertyGroup, +) from bpy.props import ( - BoolProperty, - CollectionProperty, - EnumProperty, - IntProperty, - StringProperty, - ) + BoolProperty, + CollectionProperty, + EnumProperty, + IntProperty, + StringProperty, +) class NodeSetting(PropertyGroup): diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index 7e9be607281..3a42d8d2e78 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -21,12 +21,12 @@ import bpy from bpy.types import Operator from bpy.props import ( - StringProperty, - BoolProperty, - EnumProperty, - IntProperty, - FloatProperty, - ) + BoolProperty, + EnumProperty, + FloatProperty, + IntProperty, + StringProperty, +) class SelectPattern(Operator): @@ -1052,4 +1052,4 @@ classes = ( SubdivisionSet, TransformsToDeltas, TransformsToDeltasAnim, -)
\ No newline at end of file +) diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index a088898b14d..1539ffb3545 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -26,13 +26,14 @@ from mathutils import Vector def GlobalBB_LQ(bb_world): # Initialize the variables with the 8th vertex - left, right, front, back, down, up = (bb_world[7][0], - bb_world[7][0], - bb_world[7][1], - bb_world[7][1], - bb_world[7][2], - bb_world[7][2], - ) + left, right, front, back, down, up = ( + bb_world[7][0], + bb_world[7][0], + bb_world[7][1], + bb_world[7][1], + bb_world[7][2], + bb_world[7][2], + ) # Test against the other 7 verts for i in range(7): @@ -398,13 +399,15 @@ class AlignObjects(Operator): def execute(self, context): align_axis = self.align_axis - ret = align_objects(context, - 'X' in align_axis, - 'Y' in align_axis, - 'Z' in align_axis, - self.align_mode, - self.relative_to, - self.bb_quality) + ret = align_objects( + context, + 'X' in align_axis, + 'Y' in align_axis, + 'Z' in align_axis, + self.align_mode, + self.relative_to, + self.bb_quality, + ) if not ret: self.report({'WARNING'}, "No objects with bound-box selected") @@ -415,4 +418,4 @@ class AlignObjects(Operator): classes = ( AlignObjects, -)
\ No newline at end of file +) diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index 57d7f03fcd4..16f29c77bb9 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -22,12 +22,12 @@ from mathutils import Vector import bpy from bpy.types import Operator from bpy.props import ( - BoolProperty, - EnumProperty, - IntProperty, - FloatProperty, - FloatVectorProperty, - ) + BoolProperty, + EnumProperty, + IntProperty, + FloatProperty, + FloatVectorProperty, +) def object_ensure_material(obj, mat_name): @@ -652,4 +652,4 @@ classes = ( QuickFluid, QuickFur, QuickSmoke, -)
\ No newline at end of file +) diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py index 639a558fbab..6792d525683 100644 --- a/release/scripts/startup/bl_operators/rigidbody.py +++ b/release/scripts/startup/bl_operators/rigidbody.py @@ -20,8 +20,10 @@ import bpy from bpy.types import Operator -from bpy.props import IntProperty -from bpy.props import EnumProperty +from bpy.props import ( + EnumProperty, + IntProperty, +) class CopyRigidbodySettings(Operator): @@ -315,4 +317,4 @@ classes = ( BakeToKeyframes, ConnectRigidBodies, CopyRigidbodySettings, -)
\ No newline at end of file +) diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py index 1dd5b78d599..5581415c083 100644 --- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py +++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py @@ -18,7 +18,11 @@ # TODO <pep8 compliant> -from mathutils import Matrix, Vector, geometry +from mathutils import ( + Matrix, + Vector, + geometry, +) import bpy from bpy.types import Operator @@ -1104,4 +1108,4 @@ class SmartProject(Operator): classes = ( SmartProject, -)
\ No newline at end of file +) diff --git a/release/scripts/startup/bl_operators/view3d.py b/release/scripts/startup/bl_operators/view3d.py index acec2d8fe91..18f91110053 100644 --- a/release/scripts/startup/bl_operators/view3d.py +++ b/release/scripts/startup/bl_operators/view3d.py @@ -24,7 +24,7 @@ from bpy.props import BoolProperty class VIEW3D_OT_edit_mesh_extrude_individual_move(Operator): - "Extrude individual elements and move" + """Extrude individual elements and move""" bl_label = "Extrude Individual and Move" bl_idname = "view3d.edit_mesh_extrude_individual_move" @@ -62,7 +62,7 @@ class VIEW3D_OT_edit_mesh_extrude_individual_move(Operator): class VIEW3D_OT_edit_mesh_extrude_move(Operator): - "Extrude and move along normals" + """Extrude and move along normals""" bl_label = "Extrude and Move on Normals" bl_idname = "view3d.edit_mesh_extrude_move_normal" @@ -111,7 +111,7 @@ class VIEW3D_OT_edit_mesh_extrude_move(Operator): class VIEW3D_OT_edit_mesh_extrude_shrink_fatten(Operator): - "Extrude and move along individual normals" + """Extrude and move along individual normals""" bl_label = "Extrude and Move on Individual Normals" bl_idname = "view3d.edit_mesh_extrude_move_shrink_fatten" @@ -128,7 +128,7 @@ class VIEW3D_OT_edit_mesh_extrude_shrink_fatten(Operator): class VIEW3D_OT_select_or_deselect_all(Operator): - "Select element under the mouse, deselect everything is there's nothing under the mouse" + """Select element under the mouse, deselect everything is there's nothing under the mouse""" bl_label = "Select or Deselect All" bl_idname = "view3d.select_or_deselect_all" bl_options = {'UNDO'} @@ -220,4 +220,4 @@ classes = ( VIEW3D_OT_edit_mesh_extrude_move, VIEW3D_OT_edit_mesh_extrude_shrink_fatten, VIEW3D_OT_select_or_deselect_all, -)
\ No newline at end of file +) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 42f1e723d1a..20586b727d5 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -21,12 +21,12 @@ import bpy from bpy.types import Operator from bpy.props import ( - StringProperty, - BoolProperty, - IntProperty, - FloatProperty, - EnumProperty, - ) + StringProperty, + BoolProperty, + IntProperty, + FloatProperty, + EnumProperty, +) from bpy.app.translations import pgettext_tip as tip_ @@ -130,6 +130,20 @@ def execute_context_assign(self, context): return operator_path_undo_return(context, data_path) +def module_filesystem_remove(path_base, module_name): + import os + module_name = os.path.splitext(module_name)[0] + for f in os.listdir(path_base): + f_base = os.path.splitext(f)[0] + if f_base == module_name: + f_full = os.path.join(path_base, f) + + if os.path.isdir(f_full): + os.rmdir(f_full) + else: + os.remove(f_full) + + class BRUSH_OT_active_index_set(Operator): """Set active sculpt/paint brush from it's number""" bl_idname = "brush.active_index_set" @@ -831,7 +845,7 @@ class WM_OT_context_modal_mouse(Operator): class WM_OT_url_open(Operator): - "Open a website in the web-browser" + """Open a website in the web-browser""" bl_idname = "wm.url_open" bl_label = "" bl_options = {'INTERNAL'} @@ -848,7 +862,7 @@ class WM_OT_url_open(Operator): class WM_OT_path_open(Operator): - "Open a path in a file browser" + """Open a path in a file browser""" bl_idname = "wm.path_open" bl_label = "" bl_options = {'INTERNAL'} @@ -907,7 +921,10 @@ def _wm_doc_get_id(doc_id, do_url=True, url_prefix=""): # an operator (common case - just button referencing an op) if hasattr(bpy.types, class_name.upper() + "_OT_" + class_prop): if do_url: - url = ("%s/bpy.ops.%s.html#bpy.ops.%s.%s" % (url_prefix, class_name, class_name, class_prop)) + url = ( + "%s/bpy.ops.%s.html#bpy.ops.%s.%s" % + (url_prefix, class_name, class_name, class_prop) + ) else: rna = "bpy.ops.%s.%s" % (class_name, class_prop) else: @@ -922,7 +939,10 @@ def _wm_doc_get_id(doc_id, do_url=True, url_prefix=""): class_name, class_prop = class_name.split("_OT_", 1) class_name = class_name.lower() if do_url: - url = ("%s/bpy.ops.%s.html#bpy.ops.%s.%s" % (url_prefix, class_name, class_name, class_prop)) + url = ( + "%s/bpy.ops.%s.html#bpy.ops.%s.%s" % + (url_prefix, class_name, class_name, class_prop) + ) else: rna = "bpy.ops.%s.%s" % (class_name, class_prop) else: @@ -938,9 +958,12 @@ def _wm_doc_get_id(doc_id, do_url=True, url_prefix=""): rna_parent = rna_parent.base if do_url: - url = ("%s/bpy.types.%s.html#bpy.types.%s.%s" % (url_prefix, class_name, class_name, class_prop)) + url = ( + "%s/bpy.types.%s.html#bpy.types.%s.%s" % + (url_prefix, class_name, class_name, class_prop) + ) else: - rna = ("bpy.types.%s.%s" % (class_name, class_prop)) + rna = "bpy.types.%s.%s" % (class_name, class_prop) else: # We assume this is custom property, only try to generate generic url/rna_id... if do_url: @@ -1087,10 +1110,10 @@ class WM_OT_properties_edit(Operator): def execute(self, context): from rna_prop_ui import ( - rna_idprop_ui_prop_get, - rna_idprop_ui_prop_clear, - rna_idprop_ui_prop_update, - ) + rna_idprop_ui_prop_get, + rna_idprop_ui_prop_clear, + rna_idprop_ui_prop_update, + ) data_path = self.data_path value = self.value @@ -1267,9 +1290,9 @@ class WM_OT_properties_add(Operator): def execute(self, context): from rna_prop_ui import ( - rna_idprop_ui_prop_get, - rna_idprop_ui_prop_update, - ) + rna_idprop_ui_prop_get, + rna_idprop_ui_prop_update, + ) data_path = self.data_path item = eval("context.%s" % data_path) @@ -1284,10 +1307,10 @@ class WM_OT_properties_add(Operator): return prop_new - prop = unique_name( - {*item.keys(), - *type(item).bl_rna.properties.keys(), - }) + prop = unique_name({ + *item.keys(), + *type(item).bl_rna.properties.keys(), + }) item[prop] = 1.0 rna_idprop_ui_prop_update(item, prop) @@ -1301,7 +1324,7 @@ class WM_OT_properties_add(Operator): class WM_OT_properties_context_change(Operator): - "Jump to a different tab inside the properties editor" + """Jump to a different tab inside the properties editor""" bl_idname = "wm.properties_context_change" bl_label = "" bl_options = {'INTERNAL'} @@ -1327,9 +1350,9 @@ class WM_OT_properties_remove(Operator): def execute(self, context): from rna_prop_ui import ( - rna_idprop_ui_prop_clear, - rna_idprop_ui_prop_update, - ) + rna_idprop_ui_prop_clear, + rna_idprop_ui_prop_update, + ) data_path = self.data_path item = eval("context.%s" % data_path) prop = self.property @@ -1367,7 +1390,10 @@ class WM_OT_appconfig_default(Operator): filepath = os.path.join(bpy.utils.preset_paths("interaction")[0], "blender.py") if os.path.exists(filepath): - bpy.ops.script.execute_preset(filepath=filepath, menu_idname="USERPREF_MT_interaction_presets") + bpy.ops.script.execute_preset( + filepath=filepath, + menu_idname="USERPREF_MT_interaction_presets", + ) return {'FINISHED'} @@ -1387,7 +1413,10 @@ class WM_OT_appconfig_activate(Operator): filepath = self.filepath.replace("keyconfig", "interaction") if os.path.exists(filepath): - bpy.ops.script.execute_preset(filepath=filepath, menu_idname="USERPREF_MT_interaction_presets") + bpy.ops.script.execute_preset( + filepath=filepath, + menu_idname="USERPREF_MT_interaction_presets", + ) return {'FINISHED'} @@ -1492,7 +1521,7 @@ class WM_OT_blenderplayer_start(Operator): "-g", "show_profile", "=", "%d" % gs.show_framerate_profile, "-g", "show_properties", "=", "%d" % gs.show_debug_properties, "-g", "ignore_deprecation_warnings", "=", "%d" % (not gs.use_deprecation_warnings), - ]) + ]) # finish the call with the path to the blend file args.append(filepath) @@ -1503,7 +1532,7 @@ class WM_OT_blenderplayer_start(Operator): class WM_OT_keyconfig_test(Operator): - "Test key-config for conflicts" + """Test key-config for conflicts""" bl_idname = "wm.keyconfig_test" bl_label = "Test Key Configuration for Conflicts" @@ -1520,7 +1549,7 @@ class WM_OT_keyconfig_test(Operator): class WM_OT_keyconfig_import(Operator): - "Import key configuration from a python script" + """Import key configuration from a python script""" bl_idname = "wm.keyconfig_import" bl_label = "Import Key Configuration..." @@ -1587,7 +1616,7 @@ class WM_OT_keyconfig_import(Operator): class WM_OT_keyconfig_export(Operator): - "Export key configuration to a python script" + """Export key configuration to a python script""" bl_idname = "wm.keyconfig_export" bl_label = "Export Key Configuration..." @@ -1622,10 +1651,11 @@ class WM_OT_keyconfig_export(Operator): wm = context.window_manager - keyconfig_utils.keyconfig_export(wm, - wm.keyconfigs.active, - self.filepath, - ) + keyconfig_utils.keyconfig_export( + wm, + wm.keyconfigs.active, + self.filepath, + ) return {'FINISHED'} @@ -1636,7 +1666,7 @@ class WM_OT_keyconfig_export(Operator): class WM_OT_keymap_restore(Operator): - "Restore key map(s)" + """Restore key map(s)""" bl_idname = "wm.keymap_restore" bl_label = "Restore Key Map(s)" @@ -1659,7 +1689,7 @@ class WM_OT_keymap_restore(Operator): class WM_OT_keyitem_restore(Operator): - "Restore key map item" + """Restore key map item""" bl_idname = "wm.keyitem_restore" bl_label = "Restore Key Map Item" @@ -1684,7 +1714,7 @@ class WM_OT_keyitem_restore(Operator): class WM_OT_keyitem_add(Operator): - "Add key map item" + """Add key map item""" bl_idname = "wm.keyitem_add" bl_label = "Add Key Map Item" @@ -1706,7 +1736,7 @@ class WM_OT_keyitem_add(Operator): class WM_OT_keyitem_remove(Operator): - "Remove key map item" + """Remove key map item""" bl_idname = "wm.keyitem_remove" bl_label = "Remove Key Map Item" @@ -1727,7 +1757,7 @@ class WM_OT_keyitem_remove(Operator): class WM_OT_keyconfig_remove(Operator): - "Remove key config" + """Remove key config""" bl_idname = "wm.keyconfig_remove" bl_label = "Remove Key Config" @@ -1745,6 +1775,7 @@ class WM_OT_keyconfig_remove(Operator): class WM_OT_operator_cheat_sheet(Operator): + """List all the Operators in a text-block, useful for scripting""" bl_idname = "wm.operator_cheat_sheet" bl_label = "Operator Cheat Sheet" @@ -1773,7 +1804,7 @@ class WM_OT_operator_cheat_sheet(Operator): # Add-on Operators class WM_OT_addon_enable(Operator): - "Enable an add-on" + """Enable an add-on""" bl_idname = "wm.addon_enable" bl_label = "Enable Add-on" @@ -1817,7 +1848,7 @@ class WM_OT_addon_enable(Operator): class WM_OT_addon_disable(Operator): - "Disable an add-on" + """Disable an add-on""" bl_idname = "wm.addon_disable" bl_label = "Disable Add-on" @@ -1846,7 +1877,7 @@ class WM_OT_addon_disable(Operator): class WM_OT_theme_install(Operator): - "Load and apply a Blender XML theme file" + """Load and apply a Blender XML theme file""" bl_idname = "wm.theme_install" bl_label = "Install Theme..." @@ -1890,7 +1921,10 @@ class WM_OT_theme_install(Operator): try: shutil.copyfile(xmlfile, path_dest) - bpy.ops.script.execute_preset(filepath=path_dest, menu_idname="USERPREF_MT_interface_theme_presets") + bpy.ops.script.execute_preset( + filepath=path_dest, + menu_idname="USERPREF_MT_interface_theme_presets", + ) except: traceback.print_exc() @@ -1905,7 +1939,7 @@ class WM_OT_theme_install(Operator): class WM_OT_addon_refresh(Operator): - "Scan add-on directories for new modules" + """Scan add-on directories for new modules""" bl_idname = "wm.addon_refresh" bl_label = "Refresh" @@ -1917,10 +1951,12 @@ class WM_OT_addon_refresh(Operator): return {'FINISHED'} +# Note: shares some logic with WM_OT_app_template_install +# but not enough to de-duplicate. Fixed here may apply to both. class WM_OT_addon_install(Operator): - "Install an add-on" + """Install an add-on""" bl_idname = "wm.addon_install" - bl_label = "Install from File..." + bl_label = "Install Add-on from File..." overwrite = BoolProperty( name="Overwrite", @@ -1951,20 +1987,6 @@ class WM_OT_addon_install(Operator): options={'HIDDEN'}, ) - @staticmethod - def _module_remove(path_addons, module): - import os - module = os.path.splitext(module)[0] - for f in os.listdir(path_addons): - f_base = os.path.splitext(f)[0] - if f_base == module: - f_full = os.path.join(path_addons, f) - - if os.path.isdir(f_full): - os.rmdir(f_full) - else: - os.remove(f_full) - def execute(self, context): import addon_utils import traceback @@ -2017,7 +2039,7 @@ class WM_OT_addon_install(Operator): if self.overwrite: for f in file_to_extract.namelist(): - WM_OT_addon_install._module_remove(path_addons, f) + module_filesystem_remove(path_addons, f) else: for f in file_to_extract.namelist(): path_dest = os.path.join(path_addons, os.path.basename(f)) @@ -2035,7 +2057,7 @@ class WM_OT_addon_install(Operator): path_dest = os.path.join(path_addons, os.path.basename(pyfile)) if self.overwrite: - WM_OT_addon_install._module_remove(path_addons, os.path.basename(pyfile)) + module_filesystem_remove(path_addons, os.path.basename(pyfile)) elif os.path.exists(path_dest): self.report({'WARNING'}, "File already installed to %r\n" % path_dest) return {'CANCELLED'} @@ -2070,7 +2092,10 @@ class WM_OT_addon_install(Operator): bpy.utils.refresh_script_paths() # print message - msg = tip_("Modules Installed from %r into %r (%s)") % (pyfile, path_addons, ", ".join(sorted(addons_new))) + msg = ( + tip_("Modules Installed (%s) from %r into %r") % + (", ".join(sorted(addons_new)), pyfile, path_addons) + ) print(msg) self.report({'INFO'}, msg) @@ -2083,7 +2108,7 @@ class WM_OT_addon_install(Operator): class WM_OT_addon_remove(Operator): - "Delete the add-on from the file system" + """Delete the add-on from the file system""" bl_idname = "wm.addon_remove" bl_label = "Remove Add-on" @@ -2142,7 +2167,7 @@ class WM_OT_addon_remove(Operator): class WM_OT_addon_expand(Operator): - "Display information and preferences for this add-on" + """Display information and preferences for this add-on""" bl_idname = "wm.addon_expand" bl_label = "" bl_options = {'INTERNAL'} @@ -2164,8 +2189,9 @@ class WM_OT_addon_expand(Operator): return {'FINISHED'} + class WM_OT_addon_userpref_show(Operator): - "Show add-on user preferences" + """Show add-on user preferences""" bl_idname = "wm.addon_userpref_show" bl_label = "" bl_options = {'INTERNAL'} @@ -2194,6 +2220,107 @@ class WM_OT_addon_userpref_show(Operator): return {'FINISHED'} +# Note: shares some logic with WM_OT_addon_install +# but not enough to de-duplicate. Fixes here may apply to both. +class WM_OT_app_template_install(Operator): + """Install an application-template""" + bl_idname = "wm.app_template_install" + bl_label = "Install Template from File..." + + overwrite = BoolProperty( + name="Overwrite", + description="Remove existing template with the same ID", + default=True, + ) + + filepath = StringProperty( + subtype='FILE_PATH', + ) + filter_folder = BoolProperty( + name="Filter folders", + default=True, + options={'HIDDEN'}, + ) + filter_glob = StringProperty( + default="*.zip", + options={'HIDDEN'}, + ) + + def execute(self, context): + import traceback + import zipfile + import shutil + import os + + filepath = self.filepath + + path_app_templates = bpy.utils.user_resource( + 'SCRIPTS', os.path.join("startup", "bl_app_templates_user"), + create=True, + ) + + if not path_app_templates: + self.report({'ERROR'}, "Failed to get add-ons path") + return {'CANCELLED'} + + if not os.path.isdir(path_app_templates): + try: + os.makedirs(path_app_templates, exist_ok=True) + except: + traceback.print_exc() + + app_templates_old = set(os.listdir(path_app_templates)) + + # check to see if the file is in compressed format (.zip) + if zipfile.is_zipfile(filepath): + try: + file_to_extract = zipfile.ZipFile(filepath, 'r') + except: + traceback.print_exc() + return {'CANCELLED'} + + if self.overwrite: + for f in file_to_extract.namelist(): + module_filesystem_remove(path_app_templates, f) + else: + for f in file_to_extract.namelist(): + path_dest = os.path.join(path_app_templates, os.path.basename(f)) + if os.path.exists(path_dest): + self.report({'WARNING'}, "File already installed to %r\n" % path_dest) + return {'CANCELLED'} + + try: # extract the file to "bl_app_templates_user" + file_to_extract.extractall(path_app_templates) + except: + traceback.print_exc() + return {'CANCELLED'} + + else: + # Only support installing zipfiles + self.report({'WARNING'}, "Expected a zip-file %r\n" % filepath) + return {'CANCELLED'} + + app_templates_new = set(os.listdir(path_app_templates)) - app_templates_old + + # in case a new module path was created to install this addon. + bpy.utils.refresh_script_paths() + + # print message + msg = ( + tip_("Template Installed (%s) from %r into %r") % + (", ".join(sorted(app_templates_new)), filepath, path_app_templates) + ) + print(msg) + self.report({'INFO'}, msg) + + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + + classes = ( BRUSH_OT_active_index_set, WM_OT_addon_disable, @@ -2203,6 +2330,7 @@ classes = ( WM_OT_addon_refresh, WM_OT_addon_remove, WM_OT_addon_userpref_show, + WM_OT_app_template_install, WM_OT_appconfig_activate, WM_OT_appconfig_default, WM_OT_blenderplayer_start, @@ -2246,4 +2374,4 @@ classes = ( WM_OT_sysinfo, WM_OT_theme_install, WM_OT_url_open, -)
\ No newline at end of file +) diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index 3e81724c1f9..5b609605cee 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -23,8 +23,7 @@ # support reloading sub-modules if "bpy" in locals(): from importlib import reload - for val in _modules_loaded: - reload(val) + _modules_loaded[:] = [reload(val) for val in _modules_loaded] del reload _modules = [ @@ -149,7 +148,8 @@ def unregister(): from bpy.utils import unregister_class for mod in reversed(_modules_loaded): for cls in reversed(mod.classes): - unregister_class(cls) + if cls.is_registered: + unregister_class(cls) # Define a default UIList, when a list does not need any custom drawing... # Keep in sync with its #defined name in UI_interface.h diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index a098953699e..a37d61dd0af 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -569,6 +569,14 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "use_mirror_u", text="U") col.prop(md, "use_mirror_v", text="V") + col = layout.column(align=True) + + if md.use_mirror_u: + col.prop(md, "mirror_offset_u") + + if md.use_mirror_v: + col.prop(md, "mirror_offset_v") + col = layout.column() if md.use_mirror_merge is True: diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index b274657b4f4..c748e71a0a2 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -18,6 +18,7 @@ # <pep8 compliant> import bpy +import math from bpy.types import Header, Menu, Panel from bl_ui.properties_paint_common import ( UnifiedPaintPanel, @@ -727,11 +728,73 @@ class IMAGE_PT_tools_transform_uvs(Panel, UVToolsPanel): col.operator("transform.translate") col.operator("transform.rotate") col.operator("transform.resize", text="Scale") - col.separator() - col.operator("transform.shear") +class IMAGE_PT_tools_align_uvs(Panel, UVToolsPanel): + bl_label = "UV Align" + + @classmethod + def poll(cls, context): + sima = context.space_data + return sima.show_uvedit and not context.tool_settings.use_uv_sculpt + + def draw(self, context): + layout = self.layout + layout.operator_context = 'EXEC_REGION_WIN' + + split = layout.split() + col = split.column(align=True) + col.operator("transform.mirror", text="Mirror X").constraint_axis[0] = True + col.operator("transform.mirror", text="Mirror Y").constraint_axis[1] = True + col = split.column(align=True) + col.operator("transform.rotate", text="Rotate +90°").value = math.pi / 2 + col.operator("transform.rotate", text="Rotate - 90°").value = math.pi / -2 + + split = layout.split() + col = split.column(align=True) + col.operator("uv.align", text="Straighten").axis = 'ALIGN_S' + col.operator("uv.align", text="Straighten X").axis = 'ALIGN_T' + col.operator("uv.align", text="Straighten Y").axis = 'ALIGN_U' + col = split.column(align=True) + col.operator("uv.align", text="Align Auto").axis = 'ALIGN_AUTO' + col.operator("uv.align", text="Align X").axis = 'ALIGN_X' + col.operator("uv.align", text="Align Y").axis = 'ALIGN_Y' + + +class IMAGE_PT_tools_uvs(Panel, UVToolsPanel): + bl_label = "UV Tools" + + @classmethod + def poll(cls, context): + sima = context.space_data + return sima.show_uvedit and not context.tool_settings.use_uv_sculpt + + def draw(self, context): + layout = self.layout + + col = layout.column(align=True) + row = col.row(align=True) + row.operator("uv.weld") + row.operator("uv.stitch") + col.operator("uv.remove_doubles") + col.operator("uv.average_islands_scale") + col.operator("uv.pack_islands") + col.operator("mesh.faces_mirror_uv") + col.operator("uv.minimize_stretch") + + layout.label(text="UV Unwrap:") + row = layout.row(align=True) + row.operator("uv.pin").clear = False + row.operator("uv.pin", text="Unpin").clear = True + col = layout.column(align=True) + row = col.row(align=True) + row.operator("uv.mark_seam", text="Mark Seam").clear = False + row.operator("uv.mark_seam", text="Clear Seam").clear = True + col.operator("uv.seams_from_islands", text="Mark Seams from Islands") + col.operator("uv.unwrap") + + class IMAGE_PT_paint(Panel, ImagePaintPanel): bl_label = "Paint" bl_category = "Tools" @@ -1100,6 +1163,29 @@ class IMAGE_PT_tools_mask(MASK_PT_tools, Panel): # --- end mask --- +class IMAGE_PT_options_uvs(Panel, UVToolsPanel): + bl_label = "UV Options" + bl_category = "Options" + + @classmethod + def poll(cls, context): + sima = context.space_data + return sima.show_uvedit + + def draw(self, context): + layout = self.layout + + sima = context.space_data + uv = sima.uv_editor + toolsettings = context.tool_settings + + col = layout.column(align=True) + col.prop(toolsettings, "use_uv_sculpt") + col.prop(uv, "use_live_unwrap") + col.prop(uv, "use_snap_to_pixels") + col.prop(uv, "lock_bounds") + + class ImageScopesPanel: @classmethod def poll(cls, context): @@ -1267,6 +1353,9 @@ classes = ( IMAGE_PT_game_properties, IMAGE_PT_view_properties, IMAGE_PT_tools_transform_uvs, + IMAGE_PT_tools_align_uvs, + IMAGE_PT_tools_uvs, + IMAGE_PT_options_uvs, IMAGE_PT_paint, IMAGE_PT_tools_brush_overlay, IMAGE_PT_tools_brush_texture, diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index 16ac6339504..a7b518dfd2e 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -127,6 +127,18 @@ class INFO_MT_file(Menu): layout.operator("wm.save_homefile", icon='SAVE_PREFS') layout.operator("wm.read_factory_settings", icon='LOAD_FACTORY') + if any(bpy.utils.app_template_paths()): + app_template = context.user_preferences.app_template + if app_template: + layout.operator( + "wm.read_factory_settings", + text="Load Factory Template Settings", + icon='LOAD_FACTORY', + ).app_template = app_template + del app_template + + layout.menu("USERPREF_MT_app_templates", icon='FILE_BLEND') + layout.separator() layout.operator_context = 'INVOKE_AREA' diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index fe126f6522c..5ed481a215a 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -90,6 +90,63 @@ class USERPREF_MT_interaction_presets(Menu): draw = Menu.draw_preset +class USERPREF_MT_app_templates(Menu): + bl_label = "Application Templates" + preset_subdir = "app_templates" + + def draw_ex(self, context, *, use_splash=False, use_default=False, use_install=False): + import os + + layout = self.layout + + # now draw the presets + layout.operator_context = 'EXEC_DEFAULT' + + if use_default: + props = layout.operator("wm.read_homefile", text="Default") + props.use_splash = True + props.app_template = "" + layout.separator() + + template_paths = bpy.utils.app_template_paths() + + # expand template paths + app_templates = [] + for path in template_paths: + for d in os.listdir(path): + if d.startswith(("__", ".")): + continue + template = os.path.join(path, d) + if os.path.isdir(template): + # template_paths_expand.append(template) + app_templates.append(d) + + for d in sorted(app_templates): + props = layout.operator( + "wm.read_homefile", + text=bpy.path.display_name(d), + ) + props.use_splash = True + props.app_template = d; + + if use_install: + layout.separator() + layout.operator_context = 'INVOKE_DEFAULT' + props = layout.operator("wm.app_template_install") + + + def draw(self, context): + self.draw_ex(context, use_splash=False, use_default=True, use_install=True) + + +class USERPREF_MT_templates_splash(Menu): + bl_label = "Startup Templates" + preset_subdir = "templates" + + def draw(self, context): + USERPREF_MT_app_templates.draw_ex(self, context, use_splash=True, use_default=True) + + class USERPREF_MT_appconfigs(Menu): bl_label = "AppPresets" preset_subdir = "keyconfig" @@ -110,7 +167,17 @@ class USERPREF_MT_splash(Menu): split = layout.split() row = split.row() - row.label("") + + if any(bpy.utils.app_template_paths()): + row.label("Template:") + template = context.user_preferences.app_template + row.menu( + "USERPREF_MT_templates_splash", + text=bpy.path.display_name(template) if template else "Default", + ) + else: + row.label("") + row = split.row() row.label("Interaction:") @@ -150,6 +217,7 @@ class USERPREF_PT_interface(Panel): col = row.column() col.label(text="Display:") + col.prop(view, "ui_scale", text="Scale") col.prop(view, "show_tooltips") col.prop(view, "show_tooltips_python") col.prop(view, "show_object_info", text="Object Info") @@ -400,11 +468,6 @@ class USERPREF_PT_system(Panel): col = colsplit.column() col.label(text="General:") - col.prop(system, "dpi") - col.label("Virtual Pixel Mode:") - col.prop(system, "virtual_pixel_mode", text="") - - col.separator() col.prop(system, "frame_server_port") col.prop(system, "scrollback", text="Console Scrollback") @@ -1159,23 +1222,25 @@ class USERPREF_PT_input(Panel): sub = col.column() sub.label(text="View Navigation:") sub.row().prop(inputs, "navigation_mode", expand=True) - if inputs.navigation_mode == 'WALK': - walk = inputs.walk_navigation - sub.prop(walk, "use_mouse_reverse") - sub.prop(walk, "mouse_speed") - sub.prop(walk, "teleport_time") + sub.label(text="Walk Navigation:") - sub = col.column(align=True) - sub.prop(walk, "walk_speed") - sub.prop(walk, "walk_speed_factor") + walk = inputs.walk_navigation - sub.separator() - sub.prop(walk, "use_gravity") - sub = col.column(align=True) - sub.active = walk.use_gravity - sub.prop(walk, "view_height") - sub.prop(walk, "jump_height") + sub.prop(walk, "use_mouse_reverse") + sub.prop(walk, "mouse_speed") + sub.prop(walk, "teleport_time") + + sub = col.column(align=True) + sub.prop(walk, "walk_speed") + sub.prop(walk, "walk_speed_factor") + + sub.separator() + sub.prop(walk, "use_gravity") + sub = col.column(align=True) + sub.active = walk.use_gravity + sub.prop(walk, "view_height") + sub.prop(walk, "jump_height") if inputs.use_ndof: col.separator() @@ -1485,6 +1550,8 @@ classes = ( USERPREF_HT_header, USERPREF_PT_tabs, USERPREF_MT_interaction_presets, + USERPREF_MT_templates_splash, + USERPREF_MT_app_templates, USERPREF_MT_appconfigs, USERPREF_MT_splash, USERPREF_MT_splash_footer, diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index b718228e7b2..f13c7095f67 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1206,6 +1206,16 @@ class INFO_MT_lamp_add(Menu): layout.operator_enum("object.lamp_add", "type") +class INFO_MT_camera_add(Menu): + bl_idname = "INFO_MT_camera_add" + bl_label = "Camera" + + def draw(self, context): + layout = self.layout + layout.operator_context = 'EXEC_REGION_WIN' + layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA') + + class INFO_MT_add(Menu): bl_label = "Add" @@ -1237,7 +1247,11 @@ class INFO_MT_add(Menu): layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER') layout.separator() - layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA') + if INFO_MT_camera_add.is_extended(): + layout.menu("INFO_MT_camera_add", icon='OUTLINER_OB_CAMERA') + else: + INFO_MT_camera_add.draw(self, context) + layout.menu("INFO_MT_lamp_add", icon='OUTLINER_OB_LAMP') layout.separator() @@ -3832,6 +3846,7 @@ classes = ( INFO_MT_edit_armature_add, INFO_MT_armature_add, INFO_MT_lamp_add, + INFO_MT_camera_add, INFO_MT_add, VIEW3D_MT_object, VIEW3D_MT_object_animation, diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index e915aa5bb72..517a0738b44 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -19,7 +19,11 @@ # <pep8 compliant> import bpy import nodeitems_utils -from nodeitems_utils import NodeCategory, NodeItem, NodeItemCustom +from nodeitems_utils import ( + NodeCategory, + NodeItem, + NodeItemCustom, +) # Subclasses for standard node types @@ -153,6 +157,7 @@ shader_node_categories = [ NodeItem("ShaderNodeGeometry"), NodeItem("ShaderNodeExtendedMaterial"), NodeItem("ShaderNodeParticleInfo"), + NodeItem("ShaderNodeObjectInfo"), NodeItem("NodeGroupInput", poll=group_input_output_item_poll), ]), ShaderOldNodeCategory("SH_OUTPUT", "Output", items=[ diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc index 0542255d84b..28e75db2862 100644 --- a/source/blender/alembic/intern/abc_curves.cc +++ b/source/blender/alembic/intern/abc_curves.cc @@ -205,6 +205,7 @@ void AbcCurveReader::readObjectData(Main *bmain, float time) cu->flag |= CU_DEFORM_FILL | CU_3D; cu->actvert = CU_ACT_NONE; + cu->resolu = 1; m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str()); m_object->data = cu; @@ -250,13 +251,18 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time) nu->pntsv = 1; nu->flag |= CU_SMOOTH; - nu->orderu = num_verts; - - if (smp.getType() == Alembic::AbcGeom::kCubic) { - nu->orderu = 3; - } - else if (orders && orders->size() > i) { - nu->orderu = static_cast<short>((*orders)[i] - 1); + switch (smp.getType()) { + case Alembic::AbcGeom::kCubic: + nu->orderu = 4; + break; + case Alembic::AbcGeom::kVariableOrder: + if (orders && orders->size() > i) { + nu->orderu = static_cast<short>((*orders)[i]); + } + break; + case Alembic::AbcGeom::kLinear: + default: + nu->orderu = 2; } if (periodicity == Alembic::AbcGeom::kNonPeriodic) { diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index 61e7712150f..ef3196cb15d 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -66,6 +66,7 @@ using Alembic::Abc::OBox3dProperty; ExportSettings::ExportSettings() : scene(NULL) + , logger() , selected_only(false) , visible_layers_only(false) , renderable_only(false) @@ -123,14 +124,32 @@ static bool object_is_shape(Object *ob) } } -static bool export_object(const ExportSettings * const settings, Object *ob) + +/** + * Returns whether this object should be exported into the Alembic file. + * + * @param settings export settings, used for options like 'selected only'. + * @param ob the object in question. + * @param is_duplicated normally false; true when the object is instanced + * into the scene by a dupli-object (e.g. part of a + * dupligroup). This ignores selection and layer + * visibility, and assumes that the dupli-object itself + * (e.g. the group-instantiating empty) is exported. + */ +static bool export_object(const ExportSettings * const settings, Object *ob, + bool is_duplicated) { - if (settings->selected_only && !parent_selected(ob)) { - return false; - } + if (!is_duplicated) { + /* These two tests only make sense when the object isn't being instanced + * into the scene. When it is, its exportability is determined by + * its dupli-object and the DupliObject::no_draw property. */ + if (settings->selected_only && !parent_selected(ob)) { + return false; + } - if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) { - return false; + if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) { + return false; + } } if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) { @@ -153,11 +172,13 @@ AbcExporter::AbcExporter(Scene *scene, const char *filename, ExportSettings &set AbcExporter::~AbcExporter() { - std::map<std::string, AbcTransformWriter*>::iterator it, e; - for (it = m_xforms.begin(), e = m_xforms.end(); it != e; ++it) { - delete it->second; + /* Free xforms map */ + m_xforms_type::iterator it_x, e_x; + for (it_x = m_xforms.begin(), e_x = m_xforms.end(); it_x != e_x; ++it_x) { + delete it_x->second; } + /* Free shapes vector */ for (int i = 0, e = m_shapes.size(); i != e; ++i) { delete m_shapes[i]; } @@ -269,13 +290,7 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled) OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_writer->archive(), m_trans_sampling_index); - if (m_settings.flatten_hierarchy) { - createTransformWritersFlat(); - } - else { - createTransformWritersHierarchy(bmain->eval_ctx); - } - + createTransformWritersHierarchy(bmain->eval_ctx); createShapeWriters(bmain->eval_ctx); /* Make a list of frames to export. */ @@ -322,7 +337,7 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled) continue; } - std::map<std::string, AbcTransformWriter *>::iterator xit, xe; + m_xforms_type::iterator xit, xe; for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) { xit->second->write(); } @@ -346,34 +361,16 @@ void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx) while (base) { Object *ob = base->object; - if (export_object(&m_settings, ob)) { - switch (ob->type) { - case OB_LAMP: - case OB_LATTICE: - case OB_MBALL: - case OB_SPEAKER: - /* We do not export transforms for objects of these classes. */ - break; - - default: - exploreTransform(eval_ctx, ob, ob->parent, NULL); - } - } - - base = base->next; - } -} + switch (ob->type) { + case OB_LAMP: + case OB_LATTICE: + case OB_MBALL: + case OB_SPEAKER: + /* We do not export transforms for objects of these classes. */ + break; -void AbcExporter::createTransformWritersFlat() -{ - Base *base = static_cast<Base *>(m_scene->base.first); - - while (base) { - Object *ob = base->object; - - if (export_object(&m_settings, ob) && object_is_shape(ob)) { - std::string name = get_id_name(ob); - m_xforms[name] = new AbcTransformWriter(ob, m_writer->archive().getTop(), 0, m_trans_sampling_index, m_settings); + default: + exploreTransform(eval_ctx, ob, ob->parent); } base = base->next; @@ -382,8 +379,13 @@ void AbcExporter::createTransformWritersFlat() void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent) { + /* If an object isn't exported itself, its duplilist shouldn't be + * exported either. */ + if (!export_object(&m_settings, ob, dupliObParent != NULL)) { + return; + } - if (export_object(&m_settings, ob) && object_is_shape(ob)) { + if (object_is_shape(ob)) { createTransformWriter(ob, parent, dupliObParent); } @@ -394,68 +396,91 @@ void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Obje Object *dupli_ob = NULL; Object *dupli_parent = NULL; - while (link) { + for (; link; link = link->next) { + /* This skips things like custom bone shapes. */ + if (m_settings.renderable_only && link->no_draw) { + continue; + } + if (link->type == OB_DUPLIGROUP) { dupli_ob = link->ob; dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob; exploreTransform(eval_ctx, dupli_ob, dupli_parent, ob); } - - link = link->next; } } free_object_duplilist(lb); } -void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent) +AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent) { - const std::string name = get_object_dag_path_name(ob, dupliObParent); - /* An object should not be its own parent, or we'll get infinite loops. */ BLI_assert(ob != parent); BLI_assert(ob != dupliObParent); - /* check if we have already created a transform writer for this object */ - if (getXForm(name) != NULL){ - std::cerr << "xform " << name << " already exists\n"; - return; + std::string name; + if (m_settings.flatten_hierarchy) { + name = get_id_name(ob); + } + else { + name = get_object_dag_path_name(ob, dupliObParent); } - AbcTransformWriter *parent_xform = NULL; + /* check if we have already created a transform writer for this object */ + AbcTransformWriter *my_writer = getXForm(name); + if (my_writer != NULL){ + return my_writer; + } - if (parent) { - const std::string parentname = get_object_dag_path_name(parent, dupliObParent); - parent_xform = getXForm(parentname); + AbcTransformWriter *parent_writer = NULL; + Alembic::Abc::OObject alembic_parent; - if (!parent_xform) { - if (parent->parent) { - createTransformWriter(parent, parent->parent, dupliObParent); + if (m_settings.flatten_hierarchy || parent == NULL) { + /* Parentless objects still have the "top object" as parent + * in Alembic. */ + alembic_parent = m_writer->archive().getTop(); + } + else { + /* Since there are so many different ways to find parents (as evident + * in the number of conditions below), we can't really look up the + * parent by name. We'll just call createTransformWriter(), which will + * return the parent's AbcTransformWriter pointer. */ + if (parent->parent) { + if (parent == dupliObParent) { + parent_writer = createTransformWriter(parent, parent->parent, NULL); + } + else { + parent_writer = createTransformWriter(parent, parent->parent, dupliObParent); } - else if (parent == dupliObParent) { - if (dupliObParent->parent == NULL) { - createTransformWriter(parent, NULL, NULL); - } - else { - createTransformWriter(parent, dupliObParent->parent, dupliObParent->parent); - } + } + else if (parent == dupliObParent) { + if (dupliObParent->parent == NULL) { + parent_writer = createTransformWriter(parent, NULL, NULL); } else { - createTransformWriter(parent, dupliObParent, dupliObParent); + parent_writer = createTransformWriter(parent, dupliObParent->parent, dupliObParent->parent); } - - parent_xform = getXForm(parentname); } - } + else { + parent_writer = createTransformWriter(parent, dupliObParent, dupliObParent); + } - if (parent_xform) { - m_xforms[name] = new AbcTransformWriter(ob, parent_xform->alembicXform(), parent_xform, m_trans_sampling_index, m_settings); - m_xforms[name]->setParent(parent); + BLI_assert(parent_writer); + alembic_parent = parent_writer->alembicXform(); } - else { - m_xforms[name] = new AbcTransformWriter(ob, m_writer->archive().getTop(), NULL, m_trans_sampling_index, m_settings); + + my_writer = new AbcTransformWriter(ob, alembic_parent, parent_writer, + m_trans_sampling_index, m_settings); + + /* When flattening, the matrix of the dupliobject has to be added. */ + if (m_settings.flatten_hierarchy && dupliObParent) { + my_writer->m_proxy_from = dupliObParent; } + + m_xforms[name] = my_writer; + return my_writer; } void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx) @@ -472,19 +497,28 @@ void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx) void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent) { - ListBase *lb = object_duplilist(eval_ctx, m_scene, ob); - + /* If an object isn't exported itself, its duplilist shouldn't be + * exported either. */ + if (!export_object(&m_settings, ob, dupliObParent != NULL)) { + return; + } + createShapeWriter(ob, dupliObParent); + ListBase *lb = object_duplilist(eval_ctx, m_scene, ob); + if (lb) { - DupliObject *dupliob = static_cast<DupliObject *>(lb->first); + DupliObject *link = static_cast<DupliObject *>(lb->first); - while (dupliob) { - if (dupliob->type == OB_DUPLIGROUP) { - exploreObject(eval_ctx, dupliob->ob, ob); + for (; link; link = link->next) { + /* This skips things like custom bone shapes. */ + if (m_settings.renderable_only && link->no_draw) { + continue; } - dupliob = dupliob->next; + if (link->type == OB_DUPLIGROUP) { + exploreObject(eval_ctx, link->ob, ob); + } } } @@ -497,10 +531,6 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent) return; } - if (!export_object(&m_settings, ob)) { - return; - } - std::string name; if (m_settings.flatten_hierarchy) { @@ -513,7 +543,7 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent) AbcTransformWriter *xform = getXForm(name); if (!xform) { - std::cerr << __func__ << ": xform " << name << " is NULL\n"; + ABC_LOG(m_settings.logger) << __func__ << ": xform " << name << " is NULL\n"; return; } diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h index b0eb8e185d6..73b7af280d9 100644 --- a/source/blender/alembic/intern/abc_exporter.h +++ b/source/blender/alembic/intern/abc_exporter.h @@ -28,6 +28,8 @@ #include <set> #include <vector> +#include "abc_util.h" + class AbcObjectWriter; class AbcTransformWriter; class ArchiveWriter; @@ -41,6 +43,7 @@ struct ExportSettings { ExportSettings(); Scene *scene; + SimpleLogger logger; bool selected_only; bool visible_layers_only; @@ -86,7 +89,10 @@ class AbcExporter { ArchiveWriter *m_writer; - std::map<std::string, AbcTransformWriter *> m_xforms; + /* mapping from name to transform writer */ + typedef std::map<std::string, AbcTransformWriter *> m_xforms_type; + m_xforms_type m_xforms; + std::vector<AbcObjectWriter *> m_shapes; public: @@ -103,8 +109,7 @@ private: void getFrameSet(double step, std::set<double> &frames); void createTransformWritersHierarchy(EvaluationContext *eval_ctx); - void createTransformWritersFlat(); - void createTransformWriter(Object *ob, Object *parent, Object *dupliObParent); + AbcTransformWriter * createTransformWriter(Object *ob, Object *parent, Object *dupliObParent); void exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent = NULL); void exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent); void createShapeWriters(EvaluationContext *eval_ctx); diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index 5a57e43326a..79b891dbcd4 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -897,19 +897,31 @@ static void *add_customdata_cb(void *user_data, const char *name, int data_type) { DerivedMesh *dm = static_cast<DerivedMesh *>(user_data); CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); - void *cd_ptr = NULL; - - if (ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { - cd_ptr = CustomData_get_layer_named(dm->getLoopDataLayout(dm), cd_data_type, name); - - if (cd_ptr == NULL) { - cd_ptr = CustomData_add_layer_named(dm->getLoopDataLayout(dm), - cd_data_type, - CD_DEFAULT, - NULL, - dm->getNumLoops(dm), - name); - } + void *cd_ptr; + CustomData *loopdata; + int numloops; + + /* unsupported custom data type -- don't do anything. */ + if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { + return NULL; + } + + loopdata = dm->getLoopDataLayout(dm); + cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name); + if (cd_ptr != NULL) { + /* layer already exists, so just return it. */ + return cd_ptr; + } + + /* create a new layer, taking care to construct the hopefully-soon-to-be-removed + * CD_MTEXPOLY layer too, with the same name. */ + numloops = dm->getNumLoops(dm); + cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, + NULL, numloops, name); + if (cd_data_type == CD_MLOOPUV) { + CustomData_add_layer_named(dm->getPolyDataLayout(dm), + CD_MTEXPOLY, CD_DEFAULT, + NULL, numloops, name); } return cd_ptr; diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc index a5b8af542fc..c8716d55218 100644 --- a/source/blender/alembic/intern/abc_object.cc +++ b/source/blender/alembic/intern/abc_object.cc @@ -91,7 +91,7 @@ Imath::Box3d AbcObjectWriter::bounds() if (!bb) { if (this->m_object->type != OB_CAMERA) { - std::cerr << "Boundbox is null!\n"; + ABC_LOG(m_settings.logger) << "Bounding box is null!\n"; } return Imath::Box3d(); @@ -127,6 +127,7 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings , m_min_time(std::numeric_limits<chrono_t>::max()) , m_max_time(std::numeric_limits<chrono_t>::min()) , m_refcount(0) + , parent_reader(NULL) { m_name = object.getFullName(); std::vector<std::string> parts; @@ -214,7 +215,7 @@ Imath::M44d get_matrix(const IXformSchema &schema, const float time) return s0.getMatrix(); } -void AbcObjectReader::readObjectMatrix(const float time) +void AbcObjectReader::setupObjectTransform(const float time) { bool is_constant = false; @@ -236,49 +237,88 @@ void AbcObjectReader::readObjectMatrix(const float time) } } -void AbcObjectReader::read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant) +Alembic::AbcGeom::IXform AbcObjectReader::xform() { - IXform ixform; - bool has_alembic_parent = false; - /* Check that we have an empty object (locator, bone head/tail...). */ if (IXform::matches(m_iobject.getMetaData())) { - ixform = IXform(m_iobject, Alembic::AbcGeom::kWrapExisting); - - /* See comment below. */ - has_alembic_parent = m_iobject.getParent().getParent().valid(); + return IXform(m_iobject, Alembic::AbcGeom::kWrapExisting); } - /* Check that we have an object with actual data. */ - else if (IXform::matches(m_iobject.getParent().getMetaData())) { - ixform = IXform(m_iobject.getParent(), Alembic::AbcGeom::kWrapExisting); - - /* This is a bit hackish, but we need to make sure that extra - * transformations added to the matrix (rotation/scale) are only applied - * to root objects. The way objects and their hierarchy are created will - * need to be revisited at some point but for now this seems to do the - * trick. - * - * Explanation of the trick: - * The first getParent() will return this object's transformation matrix. - * The second getParent() will get the parent of the transform, but this - * might be the archive root ('/') which is valid, so we go passed it to - * make sure that there is no parent. - */ - has_alembic_parent = m_iobject.getParent().getParent().getParent().valid(); + + /* Check that we have an object with actual data, in which case the + * parent Alembic object should contain the transform. */ + IObject abc_parent = m_iobject.getParent(); + + /* The archive's top object can be recognised by not having a parent. */ + if (abc_parent.getParent() + && IXform::matches(abc_parent.getMetaData())) { + return IXform(abc_parent, Alembic::AbcGeom::kWrapExisting); } + /* Should not happen. */ - else { + std::cerr << "AbcObjectReader::xform(): " + << "unable to find IXform for Alembic object '" + << m_iobject.getFullName() << "'\n"; + BLI_assert(false); + + return IXform(); +} + +void AbcObjectReader::read_matrix(float r_mat[4][4], const float time, + const float scale, bool &is_constant) +{ + IXform ixform = xform(); + if (!ixform) { return; } - const IXformSchema &schema(ixform.getSchema()); - + const IXformSchema & schema(ixform.getSchema()); if (!schema.valid()) { + std::cerr << "Alembic object " << ixform.getFullName() + << " has an invalid schema." << std::endl; return; } + bool has_alembic_parent; + IObject ixform_parent = ixform.getParent(); + if (!ixform_parent.getParent()) { + /* The archive top object certainly is not a transform itself, so handle + * it as "no parent". */ + has_alembic_parent = false; + } + else { + has_alembic_parent = ixform_parent && schema.getInheritsXforms(); + + if (has_alembic_parent && m_object->parent == NULL) { + /* TODO Sybren: This happened in some files. I think I solved it, + * but I'll leave this check in here anyway until we've tested it + * more thoroughly. Better than crashing on a null parent anyway. */ + std::cerr << "Alembic object " << m_iobject.getFullName() + << " with transform " << ixform.getFullName() + << " has an Alembic parent but no parent Blender object." + << std::endl; + has_alembic_parent = false; + } + } + const Imath::M44d matrix = get_matrix(schema, time); - convert_matrix(matrix, m_object, mat, scale, has_alembic_parent); + convert_matrix(matrix, m_object, r_mat); + + if (has_alembic_parent) { + /* In this case, the matrix in Alembic is in local coordinates, so + * convert to world matrix. To prevent us from reading and accumulating + * all parent matrices in the Alembic file, we assume that the Blender + * parent object is already updated for the current timekey, and use its + * world matrix. */ + BLI_assert(m_object->parent); + mul_m4_m4m4(r_mat, m_object->parent->obmat, r_mat); + } + else { + /* Only apply scaling to root objects, parenting will propagate it. */ + float scale_mat[4][4]; + scale_m4_fl(scale_mat, scale); + scale_mat[3][3] = scale; /* scale translations too */ + mul_m4_m4m4(r_mat, r_mat, scale_mat); + } is_constant = schema.isConstant(); } diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h index 0f733e67d3f..d5344533b55 100644 --- a/source/blender/alembic/intern/abc_object.h +++ b/source/blender/alembic/intern/abc_object.h @@ -117,15 +117,7 @@ struct ImportSettings { template <typename Schema> static bool has_animations(Schema &schema, ImportSettings *settings) { - if (settings->is_sequence) { - return true; - } - - if (!schema.isConstant()) { - return true; - } - - return false; + return settings->is_sequence || !schema.isConstant(); } /* ************************************************************************** */ @@ -152,15 +144,30 @@ protected: int m_refcount; public: + AbcObjectReader *parent_reader; + +public: explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings); virtual ~AbcObjectReader(); const Alembic::Abc::IObject &iobject() const; + typedef std::vector<AbcObjectReader *> ptr_vector; + + /** + * Returns the transform of this object. This can be the Alembic object + * itself (in case of an Empty) or it can be the parent Alembic object. + */ + virtual Alembic::AbcGeom::IXform xform(); + Object *object() const; void object(Object *ob); + const std::string & name() const { return m_name; } + const std::string & object_name() const { return m_object_name; } + const std::string & data_name() const { return m_data_name; } + virtual bool valid() const = 0; virtual void readObjectData(Main *bmain, float time) = 0; @@ -173,7 +180,8 @@ public: return dm; } - void readObjectMatrix(const float time); + /** Reads the object matrix and sets up an object transform if animated. */ + void setupObjectTransform(const float time); void addCacheModifier(); @@ -184,7 +192,8 @@ public: void incref(); void decref(); - void read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant); + void read_matrix(float r_mat[4][4], const float time, + const float scale, bool &is_constant); }; Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time); diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc index 2c6ef09326c..6e218cac429 100644 --- a/source/blender/alembic/intern/abc_transform.cc +++ b/source/blender/alembic/intern/abc_transform.cc @@ -62,9 +62,9 @@ AbcTransformWriter::AbcTransformWriter(Object *ob, unsigned int time_sampling, ExportSettings &settings) : AbcObjectWriter(NULL, ob, time_sampling, settings, parent) + , m_proxy_from(NULL) { m_is_animated = hasAnimation(m_object); - m_parent = NULL; if (!m_is_animated) { time_sampling = 0; @@ -72,6 +72,9 @@ AbcTransformWriter::AbcTransformWriter(Object *ob, m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling); m_schema = m_xform.getSchema(); + + /* Blender objects can't have a parent without inheriting the transform. */ + m_inherits_xform = parent != NULL; } void AbcTransformWriter::do_write() @@ -86,27 +89,29 @@ void AbcTransformWriter::do_write() return; } - float mat[4][4]; - create_transform_matrix(m_object, mat); + float yup_mat[4][4]; + create_transform_matrix(m_object, yup_mat, + m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD, + m_proxy_from); /* Only apply rotation to root camera, parenting will propagate it. */ - if (m_object->type == OB_CAMERA && !has_parent_camera(m_object)) { + if (m_object->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(m_object))) { float rot_mat[4][4]; axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2); - mul_m4_m4m4(mat, mat, rot_mat); + mul_m4_m4m4(yup_mat, yup_mat, rot_mat); } - if (!m_object->parent) { + if (!m_object->parent || !m_inherits_xform) { /* Only apply scaling to root objects, parenting will propagate it. */ float scale_mat[4][4]; scale_m4_fl(scale_mat, m_settings.global_scale); - mul_m4_m4m4(mat, mat, scale_mat); - mul_v3_fl(mat[3], m_settings.global_scale); + scale_mat[3][3] = m_settings.global_scale; /* also scale translation */ + mul_m4_m4m4(yup_mat, yup_mat, scale_mat); } - m_matrix = convert_matrix(mat); - + m_matrix = convert_matrix(yup_mat); m_sample.setMatrix(m_matrix); + m_sample.setInheritsXforms(m_inherits_xform); m_schema.set(m_sample); } @@ -133,6 +138,10 @@ bool AbcTransformWriter::hasAnimation(Object * /*ob*/) const AbcEmptyReader::AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { + /* Empties have no data. It makes the import of Alembic files easier to + * understand when we name the empty after its name in Alembic. */ + m_object_name = object.getName(); + Alembic::AbcGeom::IXform xform(object, Alembic::AbcGeom::kWrapExisting); m_schema = xform.getSchema(); @@ -146,6 +155,7 @@ bool AbcEmptyReader::valid() const void AbcEmptyReader::readObjectData(Main *bmain, float /*time*/) { - m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_data_name.c_str()); + m_object = BKE_object_add_only_object(bmain, OB_EMPTY, + m_object_name.c_str()); m_object->data = NULL; } diff --git a/source/blender/alembic/intern/abc_transform.h b/source/blender/alembic/intern/abc_transform.h index 6a3aae216f2..59388e155dc 100644 --- a/source/blender/alembic/intern/abc_transform.h +++ b/source/blender/alembic/intern/abc_transform.h @@ -37,8 +37,11 @@ class AbcTransformWriter : public AbcObjectWriter { Alembic::Abc::M44d m_matrix; bool m_is_animated; - Object *m_parent; bool m_visible; + bool m_inherits_xform; + +public: + Object *m_proxy_from; public: AbcTransformWriter(Object *ob, @@ -49,7 +52,6 @@ public: Alembic::AbcGeom::OXform &alembicXform() { return m_xform;} virtual Imath::Box3d bounds(); - void setParent(Object *p) { m_parent = p; } private: virtual void do_write(); diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index 50fa43a3491..67d2d3b1eb2 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -41,7 +41,7 @@ extern "C" { #include "PIL_time.h" } -std::string get_id_name(Object *ob) +std::string get_id_name(const Object * const ob) { if (!ob) { return ""; @@ -50,7 +50,7 @@ std::string get_id_name(Object *ob) return get_id_name(&ob->id); } -std::string get_id_name(ID *id) +std::string get_id_name(const ID * const id) { std::string name(id->name + 2); std::replace(name.begin(), name.end(), ' ', '_'); @@ -60,7 +60,7 @@ std::string get_id_name(ID *id) return name; } -std::string get_object_dag_path_name(Object *ob, Object *dupli_parent) +std::string get_object_dag_path_name(const Object * const ob, Object *dupli_parent) { std::string name = get_id_name(ob); @@ -132,15 +132,28 @@ void split(const std::string &s, const char delim, std::vector<std::string> &tok } } -/* Create a rotation matrix for each axis from euler angles. - * Euler angles are swaped to change coordinate system. */ -static void create_rotation_matrix( +void create_swapped_rotation_matrix( float rot_x_mat[3][3], float rot_y_mat[3][3], - float rot_z_mat[3][3], const float euler[3], const bool to_yup) + float rot_z_mat[3][3], const float euler[3], + AbcAxisSwapMode mode) { const float rx = euler[0]; - const float ry = (to_yup) ? euler[2] : -euler[2]; - const float rz = (to_yup) ? -euler[1] : euler[1]; + float ry; + float rz; + + /* Apply transformation */ + switch(mode) { + case ABC_ZUP_FROM_YUP: + ry = -euler[2]; + rz = euler[1]; + break; + case ABC_YUP_FROM_ZUP: + ry = euler[2]; + rz = -euler[1]; + break; + default: + BLI_assert(false); + } unit_m3(rot_x_mat); unit_m3(rot_y_mat); @@ -162,58 +175,70 @@ static void create_rotation_matrix( rot_z_mat[1][1] = cos(rz); } -/* Recompute transform matrix of object in new coordinate system - * (from Y-Up to Z-Up). */ -void create_transform_matrix(float r_mat[4][4]) +/* Convert matrix from Z=up to Y=up or vice versa. Use yup_mat = zup_mat for in-place conversion. */ +void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode) { - float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], transform_mat[4][4]; + float dst_rot[3][3], src_rot[3][3], dst_scale_mat[4][4]; float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3]; - float loc[3], scale[3], euler[3]; + float src_trans[3], dst_scale[3], src_scale[3], euler[3]; - zero_v3(loc); - zero_v3(scale); + zero_v3(src_trans); + zero_v3(dst_scale); + zero_v3(src_scale); zero_v3(euler); - unit_m3(rot); - unit_m3(rot_mat); - unit_m4(scale_mat); - unit_m4(transform_mat); - unit_m4(invmat); + unit_m3(src_rot); + unit_m3(dst_rot); + unit_m4(dst_scale_mat); - /* Compute rotation matrix. */ + /* We assume there is no sheer component and no homogeneous scaling component. */ + BLI_assert(fabs(src_mat[0][3]) < 2 * FLT_EPSILON); + BLI_assert(fabs(src_mat[1][3]) < 2 * FLT_EPSILON); + BLI_assert(fabs(src_mat[2][3]) < 2 * FLT_EPSILON); + BLI_assert(fabs(src_mat[3][3] - 1.0f) < 2 * FLT_EPSILON); - /* Extract location, rotation, and scale from matrix. */ - mat4_to_loc_rot_size(loc, rot, scale, r_mat); + /* Extract translation, rotation, and scale form matrix. */ + mat4_to_loc_rot_size(src_trans, src_rot, src_scale, src_mat); /* Get euler angles from rotation matrix. */ - mat3_to_eulO(euler, ROT_MODE_XYZ, rot); + mat3_to_eulO(euler, ROT_MODE_XZY, src_rot); /* Create X, Y, Z rotation matrices from euler angles. */ - create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, false); + create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, mode); /* Concatenate rotation matrices. */ - mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat); + mul_m3_m3m3(dst_rot, dst_rot, rot_z_mat); + mul_m3_m3m3(dst_rot, dst_rot, rot_y_mat); + mul_m3_m3m3(dst_rot, dst_rot, rot_x_mat); - /* Add rotation matrix to transformation matrix. */ - copy_m4_m3(transform_mat, rot_mat); + mat3_to_eulO(euler, ROT_MODE_XZY, dst_rot); - /* Add translation to transformation matrix. */ - copy_zup_from_yup(transform_mat[3], loc); + /* Start construction of dst_mat from rotation matrix */ + unit_m4(dst_mat); + copy_m4_m3(dst_mat, dst_rot); - /* Create scale matrix. */ - scale_mat[0][0] = scale[0]; - scale_mat[1][1] = scale[2]; - scale_mat[2][2] = scale[1]; + /* Apply translation */ + switch(mode) { + case ABC_ZUP_FROM_YUP: + copy_zup_from_yup(dst_mat[3], src_trans); + break; + case ABC_YUP_FROM_ZUP: + copy_yup_from_zup(dst_mat[3], src_trans); + break; + default: + BLI_assert(false); + } - /* Add scale to transformation matrix. */ - mul_m4_m4m4(transform_mat, transform_mat, scale_mat); + /* Apply scale matrix. Swaps y and z, but does not + * negate like translation does. */ + dst_scale[0] = src_scale[0]; + dst_scale[1] = src_scale[2]; + dst_scale[2] = src_scale[1]; - copy_m4_m4(r_mat, transform_mat); + size_to_mat4(dst_scale_mat, dst_scale); + mul_m4_m4m4(dst_mat, dst_mat, dst_scale_mat); } -void convert_matrix(const Imath::M44d &xform, Object *ob, - float r_mat[4][4], float scale, bool has_alembic_parent) +void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4]) { for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { @@ -227,207 +252,32 @@ void convert_matrix(const Imath::M44d &xform, Object *ob, mul_m4_m4m4(r_mat, r_mat, cam_to_yup); } - create_transform_matrix(r_mat); - - if (ob->parent) { - mul_m4_m4m4(r_mat, ob->parent->obmat, r_mat); - } - /* TODO(kevin) */ - else if (!has_alembic_parent) { - /* Only apply scaling to root objects, parenting will propagate it. */ - float scale_mat[4][4]; - scale_m4_fl(scale_mat, scale); - mul_m4_m4m4(r_mat, r_mat, scale_mat); - mul_v3_fl(r_mat[3], scale); - } + copy_m44_axis_swap(r_mat, r_mat, ABC_ZUP_FROM_YUP); } -/* Recompute transform matrix of object in new coordinate system (from Z-Up to Y-Up). */ -void create_transform_matrix(Object *obj, float transform_mat[4][4]) +/* Recompute transform matrix of object in new coordinate system + * (from Z-Up to Y-Up). */ +void create_transform_matrix(Object *obj, float r_yup_mat[4][4], AbcMatrixMode mode, + Object *proxy_from) { - float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], mat[4][4]; - float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3]; - float loc[3], scale[3], euler[3]; - - zero_v3(loc); - zero_v3(scale); - zero_v3(euler); - unit_m3(rot); - unit_m3(rot_mat); - unit_m4(scale_mat); - unit_m4(transform_mat); - unit_m4(invmat); - unit_m4(mat); - - /* get local matrix. */ - if (obj->parent) { - invert_m4_m4(invmat, obj->parent->obmat); - mul_m4_m4m4(mat, invmat, obj->obmat); + float zup_mat[4][4]; + + /* get local or world matrix. */ + if (mode == ABC_MATRIX_LOCAL && obj->parent) { + /* Note that this produces another matrix than the local matrix, due to + * constraints and modifiers as well as the obj->parentinv matrix. */ + invert_m4_m4(obj->parent->imat, obj->parent->obmat); + mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat); } else { - copy_m4_m4(mat, obj->obmat); + copy_m4_m4(zup_mat, obj->obmat); } - /* Compute rotation matrix. */ - switch (obj->rotmode) { - case ROT_MODE_AXISANGLE: - { - /* Get euler angles from axis angle rotation. */ - axis_angle_to_eulO(euler, ROT_MODE_XYZ, obj->rotAxis, obj->rotAngle); - - /* Create X, Y, Z rotation matrices from euler angles. */ - create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true); - - /* Concatenate rotation matrices. */ - mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat); - - /* Extract location and scale from matrix. */ - mat4_to_loc_rot_size(loc, rot, scale, mat); - - break; - } - case ROT_MODE_QUAT: - { - float q[4]; - copy_v4_v4(q, obj->quat); - - /* Swap axis. */ - q[2] = obj->quat[3]; - q[3] = -obj->quat[2]; - - /* Compute rotation matrix from quaternion. */ - quat_to_mat3(rot_mat, q); - - /* Extract location and scale from matrix. */ - mat4_to_loc_rot_size(loc, rot, scale, mat); - - break; - } - case ROT_MODE_XYZ: - { - /* Extract location, rotation, and scale form matrix. */ - mat4_to_loc_rot_size(loc, rot, scale, mat); - - /* Get euler angles from rotation matrix. */ - mat3_to_eulO(euler, ROT_MODE_XYZ, rot); - - /* Create X, Y, Z rotation matrices from euler angles. */ - create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true); - - /* Concatenate rotation matrices. */ - mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat); - - break; - } - case ROT_MODE_XZY: - { - /* Extract location, rotation, and scale form matrix. */ - mat4_to_loc_rot_size(loc, rot, scale, mat); - - /* Get euler angles from rotation matrix. */ - mat3_to_eulO(euler, ROT_MODE_XZY, rot); - - /* Create X, Y, Z rotation matrices from euler angles. */ - create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true); - - /* Concatenate rotation matrices. */ - mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat); - - break; - } - case ROT_MODE_YXZ: - { - /* Extract location, rotation, and scale form matrix. */ - mat4_to_loc_rot_size(loc, rot, scale, mat); - - /* Get euler angles from rotation matrix. */ - mat3_to_eulO(euler, ROT_MODE_YXZ, rot); - - /* Create X, Y, Z rotation matrices from euler angles. */ - create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true); - - /* Concatenate rotation matrices. */ - mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat); - - break; - } - case ROT_MODE_YZX: - { - /* Extract location, rotation, and scale form matrix. */ - mat4_to_loc_rot_size(loc, rot, scale, mat); - - /* Get euler angles from rotation matrix. */ - mat3_to_eulO(euler, ROT_MODE_YZX, rot); - - /* Create X, Y, Z rotation matrices from euler angles. */ - create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true); - - /* Concatenate rotation matrices. */ - mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat); - - break; - } - case ROT_MODE_ZXY: - { - /* Extract location, rotation, and scale form matrix. */ - mat4_to_loc_rot_size(loc, rot, scale, mat); - - /* Get euler angles from rotation matrix. */ - mat3_to_eulO(euler, ROT_MODE_ZXY, rot); - - /* Create X, Y, Z rotation matrices from euler angles. */ - create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true); - - /* Concatenate rotation matrices. */ - mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat); - - break; - } - case ROT_MODE_ZYX: - { - /* Extract location, rotation, and scale form matrix. */ - mat4_to_loc_rot_size(loc, rot, scale, mat); - - /* Get euler angles from rotation matrix. */ - mat3_to_eulO(euler, ROT_MODE_ZYX, rot); - - /* Create X, Y, Z rotation matrices from euler angles. */ - create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true); - - /* Concatenate rotation matrices. */ - mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat); - mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat); - - break; - } + if (proxy_from) { + mul_m4_m4m4(zup_mat, proxy_from->obmat, zup_mat); } - /* Add rotation matrix to transformation matrix. */ - copy_m4_m3(transform_mat, rot_mat); - - /* Add translation to transformation matrix. */ - copy_yup_from_zup(transform_mat[3], loc); - - /* Create scale matrix. */ - scale_mat[0][0] = scale[0]; - scale_mat[1][1] = scale[2]; - scale_mat[2][2] = scale[1]; - - /* Add scale to transformation matrix. */ - mul_m4_m4m4(transform_mat, transform_mat, scale_mat); + copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP); } bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name) @@ -520,7 +370,10 @@ AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSe reader = new AbcCurveReader(object, settings); } else { - assert(false); + std::cerr << "Alembic: unknown how to handle objects of schema " + << md.get("schemaObjTitle") + << ", skipping object " + << object.getFullName() << std::endl; } return reader; @@ -537,3 +390,32 @@ ScopeTimer::~ScopeTimer() { fprintf(stderr, "%s: %fs\n", m_message, PIL_check_seconds_timer() - m_start); } + +/* ********************** */ + +bool SimpleLogger::empty() +{ + return ((size_t)m_stream.tellp()) == 0ul; +} + +std::string SimpleLogger::str() const +{ + return m_stream.str(); +} + +void SimpleLogger::clear() +{ + m_stream.clear(); + m_stream.str(""); +} + +std::ostringstream &SimpleLogger::stream() +{ + return m_stream; +} + +std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger) +{ + os << logger.str(); + return os; +} diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h index 85ba4d5c9c7..74d0faf97d3 100644 --- a/source/blender/alembic/intern/abc_util.h +++ b/source/blender/alembic/intern/abc_util.h @@ -32,6 +32,11 @@ # define ABC_INLINE static inline #endif +/** + * @brief The CacheReader struct is only used for anonymous pointers, + * to interface between C and C++ code. This library only creates + * pointers to AbcObjectReader (or subclasses thereof). + */ struct CacheReader { int unused; }; @@ -44,16 +49,21 @@ struct ImportSettings; struct ID; struct Object; -std::string get_id_name(ID *id); -std::string get_id_name(Object *ob); -std::string get_object_dag_path_name(Object *ob, Object *dupli_parent); +std::string get_id_name(const ID * const id); +std::string get_id_name(const Object * const ob); +std::string get_object_dag_path_name(const Object * const ob, Object *dupli_parent); bool object_selected(Object *ob); bool parent_selected(Object *ob); Imath::M44d convert_matrix(float mat[4][4]); -void create_transform_matrix(float r_mat[4][4]); -void create_transform_matrix(Object *obj, float transform_mat[4][4]); + +typedef enum { + ABC_MATRIX_WORLD = 1, + ABC_MATRIX_LOCAL = 2, +} AbcMatrixMode; +void create_transform_matrix(Object *obj, float r_transform_mat[4][4], + AbcMatrixMode mode, Object *proxy_from); void split(const std::string &s, const char delim, std::vector<std::string> &tokens); @@ -64,8 +74,7 @@ bool begins_with(const TContainer &input, const TContainer &match) && std::equal(match.begin(), match.end(), input.begin()); } -void convert_matrix(const Imath::M44d &xform, Object *ob, - float r_mat[4][4], float scale, bool has_alembic_parent = false); +void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4]); template <typename Schema> void get_min_max_time_ex(const Schema &schema, chrono_t &min, chrono_t &max) @@ -118,34 +127,54 @@ AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSe ABC_INLINE void copy_zup_from_yup(float zup[3], const float yup[3]) { + const float old_yup1 = yup[1]; /* in case zup == yup */ zup[0] = yup[0]; zup[1] = -yup[2]; - zup[2] = yup[1]; + zup[2] = old_yup1; } ABC_INLINE void copy_zup_from_yup(short zup[3], const short yup[3]) { + const short old_yup1 = yup[1]; /* in case zup == yup */ zup[0] = yup[0]; zup[1] = -yup[2]; - zup[2] = yup[1]; + zup[2] = old_yup1; } /* Copy from Z-up to Y-up. */ ABC_INLINE void copy_yup_from_zup(float yup[3], const float zup[3]) { + const float old_zup1 = zup[1]; /* in case yup == zup */ yup[0] = zup[0]; yup[1] = zup[2]; - yup[2] = -zup[1]; + yup[2] = -old_zup1; } ABC_INLINE void copy_yup_from_zup(short yup[3], const short zup[3]) { + const short old_zup1 = zup[1]; /* in case yup == zup */ yup[0] = zup[0]; yup[1] = zup[2]; - yup[2] = -zup[1]; + yup[2] = -old_zup1; } +/* Names are given in (dst, src) order, just like + * the parameters of copy_m44_axis_swap() */ +typedef enum { + ABC_ZUP_FROM_YUP = 1, + ABC_YUP_FROM_ZUP = 2, +} AbcAxisSwapMode; + +/* Create a rotation matrix for each axis from euler angles. + * Euler angles are swaped to change coordinate system. */ +void create_swapped_rotation_matrix( + float rot_x_mat[3][3], float rot_y_mat[3][3], + float rot_z_mat[3][3], const float euler[3], + AbcAxisSwapMode mode); + +void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode); + /* *************************** */ #undef ABC_DEBUG_TIME @@ -165,4 +194,48 @@ public: # define SCOPE_TIMER(message) #endif +/* *************************** */ + +/** + * Utility class whose purpose is to more easily log related informations. An + * instance of the SimpleLogger can be created in any context, and will hold a + * copy of all the strings passed to its output stream. + * + * Different instances of the class may be accessed from different threads, + * although accessing the same instance from different threads will lead to race + * conditions. + */ +class SimpleLogger { + std::ostringstream m_stream; + +public: + /** + * Check whether or not the SimpleLogger's stream is empty. + */ + bool empty(); + + /** + * Return a copy of the string contained in the SimpleLogger's stream. + */ + std::string str() const; + + /** + * Remove the bits set on the SimpleLogger's stream and clear its string. + */ + void clear(); + + /** + * Return a reference to the SimpleLogger's stream, in order to e.g. push + * content into it. + */ + std::ostringstream &stream(); +}; + +#define ABC_LOG(logger) logger.stream() + +/** + * Pass the content of the logger's stream to the specified std::ostream. + */ +std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger); + #endif /* __ABC_UTIL_H__ */ diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index dc5146a26e0..0de0d1a1ab6 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -21,6 +21,7 @@ */ #include "../ABC_alembic.h" +#include <boost/foreach.hpp> #include <Alembic/AbcMaterial/IMaterial.h> @@ -120,91 +121,62 @@ ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive) /* NOTE: this function is similar to visit_objects below, need to keep them in * sync. */ -static void gather_objects_paths(const IObject &object, ListBase *object_paths) +static bool gather_objects_paths(const IObject &object, ListBase *object_paths) { if (!object.valid()) { - return; + return false; } - for (int i = 0; i < object.getNumChildren(); ++i) { - IObject child = object.getChild(i); - if (!child.valid()) { - continue; - } + size_t children_claiming_this_object = 0; + size_t num_children = object.getNumChildren(); - bool get_path = false; + for (size_t i = 0; i < num_children; ++i) { + bool child_claims_this_object = gather_objects_paths(object.getChild(i), object_paths); + children_claiming_this_object += child_claims_this_object ? 1 : 0; + } - const MetaData &md = child.getMetaData(); + const MetaData &md = object.getMetaData(); + bool get_path = false; + bool parent_is_part_of_this_object = false; - if (IXform::matches(md)) { - /* Check whether or not this object is a Maya locator, which is - * similar to empties used as parent object in Blender. */ - if (has_property(child.getProperties(), "locator")) { - get_path = true; - } - else { - /* Avoid creating an empty object if the child of this transform - * is not a transform (that is an empty). */ - if (child.getNumChildren() == 1) { - if (IXform::matches(child.getChild(0).getMetaData())) { - get_path = true; - } -#if 0 - else { - std::cerr << "Skipping " << child.getFullName() << '\n'; - } -#endif - } - else { - get_path = true; - } - } - } - else if (IPolyMesh::matches(md)) { - get_path = true; - } - else if (ISubD::matches(md)) { - get_path = true; - } - else if (INuPatch::matches(md)) { -#ifdef USE_NURBS - get_path = true; -#endif - } - else if (ICamera::matches(md)) { - get_path = true; - } - else if (IPoints::matches(md)) { - get_path = true; - } - else if (IMaterial::matches(md)) { - /* Pass for now. */ - } - else if (ILight::matches(md)) { - /* Pass for now. */ - } - else if (IFaceSet::matches(md)) { - /* Pass, those are handled in the mesh reader. */ - } - else if (ICurves::matches(md)) { + if (!object.getParent()) { + /* The root itself is not an object we should import. */ + } + else if (IXform::matches(md)) { + if (has_property(object.getProperties(), "locator")) { get_path = true; } else { - assert(false); + get_path = children_claiming_this_object == 0; } - if (get_path) { - AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>( - MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath")); - - BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX); + /* Transforms are never "data" for their parent. */ + parent_is_part_of_this_object = false; + } + else { + /* These types are "data" for their parent. */ + get_path = + IPolyMesh::matches(md) || + ISubD::matches(md) || +#ifdef USE_NURBS + INuPatch::matches(md) || +#endif + ICamera::matches(md) || + IPoints::matches(md) || + ICurves::matches(md); + parent_is_part_of_this_object = get_path; + } - BLI_addtail(object_paths, abc_path); - } + if (get_path) { + void *abc_path_void = MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"); + AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(abc_path_void); - gather_objects_paths(child, object_paths); + BLI_strncpy(abc_path->path, object.getFullName().c_str(), PATH_MAX); + BLI_addtail(object_paths, abc_path); } + + return parent_is_part_of_this_object; } AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths) @@ -301,10 +273,10 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo } } catch (const std::exception &e) { - std::cerr << "Abc Export error: " << e.what() << '\n'; + ABC_LOG(data->settings.logger) << "Abc Export error: " << e.what() << '\n'; } catch (...) { - std::cerr << "Abc Export error\n"; + ABC_LOG(data->settings.logger) << "Abc Export: unknown error...\n"; } } @@ -316,6 +288,11 @@ static void export_endjob(void *customdata) BLI_delete(data->filename, false, false); } + if (!data->settings.logger.empty()) { + std::cerr << data->settings.logger; + WM_report(RPT_ERROR, "Errors occured during the export, look in the console to know more..."); + } + G.is_rendering = false; BKE_spacedata_draw_locks(false); } @@ -331,6 +308,22 @@ void ABC_export( job->bmain = CTX_data_main(C); BLI_strncpy(job->filename, filepath, 1024); + /* Alright, alright, alright.... + * + * ExportJobData contains an ExportSettings containing a SimpleLogger. + * + * Since ExportJobData is a C-style struct dynamically allocated with + * MEM_mallocN (see above), its construtor is never called, therefore the + * ExportSettings constructor is not called which implies that the + * SimpleLogger one is not called either. SimpleLogger in turn does not call + * the constructor of its data members which ultimately means that its + * std::ostringstream member has a NULL pointer. To be able to properly use + * the stream's operator<<, the pointer needs to be set, therefore we have + * to properly construct everything. And this is done using the placement + * new operator as here below. It seems hackish, but I'm too lazy to + * do bigger refactor and maybe there is a better way which does not involve + * hardcore refactoring. */ + new (&job->settings) ExportSettings(); job->settings.scene = job->scene; job->settings.frame_start = params->frame_start; job->settings.frame_end = params->frame_end; @@ -376,114 +369,208 @@ void ABC_export( /* ********************** Import file ********************** */ -static void visit_object(const IObject &object, - std::vector<AbcObjectReader *> &readers, - GHash *parent_map, - ImportSettings &settings) +/** + * Generates an AbcObjectReader for this Alembic object and its children. + * + * \param object The Alembic IObject to visit. + * \param readers The created AbcObjectReader * will be appended to this vector. + * \param settings Import settings, not used directly but passed to the + * AbcObjectReader subclass constructors. + * \param r_assign_as_parent Return parameter, contains a list of reader + * pointers, whose parent pointer should still be set. + * This is filled when this call to visit_object() didn't create + * a reader that should be the parent. + * \return A pair of boolean and reader pointer. The boolean indicates whether + * this IObject claims its parent as part of the same object + * (for example an IPolyMesh object would claim its parent, as the mesh + * is interpreted as the object's data, and the parent IXform as its + * Blender object). The pointer is the AbcObjectReader that represents + * the IObject parameter. + * + * NOTE: this function is similar to gather_object_paths above, need to keep + * them in sync. */ +static std::pair<bool, AbcObjectReader *> visit_object( + const IObject &object, + AbcObjectReader::ptr_vector &readers, + ImportSettings &settings, + AbcObjectReader::ptr_vector &r_assign_as_parent) { + const std::string & full_name = object.getFullName(); + if (!object.valid()) { - return; + std::cerr << " - " + << full_name + << ": object is invalid, skipping it and all its children.\n"; + return std::make_pair(false, static_cast<AbcObjectReader *>(NULL)); } - for (int i = 0; i < object.getNumChildren(); ++i) { - IObject child = object.getChild(i); + /* The interpretation of data by the children determine the role of this + * object. This is especially important for Xform objects, as they can be + * either part of a Blender object or a Blender object (Empty) themselves. + */ + size_t children_claiming_this_object = 0; + size_t num_children = object.getNumChildren(); + AbcObjectReader::ptr_vector claiming_child_readers; + AbcObjectReader::ptr_vector nonclaiming_child_readers; + AbcObjectReader::ptr_vector assign_as_parent; + for (size_t i = 0; i < num_children; ++i) { + const IObject ichild = object.getChild(i); - if (!child.valid()) { - continue; + /* TODO: When we only support C++11, use std::tie() instead. */ + std::pair<bool, AbcObjectReader *> child_result; + child_result = visit_object(ichild, readers, settings, assign_as_parent); + + bool child_claims_this_object = child_result.first; + AbcObjectReader *child_reader = child_result.second; + + if (child_reader == NULL) { + BLI_assert(!child_claims_this_object); + } + else { + if (child_claims_this_object) { + claiming_child_readers.push_back(child_reader); + } else { + nonclaiming_child_readers.push_back(child_reader); + } } - AbcObjectReader *reader = NULL; + children_claiming_this_object += child_claims_this_object ? 1 : 0; + } + BLI_assert(children_claiming_this_object == claiming_child_readers.size()); - const MetaData &md = child.getMetaData(); + AbcObjectReader *reader = NULL; + const MetaData &md = object.getMetaData(); + bool parent_is_part_of_this_object = false; - if (IXform::matches(md)) { - bool create_xform = false; + if (!object.getParent()) { + /* The root itself is not an object we should import. */ + } + else if (IXform::matches(md)) { + bool create_empty; - /* Check whether or not this object is a Maya locator, which is - * similar to empties used as parent object in Blender. */ - if (has_property(child.getProperties(), "locator")) { - create_xform = true; - } - else { - /* Avoid creating an empty object if the child of this transform - * is not a transform (that is an empty). */ - if (child.getNumChildren() == 1) { - if (IXform::matches(child.getChild(0).getMetaData())) { - create_xform = true; - } -#if 0 - else { - std::cerr << "Skipping " << child.getFullName() << '\n'; - } -#endif - } - else { - create_xform = true; - } - } + /* An xform can either be a Blender Object (if it contains a mesh, for + * example), but it can also be an Empty. Its correct translation to + * Blender's data model depends on its children. */ - if (create_xform) { - reader = new AbcEmptyReader(child, settings); - } + /* Check whether or not this object is a Maya locator, which is + * similar to empties used as parent object in Blender. */ + if (has_property(object.getProperties(), "locator")) { + create_empty = true; } - else if (IPolyMesh::matches(md)) { - reader = new AbcMeshReader(child, settings); + else { + create_empty = claiming_child_readers.empty(); } - else if (ISubD::matches(md)) { - reader = new AbcSubDReader(child, settings); + + if (create_empty) { + reader = new AbcEmptyReader(object, settings); } - else if (INuPatch::matches(md)) { + } + else if (IPolyMesh::matches(md)) { + reader = new AbcMeshReader(object, settings); + parent_is_part_of_this_object = true; + } + else if (ISubD::matches(md)) { + reader = new AbcSubDReader(object, settings); + parent_is_part_of_this_object = true; + } + else if (INuPatch::matches(md)) { #ifdef USE_NURBS - /* TODO(kevin): importing cyclic NURBS from other software crashes - * at the moment. This is due to the fact that NURBS in other - * software have duplicated points which causes buffer overflows in - * Blender. Need to figure out exactly how these points are - * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV). - * Until this is fixed, disabling NURBS reading. */ - reader = new AbcNurbsReader(child, settings); + /* TODO(kevin): importing cyclic NURBS from other software crashes + * at the moment. This is due to the fact that NURBS in other + * software have duplicated points which causes buffer overflows in + * Blender. Need to figure out exactly how these points are + * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV). + * Until this is fixed, disabling NURBS reading. */ + reader = new AbcNurbsReader(object, settings); + parent_is_part_of_this_object = true; #endif + } + else if (ICamera::matches(md)) { + reader = new AbcCameraReader(object, settings); + parent_is_part_of_this_object = true; + } + else if (IPoints::matches(md)) { + reader = new AbcPointsReader(object, settings); + parent_is_part_of_this_object = true; + } + else if (IMaterial::matches(md)) { + /* Pass for now. */ + } + else if (ILight::matches(md)) { + /* Pass for now. */ + } + else if (IFaceSet::matches(md)) { + /* Pass, those are handled in the mesh reader. */ + } + else if (ICurves::matches(md)) { + reader = new AbcCurveReader(object, settings); + parent_is_part_of_this_object = true; + } + else { + std::cerr << "Alembic object " << full_name + << " is of unsupported schema type '" + << object.getMetaData().get("schemaObjTitle") << "'" + << std::endl; + } + + if (reader) { + /* We have created a reader, which should imply that this object is + * not claimed as part of any child Alembic object. */ + BLI_assert(claiming_child_readers.empty()); + + readers.push_back(reader); + reader->incref(); + + AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>( + MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath")); + BLI_strncpy(abc_path->path, full_name.c_str(), PATH_MAX); + BLI_addtail(&settings.cache_file->object_paths, abc_path); + + /* We can now assign this reader as parent for our children. */ + if (nonclaiming_child_readers.size() + assign_as_parent.size() > 0) { + /* TODO: When we only support C++11, use for (a: b) instead. */ + BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) { + child_reader->parent_reader = reader; + } + BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) { + child_reader->parent_reader = reader; + } } - else if (ICamera::matches(md)) { - reader = new AbcCameraReader(child, settings); - } - else if (IPoints::matches(md)) { - reader = new AbcPointsReader(child, settings); - } - else if (IMaterial::matches(md)) { - /* Pass for now. */ - } - else if (ILight::matches(md)) { - /* Pass for now. */ - } - else if (IFaceSet::matches(md)) { - /* Pass, those are handled in the mesh reader. */ - } - else if (ICurves::matches(md)) { - reader = new AbcCurveReader(child, settings); + } + else if (object.getParent()) { + if (claiming_child_readers.size() > 0) { + /* The first claiming child will serve just fine as parent to + * our non-claiming children. Since all claiming children share + * the same XForm, it doesn't really matter which one we pick. */ + AbcObjectReader *claiming_child = claiming_child_readers[0]; + BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) { + child_reader->parent_reader = claiming_child; + } + BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) { + child_reader->parent_reader = claiming_child; + } + /* Claiming children should have our parent set as their parent. */ + BOOST_FOREACH(AbcObjectReader *child_reader, claiming_child_readers) { + r_assign_as_parent.push_back(child_reader); + } } else { - assert(false); - } - - if (reader) { - readers.push_back(reader); - reader->incref(); - - AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>( - MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath")); - - BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX); - - BLI_addtail(&settings.cache_file->object_paths, abc_path); - - /* Cast to `void *` explicitly to avoid compiler errors because it - * is a `const char *` which the compiler cast to `const void *` - * instead of the expected `void *`. */ - BLI_ghash_insert(parent_map, (void *)child.getFullName().c_str(), reader); + /* This object isn't claimed by any child, and didn't produce + * a reader. Odd situation, could be the top Alembic object, or + * an unsupported Alembic schema. Delegate to our parent. */ + BOOST_FOREACH(AbcObjectReader *child_reader, claiming_child_readers) { + r_assign_as_parent.push_back(child_reader); + } + BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) { + r_assign_as_parent.push_back(child_reader); + } + BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) { + r_assign_as_parent.push_back(child_reader); + } } - - visit_object(child, readers, parent_map, settings); } + + return std::make_pair(parent_is_part_of_this_object, reader); } enum { @@ -498,7 +585,6 @@ struct ImportJobData { char filename[1024]; ImportSettings settings; - GHash *parent_map; std::vector<AbcObjectReader *> readers; short *stop; @@ -575,11 +661,12 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa *data->do_update = true; *data->progress = 0.05f; - data->parent_map = BLI_ghash_str_new("alembic parent ghash"); - /* Parse Alembic Archive. */ + AbcObjectReader::ptr_vector assign_as_parent; + visit_object(archive->getTop(), data->readers, data->settings, assign_as_parent); - visit_object(archive->getTop(), data->readers, data->parent_map, data->settings); + /* There shouldn't be any orphans. */ + BLI_assert(assign_as_parent.size() == 0); if (G.is_break) { data->was_cancelled = true; @@ -603,13 +690,16 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa if (reader->valid()) { reader->readObjectData(data->bmain, 0.0f); - reader->readObjectMatrix(0.0f); min_time = std::min(min_time, reader->minTime()); max_time = std::max(max_time, reader->maxTime()); } + else { + std::cerr << "Object " << reader->name() << " in Alembic file " + << data->filename << " is invalid.\n"; + } - *data->progress = 0.1f + 0.6f * (++i / size); + *data->progress = 0.1f + 0.3f * (++i / size); *data->do_update = true; if (G.is_break) { @@ -627,45 +717,31 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa CFRA = SFRA; } else if (min_time < max_time) { - SFRA = static_cast<int>(min_time * FPS); - EFRA = static_cast<int>(max_time * FPS); + SFRA = static_cast<int>(round(min_time * FPS)); + EFRA = static_cast<int>(round(max_time * FPS)); CFRA = SFRA; } } - /* Setup parentship. */ - - i = 0; + /* Setup parenthood. */ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { const AbcObjectReader *reader = *iter; - const AbcObjectReader *parent_reader = NULL; - const IObject &iobject = reader->iobject(); - - IObject parent = iobject.getParent(); + const AbcObjectReader *parent_reader = reader->parent_reader; + Object *ob = reader->object(); - if (!IXform::matches(iobject.getHeader())) { - /* In the case of an non XForm node, the parent is the transform - * matrix of the data itself, so we get the its grand parent. - */ - - /* Special case with object only containing a mesh and some strands, - * we want both objects to be parented to the same object. */ - if (!is_mesh_and_strands(parent)) { - parent = parent.getParent(); - } + if (parent_reader == NULL) { + ob->parent = NULL; } - - parent_reader = reinterpret_cast<AbcObjectReader *>( - BLI_ghash_lookup(data->parent_map, parent.getFullName().c_str())); - - if (parent_reader) { - Object *parent = parent_reader->object(); - - if (parent != NULL && reader->object() != parent) { - Object *ob = reader->object(); - ob->parent = parent; - } + else { + ob->parent = parent_reader->object(); } + } + + /* Setup transformations and constraints. */ + i = 0; + for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { + AbcObjectReader *reader = *iter; + reader->setupObjectTransform(0.0f); *data->progress = 0.7f + 0.3f * (++i / size); *data->do_update = true; @@ -690,10 +766,9 @@ static void import_endjob(void *user_data) for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { Object *ob = (*iter)->object(); - if (ob->data) { - BKE_libblock_free_us(data->bmain, ob->data); - ob->data = NULL; - } + /* It's possible that cancellation occured between the creation of + * the reader and the creation of the Blender object. */ + if (ob == NULL) continue; BKE_libblock_free_us(data->bmain, ob); } @@ -723,10 +798,6 @@ static void import_endjob(void *user_data) } } - if (data->parent_map) { - BLI_ghash_free(data->parent_map, NULL, NULL); - } - switch (data->error_code) { default: case ABC_NO_ERROR: @@ -760,7 +831,6 @@ void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence job->settings.sequence_len = sequence_len; job->settings.offset = offset; job->settings.validate_meshes = validate_meshes; - job->parent_map = NULL; job->error_code = ABC_NO_ERROR; job->was_cancelled = false; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index aa7d539538b..bbbabfb8ba2 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -135,6 +135,7 @@ void blf_glyph_cache_clear(FontBLF *font) while ((gc = BLI_pophead(&font->cache))) { blf_glyph_cache_free(gc); } + font->glyph_cache = NULL; } void blf_glyph_cache_free(GlyphCacheBLF *gc) diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h index 077fe2a629c..ac8f861fa56 100644 --- a/source/blender/blenkernel/BKE_appdir.h +++ b/source/blender/blenkernel/BKE_appdir.h @@ -27,11 +27,15 @@ /* note on naming: typical _get() suffix is omitted here, * since its the main purpose of the API. */ const char *BKE_appdir_folder_default(void); +const char *BKE_appdir_folder_id_ex(const int folder_id, const char *subfolder, char *path, size_t path_len); const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder); const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder); const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder); const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, const bool do_check); +bool BKE_appdir_app_template_any(void); +bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len); + /* Initialize path to program executable */ void BKE_appdir_program_path_init(const char *argv0); diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 62a15bae153..d55926ffb1e 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -52,6 +52,8 @@ void BKE_blender_userdef_set_data(struct UserDef *userdef); void BKE_blender_userdef_free_data(struct UserDef *userdef); void BKE_blender_userdef_refresh(void); +void BKE_blender_userdef_set_app_template(struct UserDef *userdef); + /* set this callback when a UI is running */ void BKE_blender_callback_test_break_set(void (*func)(void)); int BKE_blender_test_break(void); diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h index 75978120051..ac58451e412 100644 --- a/source/blender/blenkernel/BKE_blendfile.h +++ b/source/blender/blenkernel/BKE_blendfile.h @@ -50,6 +50,7 @@ bool BKE_blendfile_read_from_memory( bool BKE_blendfile_read_from_memfile( struct bContext *C, struct MemFile *memfile, struct ReportList *reports, int skip_flag); +void BKE_blendfile_read_make_empty(struct bContext *C); struct UserDef *BKE_blendfile_userdef_read( const char *filepath, struct ReportList *reports); diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index 36330242f18..6c517bd02df 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -136,9 +136,6 @@ typedef struct ClothSpring { float restlen; /* The original length of the spring. */ int type; /* types defined in BKE_cloth.h ("springType") */ int flags; /* defined in BKE_cloth.h, e.g. deactivated due to tearing */ - float dfdx[3][3]; - float dfdv[3][3]; - float f[3]; float stiffness; /* stiffness factor from the vertex groups */ float editrestlen; @@ -240,9 +237,6 @@ void bvhselftree_update_from_cloth(struct ClothModifierData *clmd, bool moving); // needed for button_object.c void cloth_clear_cache (struct Object *ob, struct ClothModifierData *clmd, float framenr ); -// needed for cloth.c -int cloth_add_spring (struct ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type); - void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3], const float dir_new[3]); //////////////////////////////////////////////// diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 5b10d7ebc06..ab8728faedb 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -60,8 +60,6 @@ typedef union IDPropertyTemplate { IDProperty *IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); IDProperty *IDP_CopyIDPArray(const IDProperty *array) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -void IDP_FreeIDPArray(IDProperty *prop); - /* shallow copies item */ void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item) ATTR_NONNULL(); struct IDProperty *IDP_GetIndexArray(struct IDProperty *prop, int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); @@ -81,8 +79,8 @@ void IDP_ConcatString(struct IDProperty *str1, struct IDProperty *append) ATTR_N void IDP_FreeString(struct IDProperty *prop) ATTR_NONNULL(); /*-------- ID Type -------*/ -void IDP_LinkID(struct IDProperty *prop, ID *id); -void IDP_UnlinkID(struct IDProperty *prop); + +typedef void(*IDPWalkFunc)(void *userData, IDProperty *idp); /*-------- Group Functions -------*/ @@ -112,11 +110,12 @@ bool IDP_EqualsProperties(struct IDProperty *prop1, struct IDProperty *prop2) AT struct IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void IDP_FreeProperty_ex(struct IDProperty *prop, const bool do_id_user); void IDP_FreeProperty(struct IDProperty *prop); void IDP_ClearProperty(IDProperty *prop); -void IDP_UnlinkProperty(struct IDProperty *prop); +void IDP_RelinkProperty(struct IDProperty *prop); #define IDP_Int(prop) ((prop)->data.val) #define IDP_Array(prop) ((prop)->data.pointer) @@ -134,11 +133,15 @@ void IDP_UnlinkProperty(struct IDProperty *prop); # define IDP_IDPArray(prop) _Generic((prop), \ IDProperty *: ((IDProperty *) (prop)->data.pointer), \ const IDProperty *: ((const IDProperty *) (prop)->data.pointer)) +# define IDP_Id(prop) _Generic((prop), \ + IDProperty *: ((ID *) (prop)->data.pointer), \ + const IDProperty *: ((const ID *) (prop)->data.pointer)) #else # define IDP_Float(prop) (*(float *)&(prop)->data.val) # define IDP_Double(prop) (*(double *)&(prop)->data.val) # define IDP_String(prop) ((char *) (prop)->data.pointer) # define IDP_IDPArray(prop) ((IDProperty *) (prop)->data.pointer) +# define IDP_Id(prop) ((ID *) (prop)->data.pointer) #endif #ifndef NDEBUG diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 72ae2cf4efa..6649cfbb585 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -66,7 +66,7 @@ struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_ void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL(); 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_us(struct Main *bmain, void *idv) ATTR_NONNULL(); -void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL(); +void BKE_libblock_free_data(struct Main *bmain, struct ID *id, const bool do_id_user) ATTR_NONNULL(); void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id); diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index 1258e2fa72e..68bf9f43fe1 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -87,7 +87,7 @@ void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used); -bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used); +bool BKE_library_id_can_use_idtype(struct ID *id_owner, const short id_type_used); bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv); bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 546f0d97c2b..193f1154c54 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -49,7 +49,7 @@ #include "RNA_types.h" /* not very important, but the stack solver likes to know a maximum */ -#define MAX_SOCKET 64 +#define MAX_SOCKET 512 struct bContext; struct bNode; diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index f2f0a92d8b3..43fd47981b1 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -114,18 +114,26 @@ static char *blender_version_decimal(const int ver) * Concatenates path_base, (optional) path_sep and (optional) folder_name into targetpath, * returning true if result points to a directory. */ -static bool test_path(char *targetpath, const char *path_base, const char *path_sep, const char *folder_name) +static bool test_path( + char *targetpath, size_t targetpath_len, + const char *path_base, const char *path_sep, const char *folder_name) { char tmppath[FILE_MAX]; - if (path_sep) BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep); - else BLI_strncpy(tmppath, path_base, sizeof(tmppath)); + if (path_sep) { + BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep); + } + else { + BLI_strncpy(tmppath, path_base, sizeof(tmppath)); + } /* rare cases folder_name is omitted (when looking for ~/.config/blender/2.xx dir only) */ - if (folder_name) - BLI_make_file_string("/", targetpath, tmppath, folder_name); - else - BLI_strncpy(targetpath, tmppath, sizeof(tmppath)); + if (folder_name) { + BLI_join_dirfile(targetpath, targetpath_len, tmppath, folder_name); + } + else { + BLI_strncpy(targetpath, tmppath, targetpath_len); + } /* FIXME: why is "//" on front of tmppath expanded to "/" (by BLI_join_dirfile) * if folder_name is specified but not otherwise? */ @@ -179,7 +187,9 @@ static bool test_env_path(char *path, const char *envvar) * \param ver To construct name of version-specific directory within bprogdir * \return true if such a directory exists. */ -static bool get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name, const int ver) +static bool get_path_local( + char *targetpath, size_t targetpath_len, + const char *folder_name, const char *subfolder_name, const int ver) { char relfolder[FILE_MAX]; @@ -201,11 +211,12 @@ static bool get_path_local(char *targetpath, const char *folder_name, const char /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */ #ifdef __APPLE__ - static char osx_resourses[FILE_MAX]; /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */ + /* 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); - return test_path(targetpath, osx_resourses, blender_version_decimal(ver), relfolder); + return test_path(targetpath, targetpath_len, osx_resourses, blender_version_decimal(ver), relfolder); #else - return test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder); + return test_path(targetpath, targetpath_len, bprogdir, blender_version_decimal(ver), relfolder); #endif } @@ -219,7 +230,7 @@ static bool is_portable_install(void) const int ver = BLENDER_VERSION; char path[FILE_MAX]; - return get_path_local(path, "config", NULL, ver); + return get_path_local(path, sizeof(path), "config", NULL, ver); } /** @@ -233,20 +244,22 @@ static bool is_portable_install(void) * \param ver Blender version, used to construct a subdirectory name * \return true if it was able to construct such a path. */ -static bool get_path_user(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver) +static bool get_path_user( + char *targetpath, size_t targetpath_len, const char *folder_name, const char *subfolder_name, + const char *envvar, const int ver) { char user_path[FILE_MAX]; const char *user_base_path; /* for portable install, user path is always local */ - if (is_portable_install()) - return get_path_local(targetpath, folder_name, subfolder_name, ver); - + if (is_portable_install()) { + return get_path_local(targetpath, targetpath_len, folder_name, subfolder_name, ver); + } user_path[0] = '\0'; if (test_env_path(user_path, envvar)) { if (subfolder_name) { - return test_path(targetpath, user_path, NULL, subfolder_name); + return test_path(targetpath, targetpath_len, user_path, NULL, subfolder_name); } else { BLI_strncpy(targetpath, user_path, FILE_MAX); @@ -266,10 +279,10 @@ static bool get_path_user(char *targetpath, const char *folder_name, const char #endif if (subfolder_name) { - return test_path(targetpath, user_path, folder_name, subfolder_name); + return test_path(targetpath, targetpath_len, user_path, folder_name, subfolder_name); } else { - return test_path(targetpath, user_path, NULL, folder_name); + return test_path(targetpath, targetpath_len, user_path, NULL, folder_name); } } @@ -283,7 +296,9 @@ static bool get_path_user(char *targetpath, const char *folder_name, const char * \param ver Blender version, used to construct a subdirectory name * \return true if it was able to construct such a path. */ -static bool get_path_system(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver) +static bool get_path_system( + char *targetpath, size_t targetpath_len, const char *folder_name, const char *subfolder_name, + const char *envvar, const int ver) { char system_path[FILE_MAX]; const char *system_base_path; @@ -307,13 +322,13 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha /* try CWD/release/folder_name */ if (BLI_current_working_dir(cwd, sizeof(cwd))) { - if (test_path(targetpath, cwd, "release", relfolder)) { + if (test_path(targetpath, targetpath_len, cwd, "release", relfolder)) { return true; } } /* try EXECUTABLE_DIR/release/folder_name */ - if (test_path(targetpath, bprogdir, "release", relfolder)) + if (test_path(targetpath, targetpath_len, bprogdir, "release", relfolder)) return true; /* end developer overrides */ @@ -324,7 +339,7 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha if (test_env_path(system_path, envvar)) { if (subfolder_name) { - return test_path(targetpath, system_path, NULL, subfolder_name); + return test_path(targetpath, targetpath_len, system_path, NULL, subfolder_name); } else { BLI_strncpy(targetpath, system_path, FILE_MAX); @@ -345,57 +360,63 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha if (subfolder_name) { /* try $BLENDERPATH/folder_name/subfolder_name */ - return test_path(targetpath, system_path, folder_name, subfolder_name); + return test_path(targetpath, targetpath_len, system_path, folder_name, subfolder_name); } else { /* try $BLENDERPATH/folder_name */ - return test_path(targetpath, system_path, NULL, folder_name); + return test_path(targetpath, targetpath_len, system_path, NULL, folder_name); } } -/* get a folder out of the 'folder_id' presets for paths */ -/* returns the path if found, NULL string if not */ -const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder) +/** + * Get a folder out of the 'folder_id' presets for paths. + * returns the path if found, NULL string if not + * + * \param subfolder: The name of a directory to check for, + * this may contain path separators but must resolve to a directory, checked with #BLI_is_dir. + */ +const char *BKE_appdir_folder_id_ex( + const int folder_id, const char *subfolder, + char *path, size_t path_len) { const int ver = BLENDER_VERSION; - static char path[FILE_MAX] = ""; - + switch (folder_id) { case BLENDER_DATAFILES: /* general case */ - if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break; - if (get_path_local(path, "datafiles", subfolder, ver)) break; - if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break; + if (get_path_user(path, path_len, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break; + if (get_path_local(path, path_len, "datafiles", subfolder, ver)) break; + if (get_path_system(path, path_len, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break; return NULL; case BLENDER_USER_DATAFILES: - if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break; + if (get_path_user(path, path_len, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break; return NULL; case BLENDER_SYSTEM_DATAFILES: - if (get_path_local(path, "datafiles", subfolder, ver)) break; - if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break; + if (get_path_local(path, path_len, "datafiles", subfolder, ver)) break; + if (get_path_system(path, path_len, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break; return NULL; case BLENDER_USER_AUTOSAVE: - if (get_path_user(path, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break; + if (get_path_user(path, path_len, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break; return NULL; case BLENDER_USER_CONFIG: - if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break; + if (get_path_user(path, path_len, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break; return NULL; case BLENDER_USER_SCRIPTS: - if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break; + if (get_path_user(path, path_len, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break; return NULL; case BLENDER_SYSTEM_SCRIPTS: - if (get_path_local(path, "scripts", subfolder, ver)) break; - if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break; + if (get_path_local(path, path_len, "scripts", subfolder, ver)) break; + if (get_path_system(path, path_len, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break; return NULL; case BLENDER_SYSTEM_PYTHON: - if (get_path_local(path, "python", subfolder, ver)) break; - if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break; + if (get_path_local(path, path_len, "python", subfolder, ver)) break; + if (get_path_system(path, path_len, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break; return NULL; default: @@ -406,6 +427,13 @@ const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder) return path; } +const char *BKE_appdir_folder_id( + const int folder_id, const char *subfolder) +{ + static char path[FILE_MAX] = ""; + return BKE_appdir_folder_id_ex(folder_id, subfolder, path, sizeof(path)); +} + /** * Returns the path to a folder in the user area without checking that it actually exists first. */ @@ -416,16 +444,16 @@ const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *su switch (folder_id) { case BLENDER_USER_DATAFILES: - get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver); + get_path_user(path, sizeof(path), "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver); break; case BLENDER_USER_CONFIG: - get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver); + get_path_user(path, sizeof(path), "config", subfolder, "BLENDER_USER_CONFIG", ver); break; case BLENDER_USER_AUTOSAVE: - get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver); + get_path_user(path, sizeof(path), "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver); break; case BLENDER_USER_SCRIPTS: - get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver); + get_path_user(path, sizeof(path), "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver); break; default: BLI_assert(0); @@ -469,13 +497,13 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con bool ok; switch (folder_id) { case BLENDER_RESOURCE_PATH_USER: - ok = get_path_user(path, NULL, NULL, NULL, ver); + ok = get_path_user(path, sizeof(path), NULL, NULL, NULL, ver); break; case BLENDER_RESOURCE_PATH_LOCAL: - ok = get_path_local(path, NULL, NULL, ver); + ok = get_path_local(path, sizeof(path), NULL, NULL, ver); break; case BLENDER_RESOURCE_PATH_SYSTEM: - ok = get_path_system(path, NULL, NULL, NULL, ver); + ok = get_path_system(path, sizeof(path), NULL, NULL, NULL, ver); break; default: path[0] = '\0'; /* in case do_check is false */ @@ -655,6 +683,48 @@ bool BKE_appdir_program_python_search( return is_found; } +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] = { + BLENDER_USER_SCRIPTS, + BLENDER_SYSTEM_SCRIPTS, +}; + +/** + * Return true if templates exist + */ +bool BKE_appdir_app_template_any(void) +{ + char temp_dir[FILE_MAX]; + for (int i = 0; i < 2; i++) { + if (BKE_appdir_folder_id_ex( + app_template_directory_id[i], app_template_directory_search[i], + temp_dir, sizeof(temp_dir))) + { + return true; + } + } + return false; +} + +bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len) +{ + for (int i = 0; i < 2; i++) { + char subdir[FILE_MAX]; + BLI_join_dirfile(subdir, sizeof(subdir), app_template_directory_search[i], app_template); + if (BKE_appdir_folder_id_ex( + app_template_directory_id[i], subdir, + path, path_len)) + { + return true; + } + } + return false; +} + /** * Gets the temp directory when blender first runs. * If the default path is not found, use try $TEMP @@ -713,7 +783,8 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c BLI_add_slash(fullname); #ifdef WIN32 if (userdir && userdir != fullname) { - BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */ + /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */ + BLI_strncpy(userdir, fullname, maxlen); } #endif } diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index f661f18fbc0..ceb641073e0 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -238,6 +238,44 @@ void BKE_blender_userdef_refresh(void) } +/** + * Write U from userdef. + * This function defines which settings a template will override for the user preferences. + */ +void BKE_blender_userdef_set_app_template(UserDef *userdef) +{ + /* TODO: + * - keymaps + * - various minor settings (add as needed). + */ + +#define LIST_OVERRIDE(id) { \ + BLI_freelistN(&U.id); \ + BLI_movelisttolist(&U.id, &userdef->id); \ +} ((void)0) + +#define MEMCPY_OVERRIDE(id) \ + memcpy(U.id, userdef->id, sizeof(U.id)); + + /* for some types we need custom free functions */ + userdef_free_addons(&U); + userdef_free_keymaps(&U); + + LIST_OVERRIDE(uistyles); + LIST_OVERRIDE(uifonts); + LIST_OVERRIDE(themes); + LIST_OVERRIDE(addons); + LIST_OVERRIDE(user_keymaps); + + MEMCPY_OVERRIDE(light); + + MEMCPY_OVERRIDE(font_path_ui); + MEMCPY_OVERRIDE(font_path_ui_mono); + +#undef LIST_OVERRIDE +#undef MEMCPY_OVERRIDE +} + /* ***************** testing for break ************* */ static void (*blender_test_break_cb)(void) = NULL; diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 5725a12e3d4..a521d671ea4 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -356,8 +356,10 @@ int BKE_blendfile_read( BlendFileData *bfd; int retval = BKE_BLENDFILE_READ_OK; - if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) /* don't print user-pref loading */ - printf("read blend: %s\n", filepath); + /* don't print user-pref loading */ + if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) { + printf("Read blend: %s\n", filepath); + } bfd = BLO_read_from_file(filepath, reports, skip_flags); if (bfd) { @@ -424,6 +426,32 @@ bool BKE_blendfile_read_from_memfile( return (bfd != NULL); } +/** + * Utility to make a file 'empty' used for startup to optionally give an empty file. + * Handy for tests. + */ +void BKE_blendfile_read_make_empty(bContext *C) +{ + Main *bmain = CTX_data_main(C); + + ListBase *lbarray[MAX_LIBARRAY]; + ID *id; + int a; + + a = set_listbasepointers(bmain, lbarray); + while (a--) { + id = lbarray[a]->first; + if (id != NULL) { + if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM)) { + continue; + } + while ((id = lbarray[a]->first)) { + BKE_libblock_delete(bmain, id); + } + } + } +} + /* only read the userdef from a .blend */ UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports) { diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 28ef3f6f248..ee0fde1ea61 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -869,12 +869,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d return 0; } - for ( i = 0; i < dm->getNumVerts(dm); i++) { - if ((!(cloth->verts[i].flags & CLOTH_VERT_FLAG_PINNED)) && (cloth->verts[i].goal > ALMOST_ZERO)) { - cloth_add_spring (clmd, i, i, 0.0, CLOTH_SPRING_TYPE_GOAL); - } - } - // init our solver BPH_cloth_solver_init(ob, clmd); @@ -944,37 +938,6 @@ BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1) } } -// be careful: implicit solver has to be resettet when using this one! -// --> only for implicit handling of this spring! -int cloth_add_spring(ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type) -{ - Cloth *cloth = clmd->clothObject; - ClothSpring *spring = NULL; - - if (cloth) { - // TODO: look if this spring is already there - - spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); - - if (!spring) - return 0; - - spring->ij = indexA; - spring->kl = indexB; - spring->restlen = restlength; - spring->type = spring_type; - spring->flags = 0; - spring->stiffness = 0; - - cloth->numsprings++; - - BLI_linklist_prepend ( &cloth->springs, spring ); - - return 1; - } - return 0; -} - static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int mvert_num) { if (edgelist) { diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index c9f0b8ec9ca..7c3f0ac630d 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -33,14 +33,10 @@ /** \file blender/blenkernel/intern/customdata.c * \ingroup bke */ - - -#include <math.h> -#include <string.h> -#include <assert.h> #include "MEM_guardedalloc.h" +#include "DNA_customdata_types.h" #include "DNA_meshdata_types.h" #include "DNA_ID.h" @@ -62,20 +58,16 @@ #include "BKE_mesh_remap.h" #include "BKE_multires.h" -#include "data_transfer_intern.h" - #include "bmesh.h" -#include <math.h> -#include <string.h> +/* only for customdata_data_transfer_interp_normal_normals */ +#include "data_transfer_intern.h" /* number of layers to add when growing a CustomData object */ #define CUSTOMDATA_GROW 5 /* ensure typemap size is ok */ -BLI_STATIC_ASSERT(sizeof(((CustomData *)NULL)->typemap) / - sizeof(((CustomData *)NULL)->typemap[0]) == CD_NUMTYPES, - "size mismatch"); +BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "size mismatch"); /********************* Layer type information **********************/ @@ -805,18 +797,15 @@ static void layerInterp_mloopcol( const float *sub_weights, int count, void *dest) { MLoopCol *mc = dest; - int i; - const float *sub_weight; struct { float a; float r; float g; float b; - } col; - col.a = col.r = col.g = col.b = 0; + } col = {0}; - sub_weight = sub_weights; - for (i = 0; i < count; ++i) { + const float *sub_weight = sub_weights; + for (int i = 0; i < count; ++i) { float weight = weights ? weights[i] : 1; const MLoopCol *src = sources[i]; if (sub_weights) { @@ -833,19 +822,16 @@ static void layerInterp_mloopcol( col.a += src->a * weight; } } - + + /* Subdivide smooth or fractal can cause problems without clamping * although weights should also not cause this situation */ - CLAMP(col.a, 0.0f, 255.0f); - CLAMP(col.r, 0.0f, 255.0f); - CLAMP(col.g, 0.0f, 255.0f); - CLAMP(col.b, 0.0f, 255.0f); - /* delay writing to the destination incase dest is in sources */ - mc->r = (int)col.r; - mc->g = (int)col.g; - mc->b = (int)col.b; - mc->a = (int)col.a; + /* 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); } static int layerMaxNum_mloopcol(void) @@ -1068,15 +1054,10 @@ static void layerInterp_mcol( /* Subdivide smooth or fractal can cause problems without clamping * although weights should also not cause this situation */ - CLAMP(col[j].a, 0.0f, 255.0f); - CLAMP(col[j].r, 0.0f, 255.0f); - CLAMP(col[j].g, 0.0f, 255.0f); - CLAMP(col[j].b, 0.0f, 255.0f); - - mc[j].a = (int)col[j].a; - mc[j].r = (int)col[j].r; - mc[j].g = (int)col[j].g; - mc[j].b = (int)col[j].b; + 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); } } diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 678dc92a5f2..302e55a1f5a 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -3053,7 +3053,7 @@ void DAG_id_type_tag(Main *bmain, short idtype) DAG_id_type_tag(bmain, ID_SCE); } - bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1; + atomic_fetch_and_or_uint8((uint8_t*)&bmain->id_tag_update[BKE_idcode_to_index(idtype)], 1); } int DAG_id_type_tagged(Main *bmain, short idtype) diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index b2641b110f8..074a9a12fe0 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -117,31 +117,35 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array) return narray; } -void IDP_FreeIDPArray(IDProperty *prop) +static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user) { int i; BLI_assert(prop->type == IDP_IDPARRAY); for (i = 0; i < prop->len; i++) - IDP_FreeProperty(GETPROP(prop, i)); + IDP_FreeProperty_ex(GETPROP(prop, i), do_id_user); if (prop->data.pointer) MEM_freeN(prop->data.pointer); } -/*shallow copies item*/ +/* shallow copies item */ void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item) { IDProperty *old; BLI_assert(prop->type == IDP_IDPARRAY); + if (index >= prop->len || index < 0) + return; + old = GETPROP(prop, index); - if (index >= prop->len || index < 0) return; - if (item != old) IDP_FreeProperty(old); - - memcpy(GETPROP(prop, index), item, sizeof(IDProperty)); + if (item != old) { + IDP_FreeProperty(old); + + memcpy(old, item, sizeof(IDProperty)); + } } IDProperty *IDP_GetIndexArray(IDProperty *prop, int index) @@ -433,22 +437,24 @@ void IDP_FreeString(IDProperty *prop) /* -------------------------------------------------------------------- */ -/* ID Type (not in use yet) */ +/* ID Type */ -/** \name IDProperty ID API (unused) +/** \name IDProperty ID API * \{ */ -void IDP_LinkID(IDProperty *prop, ID *id) -{ - if (prop->data.pointer) - id_us_min(((ID *)prop->data.pointer)); - prop->data.pointer = id; - id_us_plus(id); -} -void IDP_UnlinkID(IDProperty *prop) +static IDProperty *IDP_CopyID(const IDProperty *prop) { - id_us_min(((ID *)prop->data.pointer)); + IDProperty *newp; + + BLI_assert(prop->type == IDP_ID); + newp = idp_generic_copy(prop); + + newp->data.pointer = prop->data.pointer; + id_us_plus(IDP_Id(newp)); + + return newp; } + /** \} */ @@ -499,14 +505,9 @@ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src) break; default: { - IDProperty *tmp = other; - IDProperty *copy = IDP_CopyProperty(prop); - - BLI_insertlinkafter(&dest->data.group, other, copy); - BLI_remlink(&dest->data.group, tmp); - - IDP_FreeProperty(tmp); - MEM_freeN(tmp); + BLI_insertlinkreplace(&dest->data.group, other, IDP_CopyProperty(prop)); + IDP_FreeProperty(other); + MEM_freeN(other); break; } } @@ -526,11 +527,9 @@ void IDP_SyncGroupTypes(IDProperty *dst, const IDProperty *src, const bool do_ar if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) || (do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) && (prop_src->len != prop_dst->len))) { - IDP_FreeFromGroup(dst, prop_dst); - prop_dst = IDP_CopyProperty(prop_src); - - dst->len++; - BLI_insertlinkbefore(&dst->data.group, prop_dst_next, prop_dst); + BLI_insertlinkreplace(&dst->data.group, prop_dst, IDP_CopyProperty(prop_src)); + IDP_FreeProperty(prop_dst); + MEM_freeN(prop_dst); } else if (prop_dst->type == IDP_GROUP) { IDP_SyncGroupTypes(prop_dst, prop_src, do_arraylen); @@ -555,11 +554,7 @@ void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src) for (prop = src->data.group.first; prop; prop = prop->next) { for (loop = dest->data.group.first; loop; loop = loop->next) { if (STREQ(loop->name, prop->name)) { - IDProperty *copy = IDP_CopyProperty(prop); - - BLI_insertlinkafter(&dest->data.group, loop, copy); - - BLI_remlink(&dest->data.group, loop); + BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop)); IDP_FreeProperty(loop); MEM_freeN(loop); break; @@ -586,9 +581,7 @@ void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop BLI_assert(prop_exist == IDP_GetPropertyFromGroup(group, prop->name)); if ((prop_exist = IDP_GetPropertyFromGroup(group, prop->name))) { - BLI_insertlinkafter(&group->data.group, prop_exist, prop); - - BLI_remlink(&group->data.group, prop_exist); + BLI_insertlinkreplace(&group->data.group, prop_exist, prop); IDP_FreeProperty(prop_exist); MEM_freeN(prop_exist); } @@ -719,13 +712,13 @@ IDProperty *IDP_GetPropertyTypeFromGroup(IDProperty *prop, const char *name, con * This is because all ID Property freeing functions free only direct data (not the ID Property * struct itself), but for Groups the child properties *are* considered * direct data. */ -static void IDP_FreeGroup(IDProperty *prop) +static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user) { IDProperty *loop; BLI_assert(prop->type == IDP_GROUP); for (loop = prop->data.group.first; loop; loop = loop->next) { - IDP_FreeProperty(loop); + IDP_FreeProperty_ex(loop, do_id_user); } BLI_freelistN(&prop->data.group); } @@ -742,12 +735,51 @@ IDProperty *IDP_CopyProperty(const IDProperty *prop) 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); } } +/* 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) +{ + if (!prop) + return; + + switch (prop->type) { + case IDP_GROUP: + { + for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) { + IDP_RelinkProperty(loop); + } + break; + } + case IDP_IDPARRAY: + { + IDProperty *idp_array = IDP_Array(prop); + for (int i = 0; i < prop->len; i++) { + IDP_RelinkProperty(&idp_array[i]); + } + break; + } + case IDP_ID: + { + ID *id = IDP_Id(prop); + if (id && id->newid) { + id_us_min(IDP_Id(prop)); + prop->data.pointer = id->newid; + id_us_plus(IDP_Id(prop)); + } + break; + } + default: + break; /* Nothing to do for other IDProp types. */ + } +} + /** * Get the Group property that contains the id properties for ID id. Set create_if_needed * to create the Group property and attach it to id if it doesn't exist; otherwise @@ -844,6 +876,8 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is return false; return true; } + case IDP_ID: + return (IDP_Id(prop1) == IDP_Id(prop2)); default: /* should never get here */ BLI_assert(0); @@ -867,17 +901,19 @@ bool IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2) * The union is simple to use; see the top of this header file for its definition. * An example of using this function: * - * IDPropertyTemplate val; - * IDProperty *group, *idgroup, *color; - * group = IDP_New(IDP_GROUP, val, "group1"); //groups don't need a template. + * \code{.c} + * IDPropertyTemplate val; + * IDProperty *group, *idgroup, *color; + * group = IDP_New(IDP_GROUP, val, "group1"); //groups don't need a template. * - * val.array.len = 4 - * val.array.type = IDP_FLOAT; - * color = IDP_New(IDP_ARRAY, val, "color1"); + * val.array.len = 4 + * val.array.type = IDP_FLOAT; + * color = IDP_New(IDP_ARRAY, val, "color1"); * - * idgroup = IDP_GetProperties(some_id, 1); - * IDP_AddToGroup(idgroup, color); - * IDP_AddToGroup(idgroup, group); + * idgroup = IDP_GetProperties(some_id, 1); + * IDP_AddToGroup(idgroup, color); + * IDP_AddToGroup(idgroup, group); + * \endcode * * Note that you MUST either attach the id property to an id property group with * IDP_AddToGroup or MEM_freeN the property, doing anything else might result in @@ -897,7 +933,7 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char * *(float *)&prop->data.val = val->f; break; case IDP_DOUBLE: - prop = MEM_callocN(sizeof(IDProperty), "IDProperty float"); + prop = MEM_callocN(sizeof(IDProperty), "IDProperty double"); *(double *)&prop->data.val = val->d; break; case IDP_ARRAY: @@ -917,6 +953,7 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char * prop->len = prop->totallen = val->array.len; break; } + printf("%s: bad array type.\n",__func__); return NULL; } case IDP_STRING: @@ -963,6 +1000,14 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char * /* heh I think all needed values are set properly by calloc anyway :) */ break; } + case IDP_ID: + { + prop = MEM_callocN(sizeof(IDProperty), "IDProperty datablock"); + prop->data.pointer = (void *)val->id; + prop->type = IDP_ID; + id_us_plus(IDP_Id(prop)); + break; + } default: { prop = MEM_callocN(sizeof(IDProperty), "IDProperty array"); @@ -977,11 +1022,10 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char * } /** - * \note this will free all child properties of list arrays and groups! - * Also, note that this does NOT unlink anything! Plus it doesn't free - * the actual struct IDProperty struct either. + * \note This will free allocated data, all child properties of arrays and groups, and unlink IDs! + * But it does not free the actual IDProperty struct itself. */ -void IDP_FreeProperty(IDProperty *prop) +void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user) { switch (prop->type) { case IDP_ARRAY: @@ -991,14 +1035,24 @@ void IDP_FreeProperty(IDProperty *prop) IDP_FreeString(prop); break; case IDP_GROUP: - IDP_FreeGroup(prop); + IDP_FreeGroup(prop, do_id_user); break; case IDP_IDPARRAY: - IDP_FreeIDPArray(prop); + IDP_FreeIDPArray(prop, do_id_user); + break; + case IDP_ID: + if (do_id_user) { + id_us_min(IDP_Id(prop)); + } break; } } +void IDP_FreeProperty(IDProperty *prop) +{ + IDP_FreeProperty_ex(prop, true); +} + void IDP_ClearProperty(IDProperty *prop) { IDP_FreeProperty(prop); @@ -1006,18 +1060,4 @@ void IDP_ClearProperty(IDProperty *prop) prop->len = prop->totallen = 0; } -/** - * Unlinks any struct IDProperty<->ID linkage that might be going on. - * - * \note currently unused - */ -void IDP_UnlinkProperty(IDProperty *prop) -{ - switch (prop->type) { - case IDP_ID: - IDP_UnlinkID(prop); - break; - } -} - /** \} */ diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 9685f1f5af6..0616c614848 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -33,6 +33,7 @@ #include "DNA_actuator_types.h" #include "DNA_anim_types.h" +#include "DNA_armature_types.h" #include "DNA_brush_types.h" #include "DNA_camera_types.h" #include "DNA_constraint_types.h" @@ -70,10 +71,12 @@ #include "BKE_animsys.h" #include "BKE_constraint.h" #include "BKE_fcurve.h" +#include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_main.h" #include "BKE_modifier.h" +#include "BKE_node.h" #include "BKE_particle.h" #include "BKE_rigidbody.h" #include "BKE_sca.h" @@ -82,7 +85,9 @@ #define FOREACH_FINALIZE _finalize -#define FOREACH_FINALIZE_VOID FOREACH_FINALIZE: (void)0 +#define FOREACH_FINALIZE_VOID \ + if (0) { goto FOREACH_FINALIZE; } \ + FOREACH_FINALIZE: ((void)0) #define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, _cb_flag) \ CHECK_TYPE(id_pp, ID **); \ @@ -140,6 +145,37 @@ typedef struct LibraryForeachIDData { BLI_LINKSTACK_DECLARE(ids_todo, ID *); } LibraryForeachIDData; +static void library_foreach_idproperty_ID_link(LibraryForeachIDData *data, IDProperty *prop, int flag) +{ + if (!prop) + return; + + switch (prop->type) { + case IDP_GROUP: + { + for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) { + library_foreach_idproperty_ID_link(data, loop, flag); + } + break; + } + case IDP_IDPARRAY: + { + IDProperty *loop = IDP_Array(prop); + for (int i = 0; i < prop->len; i++) { + library_foreach_idproperty_ID_link(data, &loop[i], flag); + } + break; + } + case IDP_ID: + FOREACH_CALLBACK_INVOKE_ID(data, prop->data.pointer, flag); + break; + default: + break; /* Nothing to do here with other types of IDProperties... */ + } + + FOREACH_FINALIZE_VOID; +} + static void library_foreach_rigidbodyworldSceneLooper( struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cb_flag) { @@ -265,6 +301,17 @@ static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint) FOREACH_FINALIZE_VOID; } +static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone) +{ + library_foreach_idproperty_ID_link(data, bone->prop, IDWALK_CB_USER); + + for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) { + library_foreach_bone(data, curbone); + } + + FOREACH_FINALIZE_VOID; +} + static void library_foreach_ID_as_subdata_link( ID **id_pp, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data) { @@ -337,6 +384,8 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call continue; } + library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER); + AnimData *adt = BKE_animdata_from_id(id); if (adt) { library_foreach_animationData(&data, adt); @@ -402,6 +451,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER); CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER); CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER); + library_foreach_idproperty_ID_link(&data, seq->prop, IDWALK_CB_USER); for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) { CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER); } @@ -515,6 +565,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call data.cb_flag |= proxy_cb_flag; for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) { + library_foreach_idproperty_ID_link(&data, pchan->prop, IDWALK_CB_USER); CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER); BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data); } @@ -554,6 +605,16 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call break; } + case ID_AR: + { + bArmature *arm = (bArmature *)id; + + for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) { + library_foreach_bone(&data, bone); + } + break; + } + case ID_ME: { Mesh *mesh = (Mesh *) id; @@ -736,9 +797,27 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call { bNodeTree *ntree = (bNodeTree *) id; bNode *node; + bNodeSocket *sock; + CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER); + for (node = ntree->nodes.first; node; node = node->next) { CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER); + + library_foreach_idproperty_ID_link(&data, node->prop, IDWALK_CB_USER); + for (sock = node->inputs.first; sock; sock = sock->next) { + library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER); + } + for (sock = node->outputs.first; sock; sock = sock->next) { + library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER); + } + } + + for (sock = ntree->inputs.first; sock; sock = sock->next) { + library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER); + } + for (sock = ntree->outputs.first; sock; sock = sock->next) { + library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER); } break; } @@ -898,7 +977,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call case ID_VF: case ID_TXT: case ID_SO: - case ID_AR: case ID_GD: case ID_WM: case ID_PAL: @@ -948,9 +1026,25 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag) */ /* XXX This has to be fully rethink, basing check on ID type is not really working anymore (and even worth once * IDProps will support ID pointers), we'll have to do some quick checks on IDs themselves... */ -bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used) +bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) { - if (id_type_can_have_animdata(id_type_owner)) { + /* any type of ID can be used in custom props. */ + if (id_owner->properties) { + return true; + } + + const short id_type_owner = GS(id_owner->name); + + /* IDProps of armature bones and nodes, and bNode->id can use virtually any type of ID. */ + if (ELEM(id_type_owner, ID_NT, ID_AR)) { + return true; + } + + if (ntreeFromID(id_owner)) { + return true; + } + + if (BKE_animdata_from_id(id_owner)) { return true; /* AnimationData can use virtually any kind of datablocks, through drivers especially. */ } @@ -959,8 +1053,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id return ELEM(id_type_used, ID_LI); case ID_SCE: return (ELEM(id_type_used, ID_OB, ID_WO, ID_SCE, ID_MC, ID_MA, ID_GR, ID_TXT, - ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT) || - BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT)); case ID_OB: /* Could be the following, but simpler to just always say 'yes' here. */ #if 0 @@ -977,13 +1070,13 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id case ID_MB: return ELEM(id_type_used, ID_MA); case ID_MA: - return (ELEM(id_type_used, ID_TE, ID_GR) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + return (ELEM(id_type_used, ID_TE, ID_GR)); case ID_TE: - return (ELEM(id_type_used, ID_IM, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + return (ELEM(id_type_used, ID_IM, ID_OB)); case ID_LT: return ELEM(id_type_used, ID_KE); case ID_LA: - return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + return (ELEM(id_type_used, ID_TE)); case ID_CA: return ELEM(id_type_used, ID_OB); case ID_KE: @@ -991,7 +1084,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id case ID_SCR: return ELEM(id_type_used, ID_SCE); case ID_WO: - return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + return (ELEM(id_type_used, ID_TE)); case ID_SPK: return ELEM(id_type_used, ID_SO); case ID_GR: @@ -1012,7 +1105,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id case ID_MSK: return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */ case ID_LS: - return (ELEM(id_type_used, ID_TE, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + return (ELEM(id_type_used, ID_TE, ID_OB)); case ID_IM: case ID_VF: case ID_TXT: @@ -1118,7 +1211,7 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked) while (i-- && !is_defined) { ID *id_curr = lb_array[i]->first; - if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) { + if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) { continue; } @@ -1170,7 +1263,7 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo while (i-- && !is_defined) { ID *id_curr = lb_array[i]->first; - if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) { + if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) { continue; } diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index b6f4621a0b3..d14e0cf0b65 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -448,20 +448,16 @@ ATTR_NONNULL(1) static void libblock_remap_data( * objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */ while (i--) { - ID *id_curr = lb_array[i]->first; - - if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(old_id->name))) { - continue; - } - - for (; id_curr; id_curr = id_curr->next) { - /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for - * the user count handling... - * XXX No more true (except for debug usage of those skipping counters). */ - r_id_remap_data->id = id_curr; - libblock_remap_data_preprocess(r_id_remap_data); - BKE_library_foreach_ID_link( - NULL, id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP); + for (ID *id_curr = lb_array[i]->first; id_curr; id_curr = id_curr->next) { + if (BKE_library_id_can_use_idtype(id_curr, GS(old_id->name))) { + /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for + * the user count handling... + * XXX No more true (except for debug usage of those skipping counters). */ + r_id_remap_data->id = id_curr; + libblock_remap_data_preprocess(r_id_remap_data); + BKE_library_foreach_ID_link( + NULL, id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP); + } } } } @@ -723,10 +719,10 @@ void BKE_libblock_relink_to_newid(ID *id) BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0); } -void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id) +void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id, const bool do_id_user) { if (id->properties) { - IDP_FreeProperty(id->properties); + IDP_FreeProperty_ex(id->properties, do_id_user); MEM_freeN(id->properties); } } @@ -876,7 +872,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b BLI_remlink(lb, id); - BKE_libblock_free_data(bmain, id); + BKE_libblock_free_data(bmain, id, do_id_user); BKE_main_unlock(bmain); MEM_freeN(id); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 3f3b4896653..f3223e31b17 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1828,7 +1828,7 @@ void ntreeFreeTree(bNodeTree *ntree) if (tntree == ntree) break; if (tntree == NULL) { - BKE_libblock_free_data(G.main, &ntree->id); + BKE_libblock_free_data(G.main, &ntree->id, true); } } diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index e3b801b3193..eb7abc2f004 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -64,6 +64,7 @@ #include "BLI_strict_flags.h" +#include "BLI_hash.h" /* Dupli-Geometry */ @@ -180,6 +181,22 @@ static DupliObject *make_dupli(const DupliContext *ctx, if (ob->type == OB_MBALL) dob->no_draw = true; + /* random number */ + /* the logic here is designed to match Cycles */ + dob->random_id = BLI_hash_string(dob->ob->id.name + 2); + + if (dob->persistent_id[0] != INT_MAX) { + for(i = 0; i < MAX_DUPLI_RECUR*2; i++) + dob->random_id = BLI_hash_int_2d(dob->random_id, (unsigned int)dob->persistent_id[i]); + } + else { + dob->random_id = BLI_hash_int_2d(dob->random_id, 0); + } + + if (ctx->object != ob) { + dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2)); + } + return dob; } diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h new file mode 100644 index 00000000000..551143f5d72 --- /dev/null +++ b/source/blender/blenlib/BLI_hash.h @@ -0,0 +1,66 @@ +/* + * ***** 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_HASH_H__ +#define __BLI_HASH_H__ + +/** \file BLI_hash.h + * \ingroup bli + */ + +static inline unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky) +{ +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + + unsigned int a, b, c; + + a = b = c = 0xdeadbeef + (2 << 2) + 13; + a += kx; + b += ky; + + c ^= b; c -= rot(b,14); + a ^= c; a -= rot(c,11); + b ^= a; b -= rot(a,25); + c ^= b; c -= rot(b,16); + a ^= c; a -= rot(c,4); + b ^= a; b -= rot(a,14); + c ^= b; c -= rot(b,24); + + return c; + +#undef rot +} + +static inline unsigned int BLI_hash_string(const char *str) +{ + unsigned int i = 0, c; + + while((c = *str++)) + i = i * 37 + c; + + return i; +} + +static inline unsigned int BLI_hash_int(unsigned int k) +{ + return BLI_hash_int_2d(k, 0); +} + +#endif // __BLI_HASH_H__ diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index 96349a7b066..00e761b81bc 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -67,6 +67,7 @@ void *BLI_poptail(ListBase *listbase) ATTR_NONNULL(1); void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1); void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1); void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1); +void BLI_insertlinkreplace(ListBase *listbase, void *v_l_src, void *v_l_dst) ATTR_NONNULL(1, 2, 3); void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void *)) ATTR_NONNULL(1, 2); void BLI_listbase_sort_r(ListBase *listbase, int (*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1, 2); bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL(); diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index baa1f792018..b6a55d34d14 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -39,14 +39,6 @@ extern "C" { struct ListBase; -#ifdef WIN32 -#define SEP '\\' -#define ALTSEP '/' -#else -#define SEP '/' -#define ALTSEP '\\' -#endif - void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1); void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1); @@ -60,7 +52,13 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file) ATTR_NONNULL(); void BLI_join_dirfile(char *__restrict string, const size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL(); +size_t BLI_path_join( + char *__restrict dst, const size_t dst_len, + const char *path_first, ...) ATTR_NONNULL(1, 3) ATTR_SENTINEL(0); const char *BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; +bool BLI_path_name_at_index( + const char *__restrict path, const int index, + int *__restrict r_offset, int *__restrict r_len) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; #if 0 typedef enum bli_rebase_state { @@ -83,7 +81,6 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen); #endif bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name); -void BLI_getlastdir(const char *dir, char *last, const size_t maxlen); bool BLI_testextensie(const char *str, const char *ext) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; bool BLI_testextensie_n(const char *str, ...) ATTR_NONNULL(1) ATTR_SENTINEL(0); bool BLI_testextensie_array(const char *str, const char **ext_array) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; @@ -143,6 +140,18 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char # define FILE_MAX 1024 #endif +#ifdef WIN32 +# define SEP '\\' +# define ALTSEP '/' +# define SEP_STR "\\" +# define ALTSEP_STR "/" +#else +# define SEP '/' +# define ALTSEP '\\' +# define SEP_STR "/" +# define ALTSEP_STR "\\" +#endif + /* Parent and current dir helpers. */ #define FILENAME_PARENT ".." #define FILENAME_CURRENT "." diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index c9bf4976ae8..6cb7b7d8e3e 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -342,6 +342,40 @@ void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink) } } + +/** + * Insert a link in place of another, without changing it's position in the list. + * + * Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`. + * - `vreplacelink` *must* be in the list. + * - `vnewlink` *must not* be in the list. + */ +void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink) +{ + Link *l_old = vreplacelink; + Link *l_new = vnewlink; + + /* update adjacent links */ + if (l_old->next != NULL) { + l_old->next->prev = l_new; + } + if (l_old->prev != NULL) { + l_old->prev->next = l_new; + } + + /* set direct links */ + l_new->next = l_old->next; + l_new->prev = l_old->prev; + + /* update list */ + if (listbase->first == l_old) { + listbase->first = l_new; + } + if (listbase->last == l_old) { + listbase->last = l_new; + } +} + /** * Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move * item if new position would exceed list (could optionally move to head/tail). diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 6644e6605a1..7b765cfa939 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1167,30 +1167,6 @@ bool BLI_path_program_search( } /** - * Copies into *last the part of *dir following the second-last slash. - */ -void BLI_getlastdir(const char *dir, char *last, const size_t maxlen) -{ - const char *s = dir; - const char *lslash = NULL; - const char *prevslash = NULL; - while (*s) { - if ((*s == '\\') || (*s == '/')) { - prevslash = lslash; - lslash = s; - } - s++; - } - if (prevslash) { - BLI_strncpy(last, prevslash + 1, maxlen); - } - else { - BLI_strncpy(last, dir, maxlen); - } -} - - -/** * Sets the specified environment variable to the specified value, * and clears it if val == NULL. */ @@ -1615,6 +1591,90 @@ void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__r } /** + * Join multiple strings into a path, ensuring only a single path separator between each, + * and trailing slash is kept. + * + * \note If you want a trailing slash, add ``SEP_STR`` as the last path argument, + * duplicate slashes will be cleaned up. + */ +size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path, ...) +{ + if (UNLIKELY(dst_len == 0)) { + return 0; + } + const size_t dst_last = dst_len - 1; + size_t ofs = BLI_strncpy_rlen(dst, path, dst_len); + + if (ofs == dst_last) { + return ofs; + } + + /* remove trailing slashes, unless there are _only_ trailing slashes + * (allow "//" as the first argument). */ + bool has_trailing_slash = false; + if (ofs != 0) { + size_t len = ofs; + while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) { + len -= 1; + } + if (len != 0) { + ofs = len; + } + has_trailing_slash = (path[len] != '\0'); + } + + va_list args; + va_start(args, path); + while ((path = (const char *) va_arg(args, const char *))) { + has_trailing_slash = false; + const char *path_init = path; + while (ELEM(path[0], SEP, ALTSEP)) { + path++; + } + size_t len = strlen(path); + if (len != 0) { + while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) { + len -= 1; + } + + if (len != 0) { + /* the very first path may have a slash at the end */ + if (ofs && !ELEM(dst[ofs - 1], SEP, ALTSEP)) { + dst[ofs++] = SEP; + if (ofs == dst_last) { + break; + } + } + has_trailing_slash = (path[len] != '\0'); + if (ofs + len >= dst_last) { + len = dst_last - ofs; + } + memcpy(&dst[ofs], path, len); + ofs += len; + if (ofs == dst_last) { + break; + } + } + } + else { + has_trailing_slash = (path_init != path); + } + } + va_end(args); + + if (has_trailing_slash) { + if ((ofs != dst_last) && (ofs != 0) && (ELEM(dst[ofs - 1], SEP, ALTSEP) == 0)) { + dst[ofs++] = SEP; + } + } + + BLI_assert(ofs <= dst_last); + dst[ofs] = '\0'; + + return ofs; +} + +/** * like pythons os.path.basename() * * \return The pointer into \a path string immediately after last slash, @@ -1626,6 +1686,71 @@ const char *BLI_path_basename(const char *path) return filename ? filename + 1 : path; } +/** + * Get an element of the path at an index, eg: + * "/some/path/file.txt" where an index of... + * - 0 or -3: "some" + * - 1 or -2: "path" + * - 2 or -1: "file.txt" + * + * Ignores multiple slashes at any point in the path (including start/end). + */ +bool BLI_path_name_at_index(const char *path, const int index, int *r_offset, int *r_len) +{ + if (index >= 0) { + int index_step = 0; + int prev = -1; + int i = 0; + while (true) { + const char c = path[i]; + if (ELEM(c, SEP, ALTSEP, '\0')) { + if (prev + 1 != i) { + prev += 1; + if (index_step == index) { + *r_offset = prev; + *r_len = i - prev; + /* printf("!!! %d %d\n", start, end); */ + return true; + } + index_step += 1; + } + if (c == '\0') { + break; + } + prev = i; + } + i += 1; + } + return false; + } + else { + /* negative number, reverse where -1 is the last element */ + int index_step = -1; + int prev = strlen(path); + int i = prev - 1; + while (true) { + const char c = i >= 0 ? path[i] : '\0'; + if (ELEM(c, SEP, ALTSEP, '\0')) { + if (prev - 1 != i) { + i += 1; + if (index_step == index) { + *r_offset = i; + *r_len = prev - i; + return true; + } + index_step -= 1; + } + if (c == '\0') { + break; + } + prev = i; + } + i -= 1; + } + return false; + } +} + /* UNUSED */ #if 0 /** diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c index 17e20f8fa18..eb4e6e91aee 100644 --- a/source/blender/blenlib/intern/task.c +++ b/source/blender/blenlib/intern/task.c @@ -162,6 +162,16 @@ struct TaskPool { */ int thread_id; + /* For the pools which are created from non-main thread which is not a + * scheduler worker thread we can't re-use any of scheduler's threads TLS + * and have to use our own one. + */ + bool use_local_tls; + TaskThreadLocalStorage local_tls; +#ifndef NDEBUG + pthread_t creator_thread_id; +#endif + #ifdef DEBUG_STATS TaskMemPoolStats *mempool_stats; #endif @@ -202,13 +212,25 @@ BLI_INLINE void task_data_free(Task *task, const int thread_id) } } +BLI_INLINE void initialize_task_tls(TaskThreadLocalStorage *tls) +{ + memset(tls, 0, sizeof(TaskThreadLocalStorage)); +} + BLI_INLINE TaskThreadLocalStorage *get_task_tls(TaskPool *pool, const int thread_id) { TaskScheduler *scheduler = pool->scheduler; BLI_assert(thread_id >= 0); BLI_assert(thread_id <= scheduler->num_threads); + if (pool->use_local_tls && thread_id == 0) { + BLI_assert(pool->thread_id == 0); + BLI_assert(!BLI_thread_is_main()); + BLI_assert(pthread_equal(pthread_self(), pool->creator_thread_id)); + return &pool->local_tls; + } if (thread_id == 0) { + BLI_assert(BLI_thread_is_main()); return &scheduler->task_threads[pool->thread_id].tls; } return &scheduler->task_threads[thread_id].tls; @@ -252,6 +274,9 @@ static void task_free(TaskPool *pool, Task *task, const int thread_id) task_data_free(task, thread_id); BLI_assert(thread_id >= 0); BLI_assert(thread_id <= pool->scheduler->num_threads); + if (thread_id == 0) { + BLI_assert(pool->use_local_tls || BLI_thread_is_main()); + } TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id); TaskMemPool *task_mempool = &tls->task_mempool; if (task_mempool->num_tasks < MEMPOOL_SIZE - 1) { @@ -424,9 +449,12 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads) num_threads = 1; } - scheduler->task_threads = MEM_callocN(sizeof(TaskThread) * (num_threads + 1), + scheduler->task_threads = MEM_mallocN(sizeof(TaskThread) * (num_threads + 1), "TaskScheduler task threads"); + /* Initialize TLS for main thread. */ + initialize_task_tls(&scheduler->task_threads[0].tls); + pthread_key_create(&scheduler->tls_id_key, NULL); /* launch threads that will be waiting for work */ @@ -440,6 +468,7 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads) TaskThread *thread = &scheduler->task_threads[i + 1]; thread->scheduler = scheduler; thread->id = i + 1; + initialize_task_tls(&thread->tls); if (pthread_create(&scheduler->threads[i], NULL, task_scheduler_thread_run, thread) != 0) { fprintf(stderr, "TaskScheduler failed to launch thread %d/%d\n", i, num_threads); @@ -572,6 +601,7 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, pool->num_suspended = 0; pool->suspended_queue.first = pool->suspended_queue.last = NULL; pool->run_in_background = is_background; + pool->use_local_tls = false; BLI_mutex_init(&pool->num_mutex); BLI_condition_init(&pool->num_cond); @@ -584,13 +614,18 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, } else { TaskThread *thread = pthread_getspecific(scheduler->tls_id_key); - /* NOTE: It is possible that pool is created from non-main thread - * which isn't a scheduler thread. In this case pthread's TLS will - * be NULL and we can safely consider thread id 0 for the main - * thread of this pool (the one which does wort_and_wait()). - */ if (thread == NULL) { + /* NOTE: Task pool is created from non-main thread which is not + * managed by the task scheduler. We identify ourselves as thread ID + * 0 but we do not use scheduler's TLS storage and use our own + * instead to avoid any possible threading conflicts. + */ pool->thread_id = 0; + pool->use_local_tls = true; +#ifndef NDEBUG + pool->creator_thread_id = pthread_self(); +#endif + initialize_task_tls(&pool->local_tls); } else { pool->thread_id = thread->id; @@ -670,6 +705,10 @@ void BLI_task_pool_free(TaskPool *pool) MEM_freeN(pool->mempool_stats); #endif + if (pool->use_local_tls) { + free_task_tls(&pool->local_tls); + } + MEM_freeN(pool); BLI_end_threaded_malloc(); @@ -743,9 +782,7 @@ void BLI_task_pool_work_and_wait(TaskPool *pool) BLI_condition_notify_all(&scheduler->queue_cond); BLI_mutex_unlock(&scheduler->queue_mutex); - } - pool->is_suspended = false; } pool->do_work = true; diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 8cb9ef837b2..3d2e8a306de 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -69,6 +69,12 @@ if(WITH_BUILDINFO) add_definitions(-DWITH_BUILDINFO) endif() +if(WITH_PYTHON) + if(WITH_PYTHON_SECURITY) + add_definitions(-DWITH_PYTHON_SECURITY) + endif() +endif() + if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index fb80585dc2a..2900f9e4fc4 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -129,6 +129,7 @@ #include "BKE_library_idmap.h" #include "BKE_library_query.h" #include "BKE_idcode.h" +#include "BKE_idprop.h" #include "BKE_material.h" #include "BKE_main.h" // for Main #include "BKE_mesh.h" // for ME_ defines (patching) @@ -2001,7 +2002,7 @@ static void test_pointer_array(FileData *fd, void **mat) /* ************ READ ID Properties *************** */ static void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, FileData *fd); -static void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, FileData *fd); +static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd); static void IDP_DirectLinkIDPArray(IDProperty *prop, int switch_endian, FileData *fd) { @@ -2132,10 +2133,39 @@ static void _IDP_DirectLinkGroup_OrFree(IDProperty **prop, int switch_endian, Fi } } -/* stub function */ -static void IDP_LibLinkProperty(IDProperty *UNUSED(prop), int UNUSED(switch_endian), FileData *UNUSED(fd)) +static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd) { - /* Should we do something here, prop should be ensured to be non-NULL first... */ + if (!prop) + return; + + switch (prop->type) { + case IDP_ID: /* PointerProperty */ + { + void *newaddr = newlibadr_us(fd, NULL, IDP_Id(prop)); + if (IDP_Id(prop) && !newaddr && G.debug) { + printf("Error while loading \"%s\". Data not found in file!\n", prop->name); + } + prop->data.pointer = newaddr; + break; + } + case IDP_IDPARRAY: /* CollectionProperty */ + { + IDProperty *idp_array = IDP_IDPArray(prop); + for (int i = 0; i < prop->len; i++) { + IDP_LibLinkProperty(&(idp_array[i]), fd); + } + break; + } + case IDP_GROUP: /* PointerProperty */ + { + for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) { + IDP_LibLinkProperty(loop, fd); + } + break; + } + default: + break; /* Nothing to do for other IDProps. */ + } } /* ************ READ IMAGE PREVIEW *************** */ @@ -2192,19 +2222,19 @@ static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap) /* library brush linking after fileread */ static void lib_link_brush(FileData *fd, Main *main) { - Brush *brush; - /* only link ID pointers */ - for (brush = main->brush.first; brush; brush = brush->id.next) { + for (Brush *brush = main->brush.first; brush; brush = brush->id.next) { if (brush->id.tag & LIB_TAG_NEED_LINK) { - brush->id.tag &= ~LIB_TAG_NEED_LINK; - + IDP_LibLinkProperty(brush->id.properties, fd); + /* brush->(mask_)mtex.obj is ignored on purpose? */ brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex); brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex); brush->clone.image = newlibadr(fd, brush->id.lib, brush->clone.image); brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush); brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve); + + brush->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -2227,13 +2257,13 @@ static void direct_link_brush(FileData *fd, Brush *brush) } /* ************ READ Palette *************** */ -static void lib_link_palette(FileData *UNUSED(fd), Main *main) +static void lib_link_palette(FileData *fd, Main *main) { - Palette *palette; - /* only link ID pointers */ - for (palette = main->palettes.first; palette; palette = palette->id.next) { + for (Palette *palette = main->palettes.first; palette; palette = palette->id.next) { if (palette->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(palette->id.properties, fd); + palette->id.tag &= ~LIB_TAG_NEED_LINK; } } @@ -2245,13 +2275,13 @@ static void direct_link_palette(FileData *fd, Palette *palette) link_list(fd, &palette->colors); } -static void lib_link_paint_curve(FileData *UNUSED(fd), Main *main) +static void lib_link_paint_curve(FileData *fd, Main *main) { - PaintCurve *pc; - /* only link ID pointers */ - for (pc = main->paintcurves.first; pc; pc = pc->id.next) { + for (PaintCurve *pc = main->paintcurves.first; pc; pc = pc->id.next) { if (pc->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(pc->id.properties, fd); + pc->id.tag &= ~LIB_TAG_NEED_LINK; } } @@ -2503,15 +2533,12 @@ static void direct_link_fcurves(FileData *fd, ListBase *list) static void lib_link_action(FileData *fd, Main *main) { - bAction *act; - bActionChannel *chan; - - for (act = main->action.first; act; act = act->id.next) { + for (bAction *act = main->action.first; act; act = act->id.next) { if (act->id.tag & LIB_TAG_NEED_LINK) { - act->id.tag &= ~LIB_TAG_NEED_LINK; + IDP_LibLinkProperty(act->id.properties, fd); // XXX deprecated - old animation system <<< - for (chan=act->chanbase.first; chan; chan=chan->next) { + for (bActionChannel *chan = act->chanbase.first; chan; chan = chan->next) { chan->ipo = newlibadr_us(fd, act->id.lib, chan->ipo); lib_link_constraint_channels(fd, &act->id, &chan->constraintChannels); } @@ -2524,6 +2551,8 @@ static void lib_link_action(FileData *fd, Main *main) marker->camera = newlibadr(fd, act->id.lib, marker->camera); } } + + act->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -2710,26 +2739,20 @@ static void direct_link_animdata(FileData *fd, AnimData *adt) static void lib_link_cachefiles(FileData *fd, Main *bmain) { - CacheFile *cache_file; - /* only link ID pointers */ - for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) { + for (CacheFile *cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) { if (cache_file->id.tag & LIB_TAG_NEED_LINK) { - cache_file->id.tag &= ~LIB_TAG_NEED_LINK; - } - - BLI_listbase_clear(&cache_file->object_paths); - cache_file->handle = NULL; - cache_file->handle_mutex = NULL; - - if (cache_file->adt) { + IDP_LibLinkProperty(cache_file->id.properties, fd); lib_link_animdata(fd, &cache_file->id, cache_file->adt); + + cache_file->id.tag &= ~LIB_TAG_NEED_LINK; } } } static void direct_link_cachefile(FileData *fd, CacheFile *cache_file) { + BLI_listbase_clear(&cache_file->object_paths); cache_file->handle = NULL; cache_file->handle_mutex = NULL; @@ -2753,19 +2776,13 @@ static void direct_link_motionpath(FileData *fd, bMotionPath *mpath) /* ************ READ NODE TREE *************** */ -static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock) -{ - /* Link ID Properties -- and copy this comment EXACTLY for easy finding - * of library blocks that implement this.*/ - IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); -} - /* Single node tree (also used for material/scene trees), ntree is not NULL */ static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree) { bNode *node; bNodeSocket *sock; + IDP_LibLinkProperty(ntree->id.properties, fd); lib_link_animdata(fd, &ntree->id, ntree->adt); ntree->gpd = newlibadr_us(fd, id->lib, ntree->gpd); @@ -2773,32 +2790,35 @@ static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree) for (node = ntree->nodes.first; node; node = node->next) { /* Link ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - IDP_LibLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_LibLinkProperty(node->prop, fd); - node->id= newlibadr_us(fd, id->lib, node->id); + node->id = newlibadr_us(fd, id->lib, node->id); - for (sock = node->inputs.first; sock; sock = sock->next) - lib_link_node_socket(fd, id, sock); - for (sock = node->outputs.first; sock; sock = sock->next) - lib_link_node_socket(fd, id, sock); + for (sock = node->inputs.first; sock; sock = sock->next) { + IDP_LibLinkProperty(sock->prop, fd); + } + for (sock = node->outputs.first; sock; sock = sock->next) { + IDP_LibLinkProperty(sock->prop, fd); + } } - for (sock = ntree->inputs.first; sock; sock = sock->next) - lib_link_node_socket(fd, id, sock); - for (sock = ntree->outputs.first; sock; sock = sock->next) - lib_link_node_socket(fd, id, sock); + for (sock = ntree->inputs.first; sock; sock = sock->next) { + IDP_LibLinkProperty(sock->prop, fd); + } + for (sock = ntree->outputs.first; sock; sock = sock->next) { + IDP_LibLinkProperty(sock->prop, fd); + } } /* library ntree linking after fileread */ static void lib_link_nodetree(FileData *fd, Main *main) { - bNodeTree *ntree; - /* only link ID pointers */ - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) { + for (bNodeTree *ntree = main->nodetree.first; ntree; ntree = ntree->id.next) { if (ntree->id.tag & LIB_TAG_NEED_LINK) { - ntree->id.tag &= ~LIB_TAG_NEED_LINK; lib_link_ntree(fd, &ntree->id, ntree); + + ntree->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3291,6 +3311,8 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose) pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name); + IDP_LibLinkProperty(pchan->prop, fd); + pchan->custom = newlibadr_us(fd, arm->id.lib, pchan->custom); if (UNLIKELY(pchan->bone == NULL)) { rebuild = true; @@ -3311,13 +3333,26 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose) } } +static void lib_link_bones(FileData *fd, Bone *bone) +{ + IDP_LibLinkProperty(bone->prop, fd); + + for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) { + lib_link_bones(fd, curbone); + } +} + static void lib_link_armature(FileData *fd, Main *main) { - bArmature *arm; - - for (arm = main->armature.first; arm; arm = arm->id.next) { + for (bArmature *arm = main->armature.first; arm; arm = arm->id.next) { if (arm->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(arm->id.properties, fd); lib_link_animdata(fd, &arm->id, arm->adt); + + for (Bone *curbone = arm->bonebase.first; curbone; curbone = curbone->next) { + lib_link_bones(fd, curbone); + } + arm->id.tag &= ~LIB_TAG_NEED_LINK; } } @@ -3362,14 +3397,13 @@ static void direct_link_armature(FileData *fd, bArmature *arm) static void lib_link_camera(FileData *fd, Main *main) { - Camera *ca; - - for (ca = main->camera.first; ca; ca = ca->id.next) { + for (Camera *ca = main->camera.first; ca; ca = ca->id.next) { if (ca->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(ca->id.properties, fd); lib_link_animdata(fd, &ca->id, ca->adt); ca->ipo = newlibadr_us(fd, ca->id.lib, ca->ipo); // XXX deprecated - old animation system - + ca->dof_ob = newlibadr(fd, ca->id.lib, ca->dof_ob); ca->id.tag &= ~LIB_TAG_NEED_LINK; @@ -3388,16 +3422,13 @@ static void direct_link_camera(FileData *fd, Camera *ca) static void lib_link_lamp(FileData *fd, Main *main) { - Lamp *la; - MTex *mtex; - int a; - - for (la = main->lamp.first; la; la = la->id.next) { + for (Lamp *la = main->lamp.first; la; la = la->id.next) { if (la->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(la->id.properties, fd); lib_link_animdata(fd, &la->id, la->adt); - for (a = 0; a < MAX_MTEX; a++) { - mtex = la->mtex[a]; + for (int a = 0; a < MAX_MTEX; a++) { + MTex *mtex = la->mtex[a]; if (mtex) { mtex->tex = newlibadr_us(fd, la->id.lib, mtex->tex); mtex->object = newlibadr(fd, la->id.lib, mtex->object); @@ -3454,17 +3485,11 @@ void blo_do_versions_key_uidgen(Key *key) static void lib_link_key(FileData *fd, Main *main) { - Key *key; - - for (key = main->key.first; key; key = key->id.next) { - /*check if we need to generate unique ids for the shapekeys*/ - if (!key->uidgen) { - blo_do_versions_key_uidgen(key); - } - + for (Key *key = main->key.first; key; key = key->id.next) { BLI_assert((key->id.tag & LIB_TAG_EXTERN) == 0); if (key->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(key->id.properties, fd); lib_link_animdata(fd, &key->id, key->adt); key->ipo = newlibadr_us(fd, key->id.lib, key->ipo); // XXX deprecated - old animation system @@ -3527,15 +3552,14 @@ static void direct_link_key(FileData *fd, Key *key) static void lib_link_mball(FileData *fd, Main *main) { - MetaBall *mb; - int a; - - for (mb = main->mball.first; mb; mb = mb->id.next) { + for (MetaBall *mb = main->mball.first; mb; mb = mb->id.next) { if (mb->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(mb->id.properties, fd); lib_link_animdata(fd, &mb->id, mb->adt); - for (a = 0; a < mb->totcol; a++) + for (int a = 0; a < mb->totcol; a++) { mb->mat[a] = newlibadr_us(fd, mb->id.lib, mb->mat[a]); + } mb->ipo = newlibadr_us(fd, mb->id.lib, mb->ipo); // XXX deprecated - old animation system @@ -3564,18 +3588,15 @@ static void direct_link_mball(FileData *fd, MetaBall *mb) static void lib_link_world(FileData *fd, Main *main) { - World *wrld; - MTex *mtex; - int a; - - for (wrld = main->world.first; wrld; wrld = wrld->id.next) { + for (World *wrld = main->world.first; wrld; wrld = wrld->id.next) { if (wrld->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(wrld->id.properties, fd); lib_link_animdata(fd, &wrld->id, wrld->adt); wrld->ipo = newlibadr_us(fd, wrld->id.lib, wrld->ipo); // XXX deprecated - old animation system - for (a=0; a < MAX_MTEX; a++) { - mtex = wrld->mtex[a]; + for (int a = 0; a < MAX_MTEX; a++) { + MTex *mtex = wrld->mtex[a]; if (mtex) { mtex->tex = newlibadr_us(fd, wrld->id.lib, mtex->tex); mtex->object = newlibadr(fd, wrld->id.lib, mtex->object); @@ -3616,12 +3637,12 @@ static void direct_link_world(FileData *fd, World *wrld) /* ************ READ VFONT ***************** */ -static void lib_link_vfont(FileData *UNUSED(fd), Main *main) +static void lib_link_vfont(FileData *fd, Main *main) { - VFont *vf; - - for (vf = main->vfont.first; vf; vf = vf->id.next) { + for (VFont *vf = main->vfont.first; vf; vf = vf->id.next) { if (vf->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(vf->id.properties, fd); + vf->id.tag &= ~LIB_TAG_NEED_LINK; } } @@ -3636,12 +3657,12 @@ static void direct_link_vfont(FileData *fd, VFont *vf) /* ************ READ TEXT ****************** */ -static void lib_link_text(FileData *UNUSED(fd), Main *main) +static void lib_link_text(FileData *fd, Main *main) { - Text *text; - - for (text = main->text.first; text; text = text->id.next) { + for (Text *text = main->text.first; text; text = text->id.next) { if (text->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(text->id.properties, fd); + text->id.tag &= ~LIB_TAG_NEED_LINK; } } @@ -3690,11 +3711,9 @@ static void direct_link_text(FileData *fd, Text *text) static void lib_link_image(FileData *fd, Main *main) { - Image *ima; - - for (ima = main->image.first; ima; ima = ima->id.next) { + for (Image *ima = main->image.first; ima; ima = ima->id.next) { if (ima->id.tag & LIB_TAG_NEED_LINK) { - IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_LibLinkProperty(ima->id.properties, fd); ima->id.tag &= ~LIB_TAG_NEED_LINK; } @@ -3759,15 +3778,14 @@ static void direct_link_image(FileData *fd, Image *ima) static void lib_link_curve(FileData *fd, Main *main) { - Curve *cu; - int a; - - for (cu = main->curve.first; cu; cu = cu->id.next) { + for (Curve *cu = main->curve.first; cu; cu = cu->id.next) { if (cu->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(cu->id.properties, fd); lib_link_animdata(fd, &cu->id, cu->adt); - for (a = 0; a < cu->totcol; a++) + for (int a = 0; a < cu->totcol; a++) { cu->mat[a] = newlibadr_us(fd, cu->id.lib, cu->mat[a]); + } cu->bevobj = newlibadr(fd, cu->id.lib, cu->bevobj); cu->taperobj = newlibadr(fd, cu->id.lib, cu->taperobj); @@ -3852,10 +3870,9 @@ static void direct_link_curve(FileData *fd, Curve *cu) static void lib_link_texture(FileData *fd, Main *main) { - Tex *tex; - - for (tex = main->tex.first; tex; tex = tex->id.next) { + for (Tex *tex = main->tex.first; tex; tex = tex->id.next) { if (tex->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(tex->id.properties, fd); lib_link_animdata(fd, &tex->id, tex->adt); tex->ima = newlibadr_us(fd, tex->id.lib, tex->ima); @@ -3931,23 +3948,20 @@ static void direct_link_texture(FileData *fd, Tex *tex) static void lib_link_material(FileData *fd, Main *main) { - Material *ma; - MTex *mtex; - int a; - - for (ma = main->mat.first; ma; ma = ma->id.next) { + for (Material *ma = main->mat.first; ma; ma = ma->id.next) { if (ma->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(ma->id.properties, fd); lib_link_animdata(fd, &ma->id, ma->adt); /* Link ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_LibLinkProperty(ma->id.properties, fd); ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo); // XXX deprecated - old animation system ma->group = newlibadr_us(fd, ma->id.lib, ma->group); - for (a = 0; a < MAX_MTEX; a++) { - mtex = ma->mtex[a]; + for (int a = 0; a < MAX_MTEX; a++) { + MTex *mtex = ma->mtex[a]; if (mtex) { mtex->tex = newlibadr_us(fd, ma->id.lib, mtex->tex); mtex->object = newlibadr(fd, ma->id.lib, mtex->object); @@ -4078,14 +4092,11 @@ static void lib_link_partdeflect(FileData *fd, ID *id, PartDeflect *pd) static void lib_link_particlesettings(FileData *fd, Main *main) { - ParticleSettings *part; - ParticleDupliWeight *dw; - MTex *mtex; - int a; - - for (part = main->particle.first; part; part = part->id.next) { + for (ParticleSettings *part = main->particle.first; part; part = part->id.next) { if (part->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(part->id.properties, fd); lib_link_animdata(fd, &part->id, part->adt); + part->ipo = newlibadr_us(fd, part->id.lib, part->ipo); // XXX deprecated - old animation system part->dup_ob = newlibadr(fd, part->id.lib, part->dup_ob); @@ -4105,6 +4116,7 @@ static void lib_link_particlesettings(FileData *fd, Main *main) } if (part->dupliweights.first && part->dup_group) { + ParticleDupliWeight *dw; int index_ok = 0; /* check for old files without indices (all indexes 0) */ if (BLI_listbase_is_single(&part->dupliweights)) { @@ -4169,8 +4181,8 @@ static void lib_link_particlesettings(FileData *fd, Main *main) } } - for (a = 0; a < MAX_MTEX; a++) { - mtex= part->mtex[a]; + for (int a = 0; a < MAX_MTEX; a++) { + MTex *mtex= part->mtex[a]; if (mtex) { mtex->tex = newlibadr_us(fd, part->id.lib, mtex->tex); mtex->object = newlibadr(fd, part->id.lib, mtex->object); @@ -4404,7 +4416,7 @@ static void lib_link_mesh(FileData *fd, Main *main) /* Link ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - IDP_LibLinkProperty(me->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_LibLinkProperty(me->id.properties, fd); lib_link_animdata(fd, &me->id, me->adt); /* this check added for python created meshes */ @@ -4677,10 +4689,9 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh) static void lib_link_latt(FileData *fd, Main *main) { - Lattice *lt; - - for (lt = main->latt.first; lt; lt = lt->id.next) { + for (Lattice *lt = main->latt.first; lt; lt = lt->id.next) { if (lt->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(lt->id.properties, fd); lib_link_animdata(fd, <->id, lt->adt); lt->ipo = newlibadr_us(fd, lt->id.lib, lt->ipo); // XXX deprecated - old animation system @@ -4724,17 +4735,13 @@ static void lib_link_modifiers(FileData *fd, Object *ob) static void lib_link_object(FileData *fd, Main *main) { - Object *ob; - PartEff *paf; - bSensor *sens; - bController *cont; - bActuator *act; - void *poin; - int warn=0, a; - - for (ob = main->object.first; ob; ob = ob->id.next) { + bool warn = false; + + for (Object *ob = main->object.first; ob; ob = ob->id.next) { if (ob->id.tag & LIB_TAG_NEED_LINK) { - IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + int a; + + IDP_LibLinkProperty(ob->id.properties, fd); lib_link_animdata(fd, &ob->id, ob->adt); // XXX deprecated - old animation system <<< @@ -4766,17 +4773,17 @@ static void lib_link_object(FileData *fd, Main *main) } ob->proxy_group = newlibadr(fd, ob->id.lib, ob->proxy_group); - poin = ob->data; + void *poin = ob->data; ob->data = newlibadr_us(fd, ob->id.lib, ob->data); - if (ob->data==NULL && poin!=NULL) { + if (ob->data == NULL && poin != NULL) { if (ob->id.lib) printf("Can't find obdata of %s lib %s\n", ob->id.name + 2, ob->id.lib->name); else printf("Object %s lost data.\n", ob->id.name + 2); ob->type = OB_EMPTY; - warn = 1; + warn = true; if (ob->pose) { /* we can't call #BKE_pose_free() here because of library linking @@ -4822,13 +4829,13 @@ static void lib_link_object(FileData *fd, Main *main) lib_link_nlastrips(fd, &ob->id, &ob->nlastrips); // >>> XXX deprecated - old animation system - for (paf = ob->effect.first; paf; paf = paf->next) { + for (PartEff *paf = ob->effect.first; paf; paf = paf->next) { if (paf->type == EFF_PARTICLE) { paf->group = newlibadr_us(fd, ob->id.lib, paf->group); } } - for (sens = ob->sensors.first; sens; sens = sens->next) { + for (bSensor *sens = ob->sensors.first; sens; sens = sens->next) { for (a = 0; a < sens->totlinks; a++) sens->links[a] = newglobadr(fd, sens->links[a]); @@ -4839,7 +4846,7 @@ static void lib_link_object(FileData *fd, Main *main) } } - for (cont = ob->controllers.first; cont; cont = cont->next) { + for (bController *cont = ob->controllers.first; cont; cont = cont->next) { for (a=0; a < cont->totlinks; a++) cont->links[a] = newglobadr(fd, cont->links[a]); @@ -4851,86 +4858,117 @@ static void lib_link_object(FileData *fd, Main *main) cont->totslinks = 0; } - for (act = ob->actuators.first; act; act = act->next) { - if (act->type == ACT_SOUND) { - bSoundActuator *sa = act->data; - sa->sound= newlibadr_us(fd, ob->id.lib, sa->sound); - } - else if (act->type == ACT_GAME) { - /* bGameActuator *ga= act->data; */ - } - else if (act->type == ACT_CAMERA) { - bCameraActuator *ca = act->data; - ca->ob= newlibadr(fd, ob->id.lib, ca->ob); - } - /* leave this one, it's obsolete but necessary to read for conversion */ - else if (act->type == ACT_ADD_OBJECT) { - bAddObjectActuator *eoa = act->data; - if (eoa) eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob); - } - else if (act->type == ACT_OBJECT) { - bObjectActuator *oa = act->data; - if (oa == NULL) { - init_actuator(act); + for (bActuator *act = ob->actuators.first; act; act = act->next) { + switch (act->type) { + case ACT_SOUND: + { + bSoundActuator *sa = act->data; + sa->sound = newlibadr_us(fd, ob->id.lib, sa->sound); + break; } - else { - oa->reference = newlibadr(fd, ob->id.lib, oa->reference); + case ACT_GAME: + /* bGameActuator *ga= act->data; */ + break; + case ACT_CAMERA: + { + bCameraActuator *ca = act->data; + ca->ob = newlibadr(fd, ob->id.lib, ca->ob); + break; } - } - else if (act->type == ACT_EDIT_OBJECT) { - bEditObjectActuator *eoa = act->data; - if (eoa == NULL) { - init_actuator(act); + /* leave this one, it's obsolete but necessary to read for conversion */ + case ACT_ADD_OBJECT: + { + bAddObjectActuator *eoa = act->data; + if (eoa) + eoa->ob = newlibadr(fd, ob->id.lib, eoa->ob); + break; } - else { - eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob); - eoa->me= newlibadr(fd, ob->id.lib, eoa->me); + case ACT_OBJECT: + { + bObjectActuator *oa = act->data; + if (oa == NULL) { + init_actuator(act); + } + else { + oa->reference = newlibadr(fd, ob->id.lib, oa->reference); + } + break; } - } - else if (act->type == ACT_SCENE) { - bSceneActuator *sa = act->data; - sa->camera= newlibadr(fd, ob->id.lib, sa->camera); - sa->scene= newlibadr(fd, ob->id.lib, sa->scene); - } - else if (act->type == ACT_ACTION) { - bActionActuator *aa = act->data; - aa->act= newlibadr_us(fd, ob->id.lib, aa->act); - } - else if (act->type == ACT_SHAPEACTION) { - bActionActuator *aa = act->data; - aa->act= newlibadr_us(fd, ob->id.lib, aa->act); - } - else if (act->type == ACT_PROPERTY) { - bPropertyActuator *pa = act->data; - pa->ob= newlibadr(fd, ob->id.lib, pa->ob); - } - else if (act->type == ACT_MESSAGE) { - bMessageActuator *ma = act->data; - ma->toObject= newlibadr(fd, ob->id.lib, ma->toObject); - } - else if (act->type == ACT_2DFILTER) { - bTwoDFilterActuator *_2dfa = act->data; - _2dfa->text= newlibadr(fd, ob->id.lib, _2dfa->text); - } - else if (act->type == ACT_PARENT) { - bParentActuator *parenta = act->data; - parenta->ob = newlibadr(fd, ob->id.lib, parenta->ob); - } - else if (act->type == ACT_STATE) { - /* bStateActuator *statea = act->data; */ - } - else if (act->type == ACT_ARMATURE) { - bArmatureActuator *arma= act->data; - arma->target= newlibadr(fd, ob->id.lib, arma->target); - arma->subtarget= newlibadr(fd, ob->id.lib, arma->subtarget); - } - else if (act->type == ACT_STEERING) { - bSteeringActuator *steeringa = act->data; - steeringa->target = newlibadr(fd, ob->id.lib, steeringa->target); - steeringa->navmesh = newlibadr(fd, ob->id.lib, steeringa->navmesh); - } - else if (act->type == ACT_MOUSE) { - /* bMouseActuator *moa= act->data; */ + case ACT_EDIT_OBJECT: + { + bEditObjectActuator *eoa = act->data; + if (eoa == NULL) { + init_actuator(act); + } + else { + eoa->ob = newlibadr(fd, ob->id.lib, eoa->ob); + eoa->me = newlibadr(fd, ob->id.lib, eoa->me); + } + break; + } + case ACT_SCENE: + { + bSceneActuator *sa = act->data; + sa->camera = newlibadr(fd, ob->id.lib, sa->camera); + sa->scene = newlibadr(fd, ob->id.lib, sa->scene); + break; + } + case ACT_ACTION: + { + bActionActuator *aa = act->data; + aa->act = newlibadr_us(fd, ob->id.lib, aa->act); + break; + } + case ACT_SHAPEACTION: + { + bActionActuator *aa = act->data; + aa->act = newlibadr_us(fd, ob->id.lib, aa->act); + break; + } + case ACT_PROPERTY: + { + bPropertyActuator *pa = act->data; + pa->ob = newlibadr(fd, ob->id.lib, pa->ob); + break; + } + case ACT_MESSAGE: + { + bMessageActuator *ma = act->data; + ma->toObject = newlibadr(fd, ob->id.lib, ma->toObject); + break; + } + case ACT_2DFILTER: + { + bTwoDFilterActuator *_2dfa = act->data; + _2dfa->text = newlibadr(fd, ob->id.lib, _2dfa->text); + break; + } + case ACT_PARENT: + { + bParentActuator *parenta = act->data; + parenta->ob = newlibadr(fd, ob->id.lib, parenta->ob); + break; + } + case ACT_STATE: + /* bStateActuator *statea = act->data; */ + break; + case ACT_ARMATURE: + { + bArmatureActuator *arma= act->data; + arma->target = newlibadr(fd, ob->id.lib, arma->target); + arma->subtarget = newlibadr(fd, ob->id.lib, arma->subtarget); + break; + } + case ACT_STEERING: + { + bSteeringActuator *steeringa = act->data; + steeringa->target = newlibadr(fd, ob->id.lib, steeringa->target); + steeringa->navmesh = newlibadr(fd, ob->id.lib, steeringa->navmesh); + break; + } + case ACT_MOUSE: + /* bMouseActuator *moa = act->data; */ + break; } } @@ -5662,23 +5700,16 @@ static bool scene_validate_setscene__liblink(Scene *sce, const int totscene) static void lib_link_scene(FileData *fd, Main *main) { - Scene *sce; - Base *base, *next; - Sequence *seq; - SceneRenderLayer *srl; - FreestyleModuleConfig *fmc; - FreestyleLineSet *fls; - #ifdef USE_SETSCENE_CHECK bool need_check_set = false; int totscene = 0; #endif - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (Scene *sce = main->scene.first; sce; sce = sce->id.next) { if (sce->id.tag & LIB_TAG_NEED_LINK) { /* Link ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_LibLinkProperty(sce->id.properties, fd); lib_link_animdata(fd, &sce->id, sce->adt); lib_link_keyingsets(fd, &sce->id, &sce->keyingsets); @@ -5714,7 +5745,7 @@ static void lib_link_scene(FileData *fd, Main *main) sce->toolsettings->particle.shape_object = newlibadr(fd, sce->id.lib, sce->toolsettings->particle.shape_object); - for (base = sce->base.first; base; base = next) { + for (Base *next, *base = sce->base.first; base; base = next) { next = base->next; base->object = newlibadr_us(fd, sce->id.lib, base->object); @@ -5728,8 +5759,11 @@ static void lib_link_scene(FileData *fd, Main *main) } } + Sequence *seq; SEQ_BEGIN (sce->ed, seq) { + IDP_LibLinkProperty(seq->prop, fd); + if (seq->ipo) seq->ipo = newlibadr_us(fd, sce->id.lib, seq->ipo); // XXX deprecated - old animation system seq->scene_sound = NULL; if (seq->scene) { @@ -5793,13 +5827,13 @@ static void lib_link_scene(FileData *fd, Main *main) composite_patch(sce->nodetree, sce); } - for (srl = sce->r.layers.first; srl; srl = srl->next) { + for (SceneRenderLayer *srl = sce->r.layers.first; srl; srl = srl->next) { srl->mat_override = newlibadr_us(fd, sce->id.lib, srl->mat_override); srl->light_override = newlibadr_us(fd, sce->id.lib, srl->light_override); - for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) { + for (FreestyleModuleConfig *fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) { fmc->script = newlibadr(fd, sce->id.lib, fmc->script); } - for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) { + for (FreestyleLineSet *fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) { fls->linestyle = newlibadr_us(fd, sce->id.lib, fls->linestyle); fls->group = newlibadr_us(fd, sce->id.lib, fls->group); } @@ -5833,7 +5867,7 @@ static void lib_link_scene(FileData *fd, Main *main) #ifdef USE_SETSCENE_CHECK if (need_check_set) { - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (Scene *sce = main->scene.first; sce; sce = sce->id.next) { if (sce->id.tag & LIB_TAG_NEED_LINK) { sce->id.tag &= ~LIB_TAG_NEED_LINK; if (!scene_validate_setscene__liblink(sce, totscene)) { @@ -6243,8 +6277,10 @@ static void lib_link_windowmanager(FileData *fd, Main *main) for (wm = main->wm.first; wm; wm = wm->id.next) { if (wm->id.tag & LIB_TAG_NEED_LINK) { - for (win = wm->windows.first; win; win = win->next) + /* Note: WM IDProperties are never written to file, hence no need to read/link them here. */ + for (win = wm->windows.first; win; win = win->next) { win->screen = newlibadr(fd, NULL, win->screen); + } wm->id.tag &= ~LIB_TAG_NEED_LINK; } @@ -6256,13 +6292,12 @@ static void lib_link_windowmanager(FileData *fd, Main *main) /* relink's grease pencil data's refs */ static void lib_link_gpencil(FileData *fd, Main *main) { - bGPdata *gpd; - - for (gpd = main->gpencil.first; gpd; gpd = gpd->id.next) { + for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) { if (gpd->id.tag & LIB_TAG_NEED_LINK) { - gpd->id.tag &= ~LIB_TAG_NEED_LINK; - + IDP_LibLinkProperty(gpd->id.properties, fd); lib_link_animdata(fd, &gpd->id, gpd->adt); + + gpd->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -6324,12 +6359,11 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd) * check lib pointers in call below */ static void lib_link_screen(FileData *fd, Main *main) { - bScreen *sc; - ScrArea *sa; - - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) { if (sc->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(sc->id.properties, fd); id_us_ensure_real(&sc->id); + sc->scene = newlibadr(fd, sc->id.lib, sc->scene); /* this should not happen, but apparently it does somehow. Until we figure out the cause, @@ -6340,178 +6374,205 @@ static void lib_link_screen(FileData *fd, Main *main) sc->animtimer = NULL; /* saved in rare cases */ sc->scrubbing = false; - for (sa = sc->areabase.first; sa; sa = sa->next) { - SpaceLink *sl; - + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { sa->full = newlibadr(fd, sc->id.lib, sa->full); - for (sl = sa->spacedata.first; sl; sl= sl->next) { - if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D*) sl; - BGpic *bgpic = NULL; - - v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera); - v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre); - - /* should be do_versions but not easy adding into the listbase */ - if (v3d->bgpic) { - v3d->bgpic = newlibadr(fd, sc->id.lib, v3d->bgpic); - BLI_addtail(&v3d->bgpicbase, bgpic); - v3d->bgpic = NULL; + for (SpaceLink *sl = sa->spacedata.first; sl; sl= sl->next) { + switch (sl->spacetype) { + case SPACE_VIEW3D: + { + View3D *v3d = (View3D*) sl; + BGpic *bgpic = NULL; + + v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera); + v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre); + + /* should be do_versions but not easy adding into the listbase */ + if (v3d->bgpic) { + v3d->bgpic = newlibadr(fd, sc->id.lib, v3d->bgpic); + BLI_addtail(&v3d->bgpicbase, bgpic); + v3d->bgpic = NULL; + } + + for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { + bgpic->ima = newlibadr_us(fd, sc->id.lib, bgpic->ima); + bgpic->clip = newlibadr_us(fd, sc->id.lib, bgpic->clip); + } + if (v3d->localvd) { + v3d->localvd->camera = newlibadr(fd, sc->id.lib, v3d->localvd->camera); + } + break; } - - for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { - bgpic->ima = newlibadr_us(fd, sc->id.lib, bgpic->ima); - bgpic->clip = newlibadr_us(fd, sc->id.lib, bgpic->clip); + case SPACE_IPO: + { + SpaceIpo *sipo = (SpaceIpo *)sl; + bDopeSheet *ads = sipo->ads; + + if (ads) { + ads->source = newlibadr(fd, sc->id.lib, ads->source); + ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp); + } + break; } - if (v3d->localvd) { - v3d->localvd->camera = newlibadr(fd, sc->id.lib, v3d->localvd->camera); + case SPACE_BUTS: + { + SpaceButs *sbuts = (SpaceButs *)sl; + sbuts->pinid = newlibadr(fd, sc->id.lib, sbuts->pinid); + if (sbuts->pinid == NULL) { + sbuts->flag &= ~SB_PIN_CONTEXT; + } + break; } - } - else if (sl->spacetype == SPACE_IPO) { - SpaceIpo *sipo = (SpaceIpo *)sl; - bDopeSheet *ads = sipo->ads; - - if (ads) { - ads->source = newlibadr(fd, sc->id.lib, ads->source); - ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp); + case SPACE_FILE: + break; + case SPACE_ACTION: + { + SpaceAction *saction = (SpaceAction *)sl; + bDopeSheet *ads = &saction->ads; + + if (ads) { + ads->source = newlibadr(fd, sc->id.lib, ads->source); + ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp); + } + + saction->action = newlibadr(fd, sc->id.lib, saction->action); + break; } - } - else if (sl->spacetype == SPACE_BUTS) { - SpaceButs *sbuts = (SpaceButs *)sl; - sbuts->pinid = newlibadr(fd, sc->id.lib, sbuts->pinid); - if (sbuts->pinid == NULL) { - sbuts->flag &= ~SB_PIN_CONTEXT; + case SPACE_IMAGE: + { + SpaceImage *sima = (SpaceImage *)sl; + + sima->image = newlibadr_real_us(fd, sc->id.lib, sima->image); + sima->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sima->mask_info.mask); + + /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data + * so fingers crossed this works fine! + */ + sima->gpd = newlibadr_us(fd, sc->id.lib, sima->gpd); + break; } - } - else if (sl->spacetype == SPACE_FILE) { - ; - } - else if (sl->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)sl; - bDopeSheet *ads = &saction->ads; - - if (ads) { - ads->source = newlibadr(fd, sc->id.lib, ads->source); - ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp); + case SPACE_SEQ: + { + SpaceSeq *sseq = (SpaceSeq *)sl; + + /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data + * so fingers crossed this works fine! + */ + sseq->gpd = newlibadr_us(fd, sc->id.lib, sseq->gpd); + break; } - - saction->action = newlibadr(fd, sc->id.lib, saction->action); - } - else if (sl->spacetype == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)sl; - - sima->image = newlibadr_real_us(fd, sc->id.lib, sima->image); - sima->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sima->mask_info.mask); - - /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data - * so fingers crossed this works fine! - */ - sima->gpd = newlibadr_us(fd, sc->id.lib, sima->gpd); - } - else if (sl->spacetype == SPACE_SEQ) { - SpaceSeq *sseq = (SpaceSeq *)sl; - - /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data - * so fingers crossed this works fine! - */ - sseq->gpd = newlibadr_us(fd, sc->id.lib, sseq->gpd); + case SPACE_NLA: + { + SpaceNla *snla= (SpaceNla *)sl; + bDopeSheet *ads= snla->ads; + + if (ads) { + ads->source = newlibadr(fd, sc->id.lib, ads->source); + ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp); + } + break; + } + case SPACE_TEXT: + { + SpaceText *st= (SpaceText *)sl; - } - else if (sl->spacetype == SPACE_NLA) { - SpaceNla *snla= (SpaceNla *)sl; - bDopeSheet *ads= snla->ads; - - if (ads) { - ads->source = newlibadr(fd, sc->id.lib, ads->source); - ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp); + st->text= newlibadr(fd, sc->id.lib, st->text); + break; } - } - else if (sl->spacetype == SPACE_TEXT) { - SpaceText *st= (SpaceText *)sl; - - st->text= newlibadr(fd, sc->id.lib, st->text); - } - else if (sl->spacetype == SPACE_SCRIPT) { - SpaceScript *scpt = (SpaceScript *)sl; - /*scpt->script = NULL; - 2.45 set to null, better re-run the script */ - if (scpt->script) { - scpt->script = newlibadr(fd, sc->id.lib, scpt->script); + case SPACE_SCRIPT: + { + SpaceScript *scpt = (SpaceScript *)sl; + /*scpt->script = NULL; - 2.45 set to null, better re-run the script */ if (scpt->script) { - SCRIPT_SET_NULL(scpt->script); + scpt->script = newlibadr(fd, sc->id.lib, scpt->script); + if (scpt->script) { + SCRIPT_SET_NULL(scpt->script); + } } + break; } - } - else if (sl->spacetype == SPACE_OUTLINER) { - SpaceOops *so= (SpaceOops *)sl; - so->search_tse.id = newlibadr(fd, NULL, so->search_tse.id); - - if (so->treestore) { - TreeStoreElem *tselem; - BLI_mempool_iter iter; + case SPACE_OUTLINER: + { + SpaceOops *so= (SpaceOops *)sl; + so->search_tse.id = newlibadr(fd, NULL, so->search_tse.id); + + if (so->treestore) { + TreeStoreElem *tselem; + BLI_mempool_iter iter; + + BLI_mempool_iternew(so->treestore, &iter); + while ((tselem = BLI_mempool_iterstep(&iter))) { + tselem->id = newlibadr(fd, NULL, tselem->id); + } + if (so->treehash) { + /* rebuild hash table, because it depends on ids too */ + so->storeflag |= SO_TREESTORE_REBUILD; + } + } + break; + } + case SPACE_NODE: + { + SpaceNode *snode = (SpaceNode *)sl; + bNodeTreePath *path, *path_next; + bNodeTree *ntree; + + /* node tree can be stored locally in id too, link this first */ + snode->id = newlibadr(fd, sc->id.lib, snode->id); + snode->from = newlibadr(fd, sc->id.lib, snode->from); + + ntree = snode->id ? ntreeFromID(snode->id) : NULL; + snode->nodetree = ntree ? ntree : newlibadr_us(fd, sc->id.lib, snode->nodetree); + + for (path = snode->treepath.first; path; path = path->next) { + if (path == snode->treepath.first) { + /* first nodetree in path is same as snode->nodetree */ + path->nodetree = snode->nodetree; + } + else + path->nodetree = newlibadr_us(fd, sc->id.lib, path->nodetree); - BLI_mempool_iternew(so->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - tselem->id = newlibadr(fd, NULL, tselem->id); + if (!path->nodetree) + break; } - if (so->treehash) { - /* rebuild hash table, because it depends on ids too */ - so->storeflag |= SO_TREESTORE_REBUILD; + + /* remaining path entries are invalid, remove */ + for (; path; path = path_next) { + path_next = path->next; + + BLI_remlink(&snode->treepath, path); + MEM_freeN(path); } - } - } - else if (sl->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)sl; - bNodeTreePath *path, *path_next; - bNodeTree *ntree; - - /* node tree can be stored locally in id too, link this first */ - snode->id = newlibadr(fd, sc->id.lib, snode->id); - snode->from = newlibadr(fd, sc->id.lib, snode->from); - - ntree = snode->id ? ntreeFromID(snode->id) : NULL; - snode->nodetree = ntree ? ntree : newlibadr_us(fd, sc->id.lib, snode->nodetree); - - for (path = snode->treepath.first; path; path = path->next) { - if (path == snode->treepath.first) { - /* first nodetree in path is same as snode->nodetree */ - path->nodetree = snode->nodetree; + + /* edittree is just the last in the path, + * set this directly since the path may have been shortened above */ + if (snode->treepath.last) { + path = snode->treepath.last; + snode->edittree = path->nodetree; } - else - path->nodetree = newlibadr_us(fd, sc->id.lib, path->nodetree); - - if (!path->nodetree) - break; + else { + snode->edittree = NULL; + } + break; } - - /* remaining path entries are invalid, remove */ - for (; path; path = path_next) { - path_next = path->next; - - BLI_remlink(&snode->treepath, path); - MEM_freeN(path); + case SPACE_CLIP: + { + SpaceClip *sclip = (SpaceClip *)sl; + + sclip->clip = newlibadr_real_us(fd, sc->id.lib, sclip->clip); + sclip->secondary_clip = newlibadr_real_us(fd, sc->id.lib, sclip->secondary_clip); + sclip->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sclip->mask_info.mask); + break; } - - /* edittree is just the last in the path, - * set this directly since the path may have been shortened above */ - if (snode->treepath.last) { - path = snode->treepath.last; - snode->edittree = path->nodetree; + case SPACE_LOGIC: + { + SpaceLogic *slogic = (SpaceLogic *)sl; + + slogic->gpd = newlibadr_us(fd, sc->id.lib, slogic->gpd); + break; } - else - snode->edittree = NULL; - } - else if (sl->spacetype == SPACE_CLIP) { - SpaceClip *sclip = (SpaceClip *)sl; - - sclip->clip = newlibadr_real_us(fd, sc->id.lib, sclip->clip); - sclip->secondary_clip = newlibadr_real_us(fd, sc->id.lib, sclip->secondary_clip); - sclip->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sclip->mask_info.mask); - } - else if (sl->spacetype == SPACE_LOGIC) { - SpaceLogic *slogic = (SpaceLogic *)sl; - - slogic->gpd = newlibadr_us(fd, sc->id.lib, slogic->gpd); + default: + break; } } } @@ -7386,13 +7447,13 @@ static void fix_relpaths_library(const char *basepath, Main *main) static void lib_link_speaker(FileData *fd, Main *main) { - Speaker *spk; - - for (spk = main->speaker.first; spk; spk = spk->id.next) { + for (Speaker *spk = main->speaker.first; spk; spk = spk->id.next) { if (spk->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(spk->id.properties, fd); lib_link_animdata(fd, &spk->id, spk->adt); spk->sound = newlibadr_us(fd, spk->id.lib, spk->sound); + spk->id.tag &= ~LIB_TAG_NEED_LINK; } } @@ -7442,14 +7503,15 @@ static void direct_link_sound(FileData *fd, bSound *sound) static void lib_link_sound(FileData *fd, Main *main) { - bSound *sound; - - for (sound = main->sound.first; sound; sound = sound->id.next) { + for (bSound *sound = main->sound.first; sound; sound = sound->id.next) { if (sound->id.tag & LIB_TAG_NEED_LINK) { - sound->id.tag &= ~LIB_TAG_NEED_LINK; + IDP_LibLinkProperty(sound->id.properties, fd); + sound->ipo = newlibadr_us(fd, sound->id.lib, sound->ipo); // XXX deprecated - old animation system BKE_sound_load(main, sound); + + sound->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -7464,17 +7526,13 @@ static void direct_link_group(FileData *fd, Group *group) static void lib_link_group(FileData *fd, Main *main) { - Group *group; - GroupObject *go; - bool add_us; - - for (group = main->group.first; group; group = group->id.next) { + for (Group *group = main->group.first; group; group = group->id.next) { if (group->id.tag & LIB_TAG_NEED_LINK) { - group->id.tag &= ~LIB_TAG_NEED_LINK; + IDP_LibLinkProperty(group->id.properties, fd); - add_us = false; + bool add_us = false; - for (go = group->gobject.first; go; go = go->next) { + for (GroupObject *go = group->gobject.first; go; go = go->next) { go->ob = newlibadr_real_us(fd, group->id.lib, go->ob); if (go->ob) { go->ob->flag |= OB_FROMGROUP; @@ -7486,6 +7544,8 @@ static void lib_link_group(FileData *fd, Main *main) id_us_ensure_real(&group->id); } BKE_group_object_unlink(group, NULL, NULL, NULL); /* removes NULL entries */ + + group->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -7608,13 +7668,11 @@ static void lib_link_movieCorrespondences(FileData *fd, static void lib_link_movieclip(FileData *fd, Main *main) { - MovieClip *clip; - - for (clip = main->movieclip.first; clip; clip = clip->id.next) { + for (MovieClip *clip = main->movieclip.first; clip; clip = clip->id.next) { if (clip->id.tag & LIB_TAG_NEED_LINK) { MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *object; + IDP_LibLinkProperty(clip->id.properties, fd); lib_link_animdata(fd, &clip->id, clip->adt); clip->gpd = newlibadr_us(fd, clip->id.lib, clip->gpd); @@ -7623,7 +7681,7 @@ static void lib_link_movieclip(FileData *fd, Main *main) lib_link_moviePlaneTracks(fd, clip, &tracking->plane_tracks); lib_link_movieCorrespondences(fd, clip, &tracking->correspondences); - for (object = tracking->objects.first; object; object = object->next) { + for (MovieTrackingObject *object = tracking->objects.first; object; object = object->next) { lib_link_movieTracks(fd, clip, &object->tracks); lib_link_moviePlaneTracks(fd, clip, &object->plane_tracks); } @@ -7700,16 +7758,12 @@ static void lib_link_mask_parent(FileData *fd, Mask *mask, MaskParent *parent) static void lib_link_mask(FileData *fd, Main *main) { - Mask *mask; - - mask = main->mask.first; - while (mask) { + for (Mask *mask = main->mask.first; mask; mask = mask->id.next) { if (mask->id.tag & LIB_TAG_NEED_LINK) { - MaskLayer *masklay; - + IDP_LibLinkProperty(mask->id.properties, fd); lib_link_animdata(fd, &mask->id, mask->adt); - for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + for (MaskLayer *masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; spline = masklay->splines.first; @@ -7730,7 +7784,6 @@ static void lib_link_mask(FileData *fd, Main *main) mask->id.tag &= ~LIB_TAG_NEED_LINK; } - mask = mask->id.next; } } @@ -7738,18 +7791,13 @@ static void lib_link_mask(FileData *fd, Main *main) static void lib_link_linestyle(FileData *fd, Main *main) { - FreestyleLineStyle *linestyle; - LineStyleModifier *m; - MTex *mtex; - int a; - - linestyle = main->linestyle.first; - while (linestyle) { + for (FreestyleLineStyle *linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) { if (linestyle->id.tag & LIB_TAG_NEED_LINK) { - linestyle->id.tag &= ~LIB_TAG_NEED_LINK; + LineStyleModifier *m; - IDP_LibLinkProperty(linestyle->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_LibLinkProperty(linestyle->id.properties, fd); lib_link_animdata(fd, &linestyle->id, linestyle->adt); + for (m = linestyle->color_modifiers.first; m; m = m->next) { switch (m->type) { case LS_MODIFIER_DISTANCE_FROM_OBJECT: @@ -7780,8 +7828,8 @@ static void lib_link_linestyle(FileData *fd, Main *main) break; } } - for (a=0; a < MAX_MTEX; a++) { - mtex = linestyle->mtex[a]; + for (int a = 0; a < MAX_MTEX; a++) { + MTex *mtex = linestyle->mtex[a]; if (mtex) { mtex->tex = newlibadr_us(fd, linestyle->id.lib, mtex->tex); mtex->object = newlibadr(fd, linestyle->id.lib, mtex->object); @@ -7791,8 +7839,9 @@ static void lib_link_linestyle(FileData *fd, Main *main) lib_link_ntree(fd, &linestyle->id, linestyle->nodetree); linestyle->nodetree->id.lib = linestyle->id.lib; } + + linestyle->id.tag &= ~LIB_TAG_NEED_LINK; } - linestyle = linestyle->id.next; } } @@ -8463,12 +8512,13 @@ static void lib_link_all(FileData *fd, Main *main) lib_link_screen(fd, main); lib_link_scene(fd, main); lib_link_object(fd, main); + lib_link_mesh(fd, main); lib_link_curve(fd, main); lib_link_mball(fd, main); lib_link_material(fd, main); lib_link_texture(fd, main); lib_link_image(fd, main); - lib_link_ipo(fd, main); // XXX deprecated... still needs to be maintained for version patches still + lib_link_ipo(fd, main); /* XXX deprecated... still needs to be maintained for version patches still */ lib_link_key(fd, main); lib_link_world(fd, main); lib_link_lamp(fd, main); @@ -8481,7 +8531,7 @@ static void lib_link_all(FileData *fd, Main *main) lib_link_armature(fd, main); lib_link_action(fd, main); lib_link_vfont(fd, main); - lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */ + lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */ lib_link_brush(fd, main); lib_link_palette(fd, main); lib_link_paint_curve(fd, main); @@ -8492,9 +8542,7 @@ static void lib_link_all(FileData *fd, Main *main) lib_link_gpencil(fd, main); lib_link_cachefiles(fd, main); - lib_link_mesh(fd, main); /* as last: tpage images with users at zero */ - - lib_link_library(fd, main); /* only init users */ + lib_link_library(fd, main); /* only init users */ } static void direct_link_keymapitem(FileData *fd, wmKeyMapItem *kmi) @@ -8914,6 +8962,31 @@ static void expand_constraint_channels(FileData *fd, Main *mainvar, ListBase *ch } } +static void expand_idprops(FileData *fd, Main *mainvar, IDProperty *prop) +{ + if (!prop) + return; + + switch (prop->type) { + case IDP_ID: + expand_doit(fd, mainvar, IDP_Id(prop)); + break; + case IDP_IDPARRAY: + { + IDProperty *idp_array = IDP_IDPArray(prop); + for (int i = 0; i < prop->len; i++) { + expand_idprops(fd, mainvar, &idp_array[i]); + } + break; + } + case IDP_GROUP: + for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) { + expand_idprops(fd, mainvar, loop); + } + break; + } +} + static void expand_fmodifiers(FileData *fd, Main *mainvar, ListBase *list) { FModifier *fcm; @@ -9099,6 +9172,7 @@ static void expand_key(FileData *fd, Main *mainvar, Key *key) static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree) { bNode *node; + bNodeSocket *sock; if (ntree->adt) expand_animdata(fd, mainvar, ntree->adt); @@ -9107,10 +9181,22 @@ static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree) expand_doit(fd, mainvar, ntree->gpd); for (node = ntree->nodes.first; node; node = node->next) { - if (node->id && node->type != CMP_NODE_R_LAYERS) + if (node->id && node->type != CMP_NODE_R_LAYERS) { expand_doit(fd, mainvar, node->id); + } + + expand_idprops(fd, mainvar, node->prop); + + for (sock = node->inputs.first; sock; sock = sock->next) + expand_doit(fd, mainvar, sock->prop); + for (sock = node->outputs.first; sock; sock = sock->next) + expand_doit(fd, mainvar, sock->prop); } + for (sock = ntree->inputs.first; sock; sock = sock->next) + expand_doit(fd, mainvar, sock->prop); + for (sock = ntree->outputs.first; sock; sock = sock->next) + expand_doit(fd, mainvar, sock->prop); } static void expand_texture(FileData *fd, Main *mainvar, Tex *tex) @@ -9328,17 +9414,6 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb) } } -#if 0 /* Disabled as it doesn't actually do anything except recurse... */ -static void expand_bones(FileData *fd, Main *mainvar, Bone *bone) -{ - Bone *curBone; - - for (curBone = bone->childbase.first; curBone; curBone=curBone->next) { - expand_bones(fd, mainvar, curBone); - } -} -#endif - static void expand_pose(FileData *fd, Main *mainvar, bPose *pose) { bPoseChannel *chan; @@ -9348,24 +9423,28 @@ static void expand_pose(FileData *fd, Main *mainvar, bPose *pose) for (chan = pose->chanbase.first; chan; chan = chan->next) { expand_constraints(fd, mainvar, &chan->constraints); + expand_idprops(fd, mainvar, chan->prop); expand_doit(fd, mainvar, chan->custom); } } +static void expand_bones(FileData *fd, Main *mainvar, Bone *bone) +{ + expand_idprops(fd, mainvar, bone->prop); + + for (Bone *curBone = bone->childbase.first; curBone; curBone = curBone->next) { + expand_bones(fd, mainvar, curBone); + } +} + static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm) -{ +{ if (arm->adt) expand_animdata(fd, mainvar, arm->adt); - -#if 0 /* Disabled as this currently only recurses down the chain doing nothing */ - { - Bone *curBone; - - for (curBone = arm->bonebase.first; curBone; curBone=curBone->next) { - expand_bones(fd, mainvar, curBone); - } + + for (Bone *curBone = arm->bonebase.first; curBone; curBone = curBone->next) { + expand_bones(fd, mainvar, curBone); } -#endif } static void expand_object_expandModifiers( @@ -9593,6 +9672,8 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce) SEQ_BEGIN (sce->ed, seq) { + expand_idprops(fd, mainvar, seq->prop); + if (seq->scene) expand_doit(fd, mainvar, seq->scene); if (seq->scene_camera) expand_doit(fd, mainvar, seq->scene_camera); if (seq->clip) expand_doit(fd, mainvar, seq->clip); @@ -9750,6 +9831,8 @@ void BLO_expand_main(void *fdhandle, Main *mainvar) id = lbarray[a]->first; while (id) { if (id->tag & LIB_TAG_NEED_EXPAND) { + expand_idprops(fd, mainvar, id->properties); + switch (GS(id->name)) { case ID_OB: expand_object(fd, mainvar, (Object *)id); diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 99d9e140481..e34f12b1cf9 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -68,6 +68,18 @@ void BLO_update_defaults_userpref_blend(void) * but take care since some hardware has driver bugs here (T46962). * Further hardware workarounds should be made in gpu_extensions.c */ U.glalphaclip = (1.0f / 255); + + /* default so DPI is detected automatically */ + U.dpi = 0; + U.ui_scale = 1.0f; + +#ifdef WITH_PYTHON_SECURITY + /* use alternative setting for security nuts + * otherwise we'd need to patch the binary blob - startup.blend.c */ + U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE; +#else + U.flag &= ~USER_SCRIPT_AUTOEXEC_DISABLE; +#endif } /** diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index cee5450a37d..4fe14fdf5c9 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -2403,15 +2403,20 @@ static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separ do { LinkNode *n_orig = edges_separate->link; do { - BMEdge *e_orig = n_orig->link; + LinkNode *n_prev = n_orig; LinkNode *n_step = n_orig->next; + BMEdge *e_orig = n_orig->link; do { BMEdge *e = n_step->link; BLI_assert(e != e_orig); - if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2)) { - BM_edge_splice(bm, e_orig, e); + if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2) && + BM_edge_splice(bm, e_orig, e)) + { + /* don't visit again */ + n_prev->next = n_step->next; } - } while ((n_step = n_step->next)); + } while ((n_prev = n_step), + (n_step = n_step->next)); } while ((n_orig = n_orig->next) && n_orig->next); } while ((edges_separate = edges_separate->next)); diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index d92d0cbb469..e9fb6a28154 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -1512,23 +1512,6 @@ int BM_mesh_elem_count(BMesh *bm, const char htype) } } -/** - * Special case: Python uses custom-data layers to hold PyObject references. - * These have to be kept in-place, else the PyObject's we point to, wont point back to us. - * - * \note ``ele_src`` Is a duplicate, so we don't need to worry about getting in a feedback loop. - * - * \note If there are other customdata layers which need this functionality, it should be generalized. - * However #BM_mesh_remap is currently the only place where this is done. - */ -static void bm_mesh_remap_cd_update( - BMHeader *ele_dst, BMHeader *ele_src, - const int cd_elem_pyptr) -{ - void **pyptr_dst_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_dst), cd_elem_pyptr); - void **pyptr_src_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_src), cd_elem_pyptr); - *pyptr_dst_p = *pyptr_src_p; -} /** * Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays @@ -1570,6 +1553,8 @@ void BM_mesh_remap( BMVert **verts_pool, *verts_copy, **vep; int i, totvert = bm->totvert; const unsigned int *new_idx; + /* Special case: Python uses custom - data layers to hold PyObject references. + * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */ const int cd_vert_pyptr = CustomData_get_offset(&bm->vdata, CD_BM_ELEM_PYPTR); /* Init the old-to-new vert pointers mapping */ @@ -1578,9 +1563,14 @@ void BM_mesh_remap( /* Make a copy of all vertices. */ verts_pool = bm->vtable; verts_copy = MEM_mallocN(sizeof(BMVert) * totvert, "BM_mesh_remap verts copy"); + void **pyptrs = (cd_vert_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totvert, __func__) : NULL; for (i = totvert, ve = verts_copy + totvert - 1, vep = verts_pool + totvert - 1; i--; ve--, vep--) { *ve = **vep; /* printf("*vep: %p, verts_pool[%d]: %p\n", *vep, i, verts_pool[i]);*/ + if (cd_vert_pyptr != -1) { + void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)ve), cd_vert_pyptr); + pyptrs[i] = *pyptr; + } } /* Copy back verts to their new place, and update old2new pointers mapping. */ @@ -1593,13 +1583,17 @@ void BM_mesh_remap( /* printf("mapping vert from %d to %d (%p/%p to %p)\n", i, *new_idx, *vep, verts_pool[i], new_vep);*/ BLI_ghash_insert(vptr_map, *vep, new_vep); if (cd_vert_pyptr != -1) { - bm_mesh_remap_cd_update(&(*vep)->head, &new_vep->head, cd_vert_pyptr); + void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_vep), cd_vert_pyptr); + *pyptr = pyptrs[*new_idx]; } } bm->elem_index_dirty |= BM_VERT; bm->elem_table_dirty |= BM_VERT; MEM_freeN(verts_copy); + if (pyptrs) { + MEM_freeN(pyptrs); + } } /* Remap Edges */ @@ -1607,6 +1601,8 @@ void BM_mesh_remap( BMEdge **edges_pool, *edges_copy, **edp; int i, totedge = bm->totedge; const unsigned int *new_idx; + /* Special case: Python uses custom - data layers to hold PyObject references. + * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */ const int cd_edge_pyptr = CustomData_get_offset(&bm->edata, CD_BM_ELEM_PYPTR); /* Init the old-to-new vert pointers mapping */ @@ -1615,8 +1611,13 @@ void BM_mesh_remap( /* Make a copy of all vertices. */ edges_pool = bm->etable; edges_copy = MEM_mallocN(sizeof(BMEdge) * totedge, "BM_mesh_remap edges copy"); + void **pyptrs = (cd_edge_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totedge, __func__) : NULL; for (i = totedge, ed = edges_copy + totedge - 1, edp = edges_pool + totedge - 1; i--; ed--, edp--) { *ed = **edp; + if (cd_edge_pyptr != -1) { + void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)ed), cd_edge_pyptr); + pyptrs[i] = *pyptr; + } } /* Copy back verts to their new place, and update old2new pointers mapping. */ @@ -1629,13 +1630,17 @@ void BM_mesh_remap( BLI_ghash_insert(eptr_map, *edp, new_edp); /* printf("mapping edge from %d to %d (%p/%p to %p)\n", i, *new_idx, *edp, edges_pool[i], new_edp);*/ if (cd_edge_pyptr != -1) { - bm_mesh_remap_cd_update(&(*edp)->head, &new_edp->head, cd_edge_pyptr); + void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_edp), cd_edge_pyptr); + *pyptr = pyptrs[*new_idx]; } } bm->elem_index_dirty |= BM_EDGE; bm->elem_table_dirty |= BM_EDGE; MEM_freeN(edges_copy); + if (pyptrs) { + MEM_freeN(pyptrs); + } } /* Remap Faces */ @@ -1643,6 +1648,8 @@ void BM_mesh_remap( BMFace **faces_pool, *faces_copy, **fap; int i, totface = bm->totface; const unsigned int *new_idx; + /* Special case: Python uses custom - data layers to hold PyObject references. + * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */ const int cd_poly_pyptr = CustomData_get_offset(&bm->pdata, CD_BM_ELEM_PYPTR); /* Init the old-to-new vert pointers mapping */ @@ -1651,8 +1658,13 @@ void BM_mesh_remap( /* Make a copy of all vertices. */ faces_pool = bm->ftable; faces_copy = MEM_mallocN(sizeof(BMFace) * totface, "BM_mesh_remap faces copy"); + void **pyptrs = (cd_poly_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totface, __func__) : NULL; for (i = totface, fa = faces_copy + totface - 1, fap = faces_pool + totface - 1; i--; fa--, fap--) { *fa = **fap; + if (cd_poly_pyptr != -1) { + void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)fa), cd_poly_pyptr); + pyptrs[i] = *pyptr; + } } /* Copy back verts to their new place, and update old2new pointers mapping. */ @@ -1664,7 +1676,8 @@ void BM_mesh_remap( *new_fap = *fa; BLI_ghash_insert(fptr_map, *fap, new_fap); if (cd_poly_pyptr != -1) { - bm_mesh_remap_cd_update(&(*fap)->head, &new_fap->head, cd_poly_pyptr); + void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_fap), cd_poly_pyptr); + *pyptr = pyptrs[*new_idx]; } } @@ -1672,6 +1685,9 @@ void BM_mesh_remap( bm->elem_table_dirty |= BM_FACE; MEM_freeN(faces_copy); + if (pyptrs) { + MEM_freeN(pyptrs); + } } /* And now, fix all vertices/edges/faces/loops pointers! */ diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index 723e0b168e0..e5c3ff7a088 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -1566,7 +1566,7 @@ void BM_mesh_calc_uvs_cone( BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for ensuring the mesh has UVs */ - x = 0.0f; + x = 1.0f; y = 1.0f - uv_height; BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { @@ -1580,7 +1580,7 @@ void BM_mesh_calc_uvs_cone( switch (loop_index) { case 0: - x += uv_width; + /* Continue in the last position */ break; case 1: y += uv_height; @@ -1598,8 +1598,6 @@ void BM_mesh_calc_uvs_cone( luv->uv[0] = x; luv->uv[1] = y; } - - x += uv_width; } else { /* top or bottom face - so unwrap it by transforming back to a circle and using the X/Y coords */ diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index 3801c9300df..bd47ee0214d 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -1934,7 +1934,7 @@ Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, COLLADAFW::No mul_m4_m4m4(mat, ipar, temp); } - TransformBase::decompose(mat, job->loc, NULL, job->quat, job->size); + bc_decompose(mat, job->loc, NULL, job->quat, job->size); if (par_job) { job->parent = par_job; diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp index 40065956ecb..9348f3b3285 100644 --- a/source/blender/collada/ArmatureExporter.cpp +++ b/source/blender/collada/ArmatureExporter.cpp @@ -256,47 +256,59 @@ void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW: //bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name); float mat[4][4]; + float bone_rest_mat[4][4]; /* derived from bone->arm_mat */ + float parent_rest_mat[4][4]; /* derived from bone->parent->arm_mat */ - if (bone->parent) { - // get bone-space matrix from parent pose - /*bPoseChannel *parchan = BKE_pose_channel_find_name(ob_arm->pose, bone->parent->name); - float invpar[4][4]; - invert_m4_m4(invpar, parchan->pose_mat); - mul_m4_m4m4(mat, invpar, pchan->pose_mat);*/ - - float invpar[4][4]; - invert_m4_m4(invpar, bone->parent->arm_mat); - mul_m4_m4m4(mat, invpar, bone->arm_mat); + bool has_restmat = bc_get_property_matrix(bone, "rest_mat", mat); - } - else { + if (!has_restmat) { + + /* Have no restpose matrix stored, try old style <= Blender 2.78 */ - //copy_m4_m4(mat, pchan->pose_mat); - //pose mat is object space - //New change: export bone->arm_mat - copy_m4_m4(mat, bone->arm_mat); - } + bc_create_restpose_mat(this->export_settings, bone, bone_rest_mat, bone->arm_mat, true); - // OPEN_SIM_COMPATIBILITY - if (export_settings->open_sim) { - // Remove rotations vs armature from transform - // parent_rest_rot * mat * irest_rot - float temp[4][4]; - copy_m4_m4(temp, bone->arm_mat); - temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; - invert_m4(temp); + if (bone->parent) { + // get bone-space matrix from parent pose + /*bPoseChannel *parchan = BKE_pose_channel_find_name(ob_arm->pose, bone->parent->name); + float invpar[4][4]; + invert_m4_m4(invpar, parchan->pose_mat); + mul_m4_m4m4(mat, invpar, pchan->pose_mat);*/ + float invpar[4][4]; + bc_create_restpose_mat(this->export_settings, bone->parent, parent_rest_mat, bone->parent->arm_mat, true); - mul_m4_m4m4(mat, mat, temp); + invert_m4_m4(invpar, parent_rest_mat); + mul_m4_m4m4(mat, invpar, bone_rest_mat); - if (bone->parent) { - copy_m4_m4(temp, bone->parent->arm_mat); + } + else { + copy_m4_m4(mat, bone_rest_mat); + } + + // OPEN_SIM_COMPATIBILITY + if (export_settings->open_sim) { + // Remove rotations vs armature from transform + // parent_rest_rot * mat * irest_rot + float temp[4][4]; + copy_m4_m4(temp, bone_rest_mat); temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; + invert_m4(temp); + + mul_m4_m4m4(mat, mat, temp); + + if (bone->parent) { + copy_m4_m4(temp, parent_rest_mat); + temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; - mul_m4_m4m4(mat, temp, mat); + mul_m4_m4m4(mat, temp, mat); + } } } + if (this->export_settings->limit_precision) + bc_sanitize_mat(mat, 6); + TransformWriter::add_node_transform(node, mat, NULL); + } std::string ArmatureExporter::get_controller_id(Object *ob_arm, Object *ob) diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index f4ce3992771..0ea8324ed7c 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -32,6 +32,7 @@ #include "COLLADAFWUniqueId.h" +extern "C" { #include "BKE_action.h" #include "BKE_depsgraph.h" #include "BKE_object.h" @@ -39,7 +40,9 @@ #include "BLI_string.h" #include "BLI_listbase.h" #include "ED_armature.h" +} +#include "collada_utils.h" #include "ArmatureImporter.h" // use node name, or fall back to original id if not present (name is optional) @@ -91,6 +94,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon { float mat[4][4]; float joint_inv_bind_mat[4][4]; + float joint_bind_mat[4][4]; int chain_length = 0; //Checking if bone is already made. @@ -114,7 +118,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon // get original world-space matrix invert_m4_m4(mat, joint_inv_bind_mat); - + copy_m4_m4(joint_bind_mat, mat); // And make local to armature Object *ob_arm = skin->BKE_armature_from_object(); if (ob_arm) { @@ -130,18 +134,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon // create a bone even if there's no joint data for it (i.e. it has no influence) if (!bone_is_skinned) { - float obmat[4][4]; - // bone-space - get_node_mat(obmat, node, NULL, NULL); - - // get world-space - if (parent) { - mul_m4_m4m4(mat, parent_mat, obmat); - } - else { - copy_m4_m4(mat, obmat); - } - + get_node_mat(mat, node, NULL, NULL, parent_mat); } if (parent) bone->parent = parent; @@ -157,10 +150,11 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon int use_connect = be.get_use_connect(); switch (use_connect) { - case 1: bone->flag |= BONE_CONNECTED; - break; - case 0: bone->flag &= ~BONE_CONNECTED; - case -1: break; // not defined + case 1: bone->flag |= BONE_CONNECTED; + break; + case -1:/* Connect type not specified */ + case 0: bone->flag &= ~BONE_CONNECTED; + break; } if (be.has_roll()) { @@ -173,6 +167,15 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon bone->roll = angle; } copy_v3_v3(bone->head, mat[3]); + + if (bone_is_skinned) + { + float rest_mat[4][4]; + get_node_mat(rest_mat, node, NULL, NULL, NULL); + bc_set_IDPropertyMatrix(bone, "bind_mat", joint_bind_mat); + bc_set_IDPropertyMatrix(bone, "rest_mat", rest_mat); + } + add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero /* find smallest bone length in armature (used later for leaf bone length) */ @@ -274,7 +277,6 @@ void ArmatureImporter::fix_parent_connect(bArmature *armature, Bone *bone) } - void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone, int clip) { BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(armature); @@ -290,12 +292,13 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone for (; child; child = child->next) { BoneExtended *be = extended_bones[child->name]; if (be != NULL) { - if (be->get_chain_length() <= clip) { - if (be->get_chain_length() > maxlen) { + int chain_len = be->get_chain_length(); + if (chain_len <= clip) { + if (chain_len > maxlen) { dominant_child = be; - maxlen = be->get_chain_length(); + maxlen = chain_len; } - else if (be->get_chain_length() == maxlen) { + else if (chain_len == maxlen) { dominant_child = NULL; } } @@ -309,7 +312,6 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone EditBone *pebone = bc_get_edit_bone(armature, parentbone->name); EditBone *cebone = bc_get_edit_bone(armature, dominant_child->get_name()); if (pebone && !(cebone->flag & BONE_CONNECTED)) { - float vec[3]; sub_v3_v3v3(vec, cebone->head, pebone->head); @@ -322,14 +324,16 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone if (len_squared_v3(vec) > MINIMUM_BONE_LENGTH) { - pebone->tail[0] = cebone->head[0]; - pebone->tail[1] = cebone->head[1]; - pebone->tail[2] = cebone->head[2]; - + copy_v3_v3(pebone->tail, cebone->head); + pbe->set_tail(pebone->tail); /* to make fix_leafbone happy ...*/ if (pbe && pbe->get_chain_length() >= this->import_settings->min_chain_length) { + + BoneExtended *cbe = extended_bones[cebone->name]; + cbe->set_use_connect(true); + cebone->flag |= BONE_CONNECTED; - printf("Connecting chain: parent %s --> %s (child)\n", pebone->name, cebone->name); pbe->set_leaf_bone(false); + printf("Connect Bone chain: parent (%s --> %s) child)\n", pebone->name, cebone->name); } } } diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp index a868adc1e66..1c2642e8313 100644 --- a/source/blender/collada/ControllerExporter.cpp +++ b/source/blender/collada/ControllerExporter.cpp @@ -463,81 +463,6 @@ std::string ControllerExporter::add_joints_source(Object *ob_arm, ListBase *defb return source_id; } -static float get_property(Bone *bone, const char *key, float def) -{ - float result = def; - if (bone->prop) { - IDProperty *property = IDP_GetPropertyFromGroup(bone->prop, key); - if (property) { - switch (property->type) { - case IDP_INT: - result = (float)(IDP_Int(property)); - break; - case IDP_FLOAT: - result = (float)(IDP_Float(property)); - break; - case IDP_DOUBLE: - result = (float)(IDP_Double(property)); - break; - default: - result = def; - } - } - } - return result; -} - -/** - * This function creates an arbitrary rest pose matrix from - * data provided as custom properties. This is a workaround - * for support of maya's restpose matrix which can be arbitrary - * in opposition to Blender where the Rest pose Matrix is always - * the Identity matrix. - * - * The custom properties are: - * - * restpose_scale_x - * restpose_scale_y - * restpose_scale_z - * - * restpose_rot_x - * restpose_rot_y - * restpose_rot_z - * - * restpose_loc_x - * restpose_loc_y - * restpose_loc_z - * - * The matrix is only setup if the scale AND the rot properties are defined. - * The presence of the loc properties is optional. - * - * This feature has been implemented to support Second Life "Fitted Mesh" - * TODO: Check if an arbitrary rest pose matrix makes sense within Blender. - * Eventually leverage the custom property data into an "official" - * Edit_bone Property - */ -static void create_restpose_mat(Bone *bone, float mat[4][4]) -{ - float loc[3] = { - get_property(bone, "restpose_loc_x", 0.0), - get_property(bone, "restpose_loc_y", 0.0), - get_property(bone, "restpose_loc_z", 0.0) - }; - - float rot[3] = { - DEG2RADF(get_property(bone, "restpose_rot_x", 0.0)), - DEG2RADF(get_property(bone, "restpose_rot_y", 0.0)), - DEG2RADF(get_property(bone, "restpose_rot_z", 0.0)) - }; - - float scale[3] = { - get_property(bone, "restpose_scale_x", 1.0), - get_property(bone, "restpose_scale_y", 1.0), - get_property(bone, "restpose_scale_z", 1.0) - }; - - loc_eulO_size_to_mat4(mat, loc, rot, scale, 6); -} std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id) { @@ -580,30 +505,36 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas float world[4][4]; float inv_bind_mat[4][4]; + float bind_mat[4][4]; /* derived from bone->arm_mat */ + + bool has_bindmat = bc_get_property_matrix(pchan->bone, "bind_mat", bind_mat); - // SL/OPEN_SIM COMPATIBILITY - if (export_settings->open_sim) { - // Only translations, no rotation vs armature - float temp[4][4]; - unit_m4(temp); - copy_v3_v3(temp[3], pchan->bone->arm_mat[3]); - mul_m4_m4m4(world, ob_arm->obmat, temp); - - // Add Maya restpose matrix (if defined as properties) - float restpose_mat[4][4]; - create_restpose_mat(pchan->bone, restpose_mat); - mul_m4_m4m4(world, world, restpose_mat); + if (!has_bindmat) { - } - else { - // make world-space matrix, arm_mat is armature-space - mul_m4_m4m4(world, ob_arm->obmat, pchan->bone->arm_mat); + /* Have no bind matrix stored, try old style <= Blender 2.78 */ + + bc_create_restpose_mat(this->export_settings, pchan->bone, bind_mat, pchan->bone->arm_mat, true); + + // SL/OPEN_SIM COMPATIBILITY + if (export_settings->open_sim) { + + float loc[3]; + float rot[3] = { 0, 0, 0 }; + float scale[3]; + bc_decompose(bind_mat, loc, NULL, NULL, scale); + + // Only translations, no rotation vs armature + loc_eulO_size_to_mat4(bind_mat, loc, rot, scale, 6); + } } + // make world-space matrix (bind_mat is armature-space) + mul_m4_m4m4(world, ob_arm->obmat, bind_mat); invert_m4_m4(mat, world); converter.mat4_to_dae(inv_bind_mat, mat); - + if (this->export_settings->limit_precision) + bc_sanitize_mat(inv_bind_mat, 6); source.appendValues(inv_bind_mat); } } diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h index 9451cac9dae..de91f68a492 100644 --- a/source/blender/collada/ExportSettings.h +++ b/source/blender/collada/ExportSettings.h @@ -51,7 +51,10 @@ public: bool use_blender_profile; bool sort_by_name; BC_export_transformation_type export_transformation_type; + bool open_sim; + bool limit_precision; + bool keep_bind_info; char *filepath; LinkNode *export_set; diff --git a/source/blender/collada/ImportSettings.h b/source/blender/collada/ImportSettings.h index 2c52d73e756..4a2d4e8046a 100644 --- a/source/blender/collada/ImportSettings.h +++ b/source/blender/collada/ImportSettings.h @@ -37,6 +37,7 @@ public: bool fix_orientation; int min_chain_length; char *filepath; + bool keep_bind_info; }; #endif diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp index f8f31304d28..7f742be7e30 100644 --- a/source/blender/collada/TransformReader.cpp +++ b/source/blender/collada/TransformReader.cpp @@ -34,7 +34,21 @@ TransformReader::TransformReader(UnitConverter *conv) : unit_converter(conv) /* pass */ } -void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob) +void TransformReader::get_node_mat( + float mat[4][4], + COLLADAFW::Node *node, + std::map<COLLADAFW::UniqueId, Animation> *animation_map, + Object *ob) +{ + get_node_mat(mat, node, animation_map, ob, NULL); +} + +void TransformReader::get_node_mat( + float mat[4][4], + COLLADAFW::Node *node, + std::map<COLLADAFW::UniqueId, Animation> *animation_map, + Object *ob, + float parent_mat[4][4]) { float cur[4][4]; float copy[4][4]; @@ -52,6 +66,9 @@ void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std:: // then this is considered as redundant information. // So if we find a Matrix we use that and return. dae_matrix_to_mat4(tm, mat); + if (parent_mat) { + mul_m4_m4m4(mat, parent_mat, mat); + } return; case COLLADAFW::Transformation::TRANSLATE: dae_translate_to_mat4(tm, cur); @@ -80,6 +97,10 @@ void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std:: (*animation_map)[anim_list_id] = anim; } } + + if (parent_mat) { + mul_m4_m4m4(mat, parent_mat, mat); + } } void TransformReader::dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]) diff --git a/source/blender/collada/TransformReader.h b/source/blender/collada/TransformReader.h index ab974b9ba85..08bb17ccac1 100644 --- a/source/blender/collada/TransformReader.h +++ b/source/blender/collada/TransformReader.h @@ -43,7 +43,7 @@ //struct Object; -class TransformReader : public TransformBase +class TransformReader { protected: @@ -59,7 +59,8 @@ public: TransformReader(UnitConverter *conv); void get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob); - + void get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob, float parent_mat[4][4]); + void dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]); void dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]); void dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]); diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp index 908111ebae6..b7eeff3b074 100644 --- a/source/blender/collada/TransformWriter.cpp +++ b/source/blender/collada/TransformWriter.cpp @@ -27,11 +27,10 @@ #include "BKE_object.h" +#include "BLI_math.h" #include "TransformWriter.h" -#include "BLI_math.h" - void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4]) { float loc[3], rot[3], scale[3]; @@ -51,7 +50,7 @@ void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4], converter->mat4_to_dae_double(dmat, local); delete converter; - TransformBase::decompose(local, loc, rot, NULL, scale); + bc_decompose(local, loc, rot, NULL, scale); if (node.getType() == COLLADASW::Node::JOINT) { // XXX Why are joints handled differently ? @@ -116,7 +115,7 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B case BC_TRANSFORMATION_TYPE_TRANSROTLOC: { float loc[3], rot[3], scale[3]; - TransformBase::decompose(f_obmat, loc, rot, NULL, scale); + bc_decompose(f_obmat, loc, rot, NULL, scale); add_transform(node, loc, rot, scale); break; } diff --git a/source/blender/collada/TransformWriter.h b/source/blender/collada/TransformWriter.h index 7f69a4b9c95..5bb13d4aac9 100644 --- a/source/blender/collada/TransformWriter.h +++ b/source/blender/collada/TransformWriter.h @@ -33,9 +33,10 @@ #include "DNA_object_types.h" #include "collada_internal.h" +#include "collada_utils.h" #include "collada.h" -class TransformWriter : protected TransformBase +class TransformWriter { protected: void add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4]); diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp index fe8b1d2320a..bfe3180909b 100644 --- a/source/blender/collada/collada.cpp +++ b/source/blender/collada/collada.cpp @@ -48,7 +48,8 @@ int collada_import(bContext *C, int find_chains, int auto_connect, int fix_orientation, - int min_chain_length) + int min_chain_length, + int keep_bind_info) { ImportSettings import_settings; @@ -58,6 +59,7 @@ int collada_import(bContext *C, import_settings.find_chains = find_chains != 0; import_settings.fix_orientation = fix_orientation != 0; import_settings.min_chain_length = min_chain_length; + import_settings.keep_bind_info = keep_bind_info !=0; DocumentImporter imp(C, &import_settings); if (imp.import()) return 1; @@ -87,7 +89,9 @@ int collada_export(Scene *sce, int use_blender_profile, int sort_by_name, BC_export_transformation_type export_transformation_type, - int open_sim) + int open_sim, + int limit_precision, + int keep_bind_info) { ExportSettings export_settings; @@ -112,7 +116,8 @@ int collada_export(Scene *sce, export_settings.sort_by_name = sort_by_name != 0; export_settings.export_transformation_type = export_transformation_type; export_settings.open_sim = open_sim != 0; - + export_settings.limit_precision = limit_precision != 0; + export_settings.keep_bind_info = keep_bind_info !=0; int includeFilter = OB_REL_NONE; if (export_settings.include_armatures) includeFilter |= OB_REL_MOD_ARMATURE; diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h index a4416608584..8035af59c8b 100644 --- a/source/blender/collada/collada.h +++ b/source/blender/collada/collada.h @@ -58,7 +58,9 @@ int collada_import(struct bContext *C, int find_chains, int auto_connect, int fix_orientation, - int min_chain_length); + int min_chain_length, + + int keep_bind_info); int collada_export(struct Scene *sce, const char *filepath, @@ -81,9 +83,10 @@ int collada_export(struct Scene *sce, int use_blender_profile, int sort_by_name, BC_export_transformation_type export_transformation_type, - int open_sim); - + int open_sim, + int limit_precision, + int keep_bind_info); #ifdef __cplusplus } diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp index 70b44ebc222..6ebde6bd773 100644 --- a/source/blender/collada/collada_internal.cpp +++ b/source/blender/collada/collada_internal.cpp @@ -162,18 +162,6 @@ void UnitConverter::calculate_scale(Scene &sce) size_to_mat4(scale_mat4, rescale); } -void TransformBase::decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size) -{ - mat4_to_size(size, mat); - if (eul) { - mat4_to_eul(eul, mat); - } - if (quat) { - mat4_to_quat(quat, mat); - } - copy_v3_v3(loc, mat[3]); -} - /** * Translation map. * Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h index 482dbf9ab31..1c7aa160f57 100644 --- a/source/blender/collada/collada_internal.h +++ b/source/blender/collada/collada_internal.h @@ -85,12 +85,6 @@ public: }; -class TransformBase -{ -public: - void decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size); -}; - extern void clear_global_id_map(); /** Look at documentation of translate_map */ extern std::string translate_id(const std::string &id); diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index 2efa8b21d81..ac4395e1430 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -32,8 +32,6 @@ #include "COLLADAFWMeshPrimitive.h" #include "COLLADAFWMeshVertexData.h" -#include "collada_utils.h" - extern "C" { #include "DNA_modifier_types.h" #include "DNA_customdata_types.h" @@ -63,6 +61,9 @@ extern "C" { #include "bmesh_tools.h" } +#include "collada_utils.h" +#include "ExportSettings.h" + float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index) { if (index >= array.getValuesCount()) @@ -352,6 +353,28 @@ void bc_match_scale(std::vector<Object *> *objects_done, } } +/* + Convenience function to get only the needed components of a matrix +*/ +void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size) +{ + if (size) { + mat4_to_size(size, mat); + } + + if (eul) { + mat4_to_eul(eul, mat); + } + + if (quat) { + mat4_to_quat(quat, mat); + } + + if (loc) { + copy_v3_v3(loc, mat[3]); + } +} + void bc_triangulate_mesh(Mesh *me) { bool use_beauty = false; @@ -612,3 +635,200 @@ int BoneExtended::get_use_connect() { return this->use_connect; } + +/** +* Stores a 4*4 matrix as a custom bone property array of size 16 +*/ +void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4]) +{ + IDProperty *idgroup = (IDProperty *)ebone->prop; + if (idgroup == NULL) + { + IDPropertyTemplate val = { 0 }; + idgroup = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties"); + ebone->prop = idgroup; + } + + IDPropertyTemplate val = { 0 }; + val.array.len = 16; + val.array.type = IDP_FLOAT; + + IDProperty *data = IDP_New(IDP_ARRAY, &val, key); + float *array = (float *)IDP_Array(data); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + array[4 * i + j] = mat[i][j]; + + IDP_AddToGroup(idgroup, data); +} + +#if 0 +/** +* Stores a Float value as a custom bone property +* +* Note: This function is currently not needed. Keep for future usage +*/ +static void bc_set_IDProperty(EditBone *ebone, const char *key, float value) +{ + if (ebone->prop == NULL) + { + IDPropertyTemplate val = { 0 }; + ebone->prop = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties"); + } + + IDProperty *pgroup = (IDProperty *)ebone->prop; + IDPropertyTemplate val = { 0 }; + IDProperty *prop = IDP_New(IDP_FLOAT, &val, key); + IDP_Float(prop) = value; + IDP_AddToGroup(pgroup, prop); + +} +#endif + +/* +* Get a custom property when it exists. +* This function is also used to check if a property exists. +*/ +IDProperty *bc_get_IDProperty(Bone *bone, std::string key) +{ + return (bone->prop == NULL) ? NULL : IDP_GetPropertyFromGroup(bone->prop, key.c_str()); +} + +/** +* Read a custom bone property and convert to float +* Return def if the property does not exist. +*/ +float bc_get_property(Bone *bone, std::string key, float def) +{ + float result = def; + IDProperty *property = bc_get_IDProperty(bone, key); + if (property) { + switch (property->type) { + case IDP_INT: + result = (float)(IDP_Int(property)); + break; + case IDP_FLOAT: + result = (float)(IDP_Float(property)); + break; + case IDP_DOUBLE: + result = (float)(IDP_Double(property)); + break; + default: + result = def; + } + } + return result; +} + +/** +* Read a custom bone property and convert to matrix +* Return true if conversion was succesfull +* +* Return false if: +* - the property does not exist +* - is not an array of size 16 +*/ +bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4]) +{ + IDProperty *property = bc_get_IDProperty(bone, key); + if (property && property->type == IDP_ARRAY && property->len == 16) { + float *array = (float *)IDP_Array(property); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + mat[i][j] = array[4 * i + j]; + return true; + } + return false; +} + +/** +* get a vector that is stored in 3 custom properties (used in Blender <= 2.78) +*/ +void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3]) +{ + val[0] = bc_get_property(bone, key + "_x", def[0]); + val[1] = bc_get_property(bone, key + "_y", def[1]); + val[2] = bc_get_property(bone, key + "_z", def[2]); +} + +/** +* Check if vector exist stored in 3 custom properties (used in Blender <= 2.78) +*/ +static bool has_custom_props(Bone *bone, bool enabled, std::string key) +{ + if (!enabled) + return false; + + return (bc_get_IDProperty(bone, key + "_x") + || bc_get_IDProperty(bone, key + "_y") + || bc_get_IDProperty(bone, key + "_z")); + +} + +/** +* Check if custom information about bind matrix exists and modify the from_mat +* accordingly. +* +* Note: This is old style for Blender <= 2.78 only kept for compatibility +*/ +void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, float to_mat[4][4], float from_mat[4][4], bool use_local_space) +{ + float loc[3]; + float rot[3]; + float scale[3]; + static const float V0[3] = { 0, 0, 0 }; + + if (!has_custom_props(bone, export_settings->keep_bind_info, "restpose_loc") && + !has_custom_props(bone, export_settings->keep_bind_info, "restpose_rot") && + !has_custom_props(bone, export_settings->keep_bind_info, "restpose_scale")) + { + /* No need */ + copy_m4_m4(to_mat, from_mat); + return; + } + + bc_decompose(from_mat, loc, rot, NULL, scale); + loc_eulO_size_to_mat4(to_mat, loc, rot, scale, 6); + + if (export_settings->keep_bind_info) { + bc_get_property_vector(bone, "restpose_loc", loc, loc); + + if (use_local_space && bone->parent) { + Bone *b = bone; + while (b->parent) { + b = b->parent; + float ploc[3]; + bc_get_property_vector(b, "restpose_loc", ploc, V0); + loc[0] += ploc[0]; + loc[1] += ploc[1]; + loc[2] += ploc[2]; + } + } + } + + if (export_settings->keep_bind_info) { + if (bc_get_IDProperty(bone, "restpose_rot_x")) + rot[0] = DEG2RADF(bc_get_property(bone, "restpose_rot_x", 0)); + if (bc_get_IDProperty(bone, "restpose_rot_y")) + rot[1] = DEG2RADF(bc_get_property(bone, "restpose_rot_y", 0)); + if (bc_get_IDProperty(bone, "restpose_rot_z")) + rot[2] = DEG2RADF(bc_get_property(bone, "restpose_rot_z", 0)); + } + + if (export_settings->keep_bind_info) { + bc_get_property_vector(bone, "restpose_scale", scale, scale); + } + + loc_eulO_size_to_mat4(to_mat, loc, rot, scale, 6); + +} + +/* + Make 4*4 matrices better readable +*/ +void bc_sanitize_mat(float mat[4][4], int precision) +{ + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + mat[i][j] = double_round(mat[i][j], precision); +}
\ No newline at end of file diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h index 7fdbef3b6cb..38c0bd5096a 100644 --- a/source/blender/collada/collada_utils.h +++ b/source/blender/collada/collada_utils.h @@ -53,8 +53,10 @@ extern "C" { #include "BKE_object.h" #include "BKE_DerivedMesh.h" #include "BKE_scene.h" +#include "BKE_idprop.h" } +#include "ImportSettings.h" #include "ExportSettings.h" #include "collada_internal.h" @@ -88,11 +90,24 @@ extern std::string bc_url_encode(std::string data); extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene); extern void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &unit_converter, bool scale_to_scene); +extern void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size); + extern void bc_triangulate_mesh(Mesh *me); extern bool bc_is_leaf_bone(Bone *bone); extern EditBone *bc_get_edit_bone(bArmature * armature, char *name); extern int bc_set_layer(int bitfield, int layer, bool enable); extern int bc_set_layer(int bitfield, int layer); +extern void bc_sanitize_mat(float mat[4][4], int precision); + +extern IDProperty *bc_get_IDProperty(Bone *bone, std::string key); +extern void bc_set_IDProperty(EditBone *ebone, const char *key, float value); +extern void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4]); + +extern float bc_get_property(Bone *bone, std::string key, float def); +extern void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3]); +extern bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4]); + +extern void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, float to_mat[4][4], float world[4][4], bool use_local_space); class BCPolygonNormalsIndices { diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index cb2f057a090..7f62eb122db 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -52,14 +52,6 @@ namespace DEG { -string deg_fcurve_id_name(const FCurve *fcu) -{ - char index_buf[32]; - // TODO(sergey): Use int-to-string utility or so. - BLI_snprintf(index_buf, sizeof(index_buf), "[%d]", fcu->array_index); - return string(fcu->rna_path) + index_buf; -} - static bool check_object_needs_evaluation(Object *object) { if (object->recalc & OB_RECALC_ALL) { @@ -77,28 +69,8 @@ static bool check_object_needs_evaluation(Object *object) return false; } -void deg_graph_build_finalize(Depsgraph *graph) +void deg_graph_build_flush_layers(Depsgraph *graph) { - /* STEP 1: Make sure new invisible dependencies are ready for use. - * - * TODO(sergey): This might do a bit of extra tagging, but it's kinda nice - * to do it ahead of a time and don't spend time on flushing updates on - * every frame change. - */ - GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash) - { - if (id_node->layers == 0) { - ID *id = id_node->id; - if (GS(id->name) == ID_OB) { - Object *object = (Object *)id; - if (check_object_needs_evaluation(object)) { - id_node->tag_update(graph); - } - } - } - } - GHASH_FOREACH_END(); - /* STEP 2: Flush visibility layers from children to parent. */ std::stack<OperationDepsNode *> stack; foreach (OperationDepsNode *node, graph->operations) { IDDepsNode *id_node = node->owner->owner; @@ -143,6 +115,31 @@ void deg_graph_build_finalize(Depsgraph *graph) } } } +} + +void deg_graph_build_finalize(Depsgraph *graph) +{ + /* STEP 1: Make sure new invisible dependencies are ready for use. + * + * TODO(sergey): This might do a bit of extra tagging, but it's kinda nice + * to do it ahead of a time and don't spend time on flushing updates on + * every frame change. + */ + GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash) + { + if (id_node->layers == 0) { + ID *id = id_node->id; + if (GS(id->name) == ID_OB) { + Object *object = (Object *)id; + if (check_object_needs_evaluation(object)) { + id_node->tag_update(graph); + } + } + } + } + GHASH_FOREACH_END(); + /* STEP 2: Flush visibility layers from children to parent. */ + deg_graph_build_flush_layers(graph); /* STEP 3: Re-tag IDs for update if it was tagged before the relations * update tag. */ @@ -154,7 +151,7 @@ void deg_graph_build_finalize(Depsgraph *graph) } GHASH_FOREACH_END(); - if ((id_node->layers & graph->layers) != 0) { + if ((id_node->layers & graph->layers) != 0 || graph->layers == 0) { ID *id = id_node->id; if ((id->tag & LIB_TAG_ID_RECALC_ALL) && (id->tag & LIB_TAG_DOIT)) diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h index bdc030e3810..b8ea8c8e599 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.h +++ b/source/blender/depsgraph/intern/builder/deg_builder.h @@ -38,9 +38,7 @@ namespace DEG { struct Depsgraph; -/* Get unique identifier for FCurves and Drivers */ -string deg_fcurve_id_name(const FCurve *fcu); - void deg_graph_build_finalize(struct Depsgraph *graph); +void deg_graph_build_flush_layers(struct Depsgraph *graph); } // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index e8ed03666a6..cfc9005a1e3 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -56,8 +56,8 @@ extern "C" { #include "DEG_depsgraph.h" } /* extern "C" */ +#include "intern/builder/deg_builder.h" #include "intern/eval/deg_eval_flush.h" - #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" #include "intern/nodes/deg_node_operation.h" @@ -346,6 +346,27 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene) GHASH_FOREACH_END(); } scene->lay_updated |= graph->layers; + /* Special trick to get local view to work. */ + LINKLIST_FOREACH (Base *, base, &scene->base) { + Object *object = base->object; + DEG::IDDepsNode *id_node = graph->find_id_node(&object->id); + id_node->layers = 0; + } + LINKLIST_FOREACH (Base *, base, &scene->base) { + Object *object = base->object; + DEG::IDDepsNode *id_node = graph->find_id_node(&object->id); + id_node->layers |= base->lay; + } + DEG::deg_graph_build_flush_layers(graph); + LINKLIST_FOREACH (Base *, base, &scene->base) { + Object *object = base->object; + DEG::IDDepsNode *id_node = graph->find_id_node(&object->id); + GHASH_FOREACH_BEGIN(DEG::ComponentDepsNode *, comp, id_node->components) + { + id_node->layers |= comp->layers; + } + GHASH_FOREACH_END(); + } } void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time)) diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 47f42ab5321..648fe930030 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -6047,6 +6047,9 @@ int join_curve_exec(bContext *C, wmOperator *op) cu = ob->data; BLI_movelisttolist(&cu->nurb, &tempbase); + /* Account for mixed 2D/3D curves when joining */ + BKE_curve_curve_dimension_update(cu); + DAG_relations_tag_update(bmain); // because we removed object(s), call before editmode! DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index a542bf8fa11..f091609da49 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -701,24 +701,25 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness */ { bGPDspoint *pt1, *pt2; - float pm[2]; + float s0[2], s1[2]; /* segment 'center' points */ + float pm[2]; /* normal from previous segment. */ int i; float fpt[3]; glShadeModel(GL_FLAT); glBegin(GL_QUADS); - + + /* get x and y coordinates from first point */ + mul_v3_m4v3(fpt, diff_mat, &points->x); + gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0); + for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) { - float s0[2], s1[2]; /* segment 'center' points */ float t0[2], t1[2]; /* tessellated coordinates */ float m1[2], m2[2]; /* gradient and normal */ float mt[2], sc[2]; /* gradient for thickness, point for end-cap */ float pthick; /* thickness at segment point */ - /* get x and y coordinates from points */ - mul_v3_m4v3(fpt, diff_mat, &pt1->x); - gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0); - + /* get x and y coordinates from point2 (point1 has already been computed in previous iteration). */ mul_v3_m4v3(fpt, diff_mat, &pt2->x); gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1); @@ -846,6 +847,8 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness glVertex2fv(t0); } + /* store computed point2 coordinates as point1 ones of next segment. */ + copy_v2_v2(s0, s1); /* store stroke's 'natural' normal for next stroke to use */ copy_v2_v2(pm, m2); } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index fa9acc36a2b..601a86b97cb 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -2126,10 +2126,10 @@ static int gp_count_subdivision_cuts(bGPDstroke *gps) int totnewpoints = 0; for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { - if (i + 1 < gps->totpoints){ + if (i + 1 < gps->totpoints) { if (gps->points[i + 1].flag & GP_SPOINT_SELECT) { ++totnewpoints; - }; + } } } } @@ -2184,7 +2184,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) /* if next point is selected add a half way point */ if (pt->flag & GP_SPOINT_SELECT) { - if (i + 1 < oldtotpoints){ + if (i + 1 < oldtotpoints) { if (temp_points[i + 1].flag & GP_SPOINT_SELECT) { pt_final = &gps->points[i2]; /* Interpolate all values */ @@ -2196,7 +2196,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) pt_final->time = interpf(pt->time, next->time, 0.5f); pt_final->flag |= GP_SPOINT_SELECT; ++i2; - }; + } } } } diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 297058168a0..d2360fea672 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -86,13 +86,14 @@ /* Core/Shared Utilities */ /* Poll callback for interpolation operators */ -static int gpencil_interpolate_poll(bContext *C) +static int gpencil_view3d_poll(bContext *C) { bGPdata *gpd = CTX_data_gpencil_data(C); bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only 3D view */ - if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) { + ScrArea *sa = CTX_wm_area(C); + if (sa && sa->spacetype != SPACE_VIEW3D) { return 0; } @@ -673,7 +674,7 @@ void GPENCIL_OT_interpolate(wmOperatorType *ot) ot->invoke = gpencil_interpolate_invoke; ot->modal = gpencil_interpolate_modal; ot->cancel = gpencil_interpolate_cancel; - ot->poll = gpencil_interpolate_poll; + ot->poll = gpencil_view3d_poll; /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; @@ -1017,7 +1018,7 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) /* api callbacks */ ot->exec = gpencil_interpolate_seq_exec; - ot->poll = gpencil_interpolate_poll; + ot->poll = gpencil_view3d_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1025,24 +1026,14 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) /* ******************** Remove Breakdowns ************************ */ -/* Same as gpencil_interpolate_poll(), - * except we ALSO need to have an active frame that is a breakdown - */ static int gpencil_interpolate_reverse_poll(bContext *C) { - bGPdata *gpd = CTX_data_gpencil_data(C); - bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); - - /* only 3D view */ - if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) { - return 0; - } - - /* need data to interpolate */ - if (ELEM(NULL, gpd, gpl)) { + if (!gpencil_view3d_poll(C)) { return 0; } - + + bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); + /* need to be on a breakdown frame */ if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN)) { CTX_wm_operator_poll_msg_set(C, "Expected current frame to be a breakdown"); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9fbce7dd203..4945406c57b 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -421,7 +421,7 @@ typedef void (*uiBlockCancelFunc)(struct bContext *C, void *arg1); void UI_popup_block_invoke(struct bContext *C, uiBlockCreateFunc func, void *arg); void UI_popup_block_invoke_ex(struct bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext); -void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg); +void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg, struct wmOperator *op); /* void uiPupBlockOperator(struct bContext *C, uiBlockCreateFunc func, struct wmOperator *op, int opcontext); */ /* UNUSED */ void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *block); @@ -695,7 +695,7 @@ void UI_but_func_search_set( int UI_searchbox_size_y(void); int UI_searchbox_size_x(void); /* check if a string is in an existing search box */ -int UI_search_items_find_index(uiSearchItems *items, const char *name); +int UI_search_items_find_index(uiSearchItems *items, const char *name, const size_t offset); void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg); void UI_block_func_butmenu_set(uiBlock *block, uiMenuHandleFunc func, void *arg); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 57f3d228a17..d4b1a7e603a 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1337,7 +1337,7 @@ static void ui_but_to_pixelrect(rcti *rect, const ARegion *ar, uiBlock *block, u rctf rectf; ui_block_to_window_rctf(ar, block, &rectf, (but) ? &but->rect : &block->rect); - BLI_rcti_rctf_copy_floor(rect, &rectf); + BLI_rcti_rctf_copy(rect, &rectf); BLI_rcti_translate(rect, -ar->winrct.xmin, -ar->winrct.ymin); } @@ -3913,7 +3913,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block, int type, wmOperatorType *ot, int o uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, int opcontext, int icon, const char *str, int x, int y, short width, short height, const char *tip) { wmOperatorType *ot = WM_operatortype_find(opname, 0); - if (str[0] == '\0') + if (str && str[0] == '\0') return uiDefIconButO_ptr(block, type, ot, opcontext, icon, x, y, width, height, tip); return uiDefIconTextButO_ptr(block, type, ot, opcontext, icon, str, x, y, width, height, tip); } @@ -4372,7 +4372,7 @@ void UI_but_func_search_set( if (0 == (but->block->flag & UI_BLOCK_LOOP)) { /* skip empty buttons, not all buttons need input, we only show invalid */ if (but->drawstr[0]) - ui_but_search_refresh(but); + ui_but_search_refresh(but, false); } } diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 5da294302e9..a04360b3395 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -39,6 +39,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_nla.h" @@ -210,6 +211,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str) /* updates */ driver->flag |= DRIVER_FLAG_RECOMPILE; + DAG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL); ok = true; } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 6e3c3c3674a..2974c2e9304 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -87,6 +87,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "wm_event_system.h" #ifdef WITH_INPUT_IME # include "wm_window.h" @@ -380,6 +381,7 @@ typedef struct uiAfterFunc { void *butm_func_arg; int a2; + wmOperator *popup_op; wmOperatorType *optype; int opcontext; PointerRNA *opptr; @@ -635,13 +637,24 @@ PointerRNA *ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext, return ptr; } +static void popup_check(bContext *C, wmOperator *op) +{ + if (op && op->type->check && op->type->check(C, op)) { + /* check for popup and re-layout buttons */ + ARegion *ar_menu = CTX_wm_menu(C); + if (ar_menu) + ED_region_tag_refresh_ui(ar_menu); + } +} + /** * Check if a #uiAfterFunc is needed for this button. */ static bool ui_afterfunc_check(const uiBlock *block, const uiBut *but) { return (but->func || but->funcN || but->rename_func || but->optype || but->rnaprop || block->handle_func || - (but->type == UI_BTYPE_BUT_MENU && block->butm_func)); + (but->type == UI_BTYPE_BUT_MENU && block->butm_func) || + (block->handle && block->handle->popup_op)); } static void ui_apply_but_func(bContext *C, uiBut *but) @@ -682,6 +695,9 @@ static void ui_apply_but_func(bContext *C, uiBut *but) after->butm_func_arg = block->butm_func_arg; after->a2 = but->a2; } + + if (block->handle) + after->popup_op = block->handle->popup_op; after->optype = but->optype; after->opcontext = but->opcontext; @@ -766,6 +782,9 @@ static void ui_apply_but_funcs_after(bContext *C) if (after.context) CTX_store_set(C, after.context); + if (after.popup_op) + popup_check(C, after.popup_op); + if (after.opptr) { /* free in advance to avoid leak on exit */ opptr = *after.opptr; @@ -6665,7 +6684,7 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) { uiBut *but = (uiBut *)arg1; - UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but); + UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but, NULL); } /** @@ -7005,20 +7024,17 @@ static bool ui_but_menu(bContext *C, uiBut *but) uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"), ICON_URL, "WM_OT_doc_view_manual_ui_context"); - WM_operator_properties_create(&ptr_props, "WM_OT_doc_view"); + ptr_props = uiItemFullO(layout, "WM_OT_doc_view", + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"), + ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&ptr_props, "doc_id", buf); - uiItemFullO(layout, "WM_OT_doc_view", - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"), - ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0); /* XXX inactive option, not for public! */ #if 0 - WM_operator_properties_create(&ptr_props, "WM_OT_doc_edit"); + ptr_props = uiItemFullO(layout, "WM_OT_doc_edit", + "Submit Description", ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&ptr_props, "doc_id", buf); RNA_string_set(&ptr_props, "doc_new", RNA_property_description(but->rnaprop)); - - uiItemFullO(layout, "WM_OT_doc_edit", - "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0); #endif } } @@ -10182,6 +10198,25 @@ void UI_popup_handlers_add(bContext *C, ListBase *handlers, uiPopupBlockHandle * void UI_popup_handlers_remove(ListBase *handlers, uiPopupBlockHandle *popup) { + wmEventHandler *handler; + + for (handler = handlers->first; handler; handler = handler->next) { + if (handler->ui_handle == ui_popup_handler && + handler->ui_remove == ui_popup_handler_remove && + handler->ui_userdata == popup) + { + /* tag refresh parent popup */ + if (handler->next && + handler->next->ui_handle == ui_popup_handler && + handler->next->ui_remove == ui_popup_handler_remove) + { + uiPopupBlockHandle *parent_popup = handler->next->ui_userdata; + ED_region_tag_refresh_ui(parent_popup->region); + } + break; + } + } + WM_event_remove_ui_handler(handlers, ui_popup_handler, ui_popup_handler_remove, popup, false); } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index d8f9fdcbaae..6706298c3c0 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -556,6 +556,7 @@ struct uiPopupBlockHandle { struct uiKeyNavLock keynav_state; /* for operator popups */ + struct wmOperator *popup_op; struct wmOperatorType *optype; ScrArea *ctx_area; ARegion *ctx_region; @@ -604,7 +605,7 @@ int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *ar, uiBut *but void ui_searchbox_event(struct bContext *C, struct ARegion *ar, uiBut *but, const struct wmEvent *event); bool ui_searchbox_apply(uiBut *but, struct ARegion *ar); void ui_searchbox_free(struct bContext *C, struct ARegion *ar); -void ui_but_search_refresh(uiBut *but); +void ui_but_search_refresh(uiBut *but, const bool is_template_ID); uiBlock *ui_popup_block_refresh( struct bContext *C, uiPopupBlockHandle *handle, diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index c62fb4cadd6..30a2094fee7 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1274,7 +1274,8 @@ static void ui_item_rna_size( if (!w) { if (type == PROP_ENUM && icon_only) { w = ui_text_icon_width(layout, "", ICON_BLANK1, 0); - w += 0.6f * UI_UNIT_X; + if (index != RNA_ENUM_VALUE) + w += 0.6f * UI_UNIT_X; } else { w = ui_text_icon_width(layout, name, icon, 0); @@ -2171,7 +2172,17 @@ static void ui_litem_layout_row(uiLayout *litem) x += neww; - if ((neww < minw || itemw == minw || item->flag & UI_ITEM_MIN) && w != 0) { + bool min_flag = item->flag & UI_ITEM_MIN; + /* ignore min flag for rows with right or center alignment */ + if (item->type != ITEM_BUTTON && + ELEM(((uiLayout *)item)->alignment, UI_LAYOUT_ALIGN_RIGHT, UI_LAYOUT_ALIGN_CENTER) && + litem->alignment == UI_LAYOUT_ALIGN_EXPAND && + ((uiItem *)litem)->flag & UI_ITEM_MIN) + { + min_flag = false; + } + + if ((neww < minw || min_flag) && w != 0) { /* fixed size */ item->flag |= UI_ITEM_FIXED; if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) { @@ -2253,10 +2264,11 @@ static void ui_litem_layout_row(uiLayout *litem) } /* single-column layout */ -static void ui_litem_estimate_column(uiLayout *litem) +static void ui_litem_estimate_column(uiLayout *litem, bool is_box) { uiItem *item; int itemw, itemh; + bool min_size_flag = true; litem->w = 0; litem->h = 0; @@ -2264,15 +2276,21 @@ static void ui_litem_estimate_column(uiLayout *litem) for (item = litem->items.first; item; item = item->next) { ui_item_size(item, &itemw, &itemh); + min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN); + litem->w = MAX2(litem->w, itemw); litem->h += itemh; - if (item->next) + if (item->next && (!is_box || item != litem->items.first)) litem->h += litem->space; } + + if (min_size_flag) { + litem->item.flag |= UI_ITEM_MIN; + } } -static void ui_litem_layout_column(uiLayout *litem) +static void ui_litem_layout_column(uiLayout *litem, bool is_box) { uiItem *item; int itemh, x, y; @@ -2286,7 +2304,7 @@ static void ui_litem_layout_column(uiLayout *litem) y -= itemh; ui_item_position(item, x, y, litem->w, itemh); - if (item->next) + if (item->next && (!is_box || item != litem->items.first)) y -= litem->space; } @@ -2428,7 +2446,7 @@ static void ui_litem_layout_root(uiLayout *litem) else if (litem->root->type == UI_LAYOUT_PIEMENU) ui_litem_layout_root_radial(litem); else - ui_litem_layout_column(litem); + ui_litem_layout_column(litem, false); } /* box layout */ @@ -2436,9 +2454,10 @@ static void ui_litem_estimate_box(uiLayout *litem) { uiStyle *style = litem->root->style; - ui_litem_estimate_column(litem); + ui_litem_estimate_column(litem, true); + litem->item.flag &= ~UI_ITEM_MIN; litem->w += 2 * style->boxspace; - litem->h += style->boxspace; + litem->h += 2 * style->boxspace; } static void ui_litem_layout_box(uiLayout *litem) @@ -2452,17 +2471,18 @@ static void ui_litem_layout_box(uiLayout *litem) h = litem->h; litem->x += style->boxspace; + litem->y -= style->boxspace; if (w != 0) litem->w -= 2 * style->boxspace; if (h != 0) litem->h -= 2 * style->boxspace; - ui_litem_layout_column(litem); + ui_litem_layout_column(litem, true); litem->x -= style->boxspace; litem->y -= style->boxspace; if (w != 0) litem->w += 2 * style->boxspace; - if (h != 0) litem->h += style->boxspace; + if (h != 0) litem->h += 2 * style->boxspace; /* roundbox around the sublayout */ but = box->roundbox; @@ -3115,7 +3135,7 @@ static void ui_item_estimate(uiItem *item) switch (litem->item.type) { case ITEM_LAYOUT_COLUMN: - ui_litem_estimate_column(litem); + ui_litem_estimate_column(litem, false); break; case ITEM_LAYOUT_COLUMN_FLOW: ui_litem_estimate_column_flow(litem); @@ -3170,7 +3190,9 @@ static void ui_item_align(uiLayout *litem, short nr) } else if (item->type == ITEM_LAYOUT_BOX) { box = (uiLayoutItemBx *)item; - box->roundbox->alignnr = nr; + if (!box->roundbox->alignnr) { + box->roundbox->alignnr = nr; + } } else if (((uiLayout *)item)->align) { ui_item_align((uiLayout *)item, nr); @@ -3212,7 +3234,7 @@ static void ui_item_layout(uiItem *item) switch (litem->item.type) { case ITEM_LAYOUT_COLUMN: - ui_litem_layout_column(litem); + ui_litem_layout_column(litem, false); break; case ITEM_LAYOUT_COLUMN_FLOW: ui_litem_layout_column_flow(litem); @@ -3556,14 +3578,13 @@ void uiLayoutOperatorButs( row = uiLayoutRow(layout, true); uiItemM(row, (bContext *)C, "WM_MT_operator_presets", NULL, ICON_NONE); - WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add"); + wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false); + op_ptr = uiItemFullO_ptr(row, ot, "", ICON_ZOOMIN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&op_ptr, "operator", op->type->idname); - uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMIN, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0); - WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add"); + op_ptr = uiItemFullO_ptr(row, ot, "", ICON_ZOOMOUT, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&op_ptr, "operator", op->type->idname); RNA_boolean_set(&op_ptr, "remove_active", true); - uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMOUT, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0); } if (op->type->ui) { diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 466978272bc..0d9d8c4f887 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -811,11 +811,11 @@ int UI_searchbox_size_x(void) return 12 * UI_UNIT_X; } -int UI_search_items_find_index(uiSearchItems *items, const char *name) +int UI_search_items_find_index(uiSearchItems *items, const char *name, const size_t offset) { int i; for (i = 0; i < items->totitem; i++) { - if (STREQ(name, items->names[i])) { + if (STREQ(name, items->names[i] + offset)) { return i; } } @@ -894,7 +894,7 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr int ui_searchbox_find_index(ARegion *ar, const char *name) { uiSearchboxData *data = ar->regiondata; - return UI_search_items_find_index(&data->items, name); + return UI_search_items_find_index(&data->items, name, 0); } /* x and y in screencoords */ @@ -1420,14 +1420,14 @@ void ui_searchbox_free(bContext *C, ARegion *ar) /* sets red alert if button holds a string it can't find */ /* XXX weak: search_func adds all partial matches... */ -void ui_but_search_refresh(uiBut *but) +void ui_but_search_refresh(uiBut *but, const bool is_template_ID) { uiSearchItems *items; int x1; - /* possibly very large lists (such as ID datablocks) only - * only validate string RNA buts (not pointers) */ - if (but->rnaprop && RNA_property_type(but->rnaprop) != PROP_STRING) { + /* possibly very large lists (such as ID datablocks), + * only validate string and pointer RNA buts */ + if (but->rnaprop && !ELEM(RNA_property_type(but->rnaprop), PROP_STRING, PROP_POINTER)) { return; } @@ -1447,7 +1447,8 @@ void ui_but_search_refresh(uiBut *but) UI_but_flag_enable(but, UI_BUT_REDALERT); } else if (items->more == 0) { - if (UI_search_items_find_index(items, but->drawstr) == -1) { + const size_t offset = is_template_ID ? 3 : 0; + if (UI_search_items_find_index(items, but->drawstr, offset) == -1) { UI_but_flag_enable(but, UI_BUT_REDALERT); } } @@ -1692,6 +1693,28 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar) UI_block_draw(C, block); } +/** + * Use to refresh centered popups on screen resizing (for splash). + */ +static void ui_block_region_popup_window_listener( + bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +{ + switch (wmn->category) { + case NC_WINDOW: + { + switch (wmn->action) { + case NA_EDITED: + { + /* window resize */ + ED_region_tag_refresh_ui(ar); + break; + } + } + break; + } + } +} + static void ui_popup_block_clip(wmWindow *window, uiBlock *block) { uiBut *bt; @@ -2003,6 +2026,11 @@ uiPopupBlockHandle *ui_popup_block_create( block = ui_popup_block_refresh(C, handle, butregion, but); handle = block->handle; + /* keep centered on window resizing */ + if ((block->bounds_type == UI_BLOCK_BOUNDS_POPUP_CENTER) && handle->can_refresh) { + type.listener = ui_block_region_popup_window_listener; + } + return handle; } @@ -3285,7 +3313,7 @@ void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg) UI_popup_block_invoke_ex(C, func, arg, NULL, WM_OP_INVOKE_DEFAULT); } -void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg) +void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg, wmOperator *op) { wmWindow *window = CTX_wm_window(C); uiPopupBlockHandle *handle; @@ -3294,6 +3322,7 @@ void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc po handle->popup = true; handle->retvalue = 1; + handle->popup_op = op; handle->popup_arg = arg; handle->popup_func = popup_func; handle->cancel_func = cancel_func; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 131584dd405..a3541e641ed 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -451,6 +451,11 @@ static void template_ID( but = uiDefButR(block, UI_BTYPE_TEXT, 0, name, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, &idptr, "name", -1, 0, 0, -1, -1, RNA_struct_ui_description(type)); UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME)); + + but->search_func = id_search_cb; + but->search_arg = template; + ui_but_search_refresh(but, true); + if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT); if (id->lib) { diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index df6f098ee81..636b7e4e9ce 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -127,12 +127,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind break; case PROP_POINTER: { - PointerRNA pptr; - - pptr = RNA_property_pointer_get(ptr, prop); - if (!pptr.type) - pptr.type = RNA_property_pointer_type(ptr, prop); - icon = RNA_struct_ui_icon(pptr.type); + if (icon == 0) { + PointerRNA pptr = RNA_property_pointer_get(ptr, prop); + icon = RNA_struct_ui_icon(pptr.type ? pptr.type : RNA_property_pointer_type(ptr, prop)); + } if (icon == ICON_DOT) icon = 0; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 5ec0c49a8cd..f7f2b422724 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -874,24 +874,18 @@ static void widget_draw_icon( float ofs = 1.0f / aspect; if (but->drawflag & UI_BUT_ICON_LEFT) { - if (but->block->flag & UI_BLOCK_LOOP) { - if (but->type == UI_BTYPE_SEARCH_MENU) - xs = rect->xmin + 4.0f * ofs; - else - xs = rect->xmin + ofs; - } - else { - if (but->dt == UI_EMBOSS_NONE || but->type == UI_BTYPE_LABEL) - xs = rect->xmin + 2.0f * ofs; - else - xs = rect->xmin + 4.0f * ofs; - } - ys = (rect->ymin + rect->ymax - height) / 2.0f; + /* special case - icon_only pie buttons */ + if (ui_block_is_pie_menu(but->block) && but->type != UI_BTYPE_MENU && but->str && but->str[0] == '\0') + xs = rect->xmin + 2.0f * ofs; + else if (but->dt == UI_EMBOSS_NONE || but->type == UI_BTYPE_LABEL) + xs = rect->xmin + 2.0f * ofs; + else + xs = rect->xmin + 4.0f * ofs; } else { xs = (rect->xmin + rect->xmax - height) / 2.0f; - ys = (rect->ymin + rect->ymax - height) / 2.0f; } + ys = (rect->ymin + rect->ymax - height) / 2.0f; /* force positions to integers, for zoom levels near 1. draws icons crisp. */ if (aspect > 0.95f && aspect < 1.05f) { diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 0e185cd93a7..139c9817437 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -97,7 +97,10 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) int use_blender_profile; int sort_by_name; int export_transformation_type; + int open_sim; + int limit_precision; + int keep_bind_info; int export_count; @@ -148,6 +151,9 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) export_transformation_type = RNA_enum_get(op->ptr, "export_transformation_type_selection"); open_sim = RNA_boolean_get(op->ptr, "open_sim"); + limit_precision = RNA_boolean_get(op->ptr, "limit_precision"); + keep_bind_info = RNA_boolean_get(op->ptr, "keep_bind_info"); + /* get editmode results */ ED_object_editmode_load(CTX_data_edit_object(C)); @@ -172,7 +178,11 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) use_blender_profile, sort_by_name, export_transformation_type, - open_sim); + + open_sim, + limit_precision, + keep_bind_info + ); if (export_count == 0) { BKE_report(op->reports, RPT_WARNING, "No objects selected -- Created empty export file"); @@ -270,6 +280,12 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr) row = uiLayoutRow(box, false); uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE); + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "keep_bind_info", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "limit_precision", 0, NULL, ICON_NONE); + } static void wm_collada_export_draw(bContext *UNUSED(C), wmOperator *op) @@ -386,6 +402,13 @@ void WM_OT_collada_export(wmOperatorType *ot) RNA_def_boolean(func, "open_sim", 0, "Export to SL/OpenSim", "Compatibility mode for SL, OpenSim and other compatible online worlds"); + + RNA_def_boolean(func, "limit_precision", 0, + "Limit Precision", "Reduce the precision of the exported data to 6 digits"); + + RNA_def_boolean(func, "keep_bind_info", 0, + "Keep Bind Info", "Store Bindpose information in custom bone properties for later use during Collada export"); + } @@ -397,7 +420,9 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) int find_chains; int auto_connect; int fix_orientation; - int min_chain_length; + int min_chain_length; + + int keep_bind_info; if (!RNA_struct_property_is_set(op->ptr, "filepath")) { BKE_report(op->reports, RPT_ERROR, "No filename given"); @@ -409,6 +434,9 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) find_chains = RNA_boolean_get(op->ptr, "find_chains"); auto_connect = RNA_boolean_get(op->ptr, "auto_connect"); fix_orientation = RNA_boolean_get(op->ptr, "fix_orientation"); + + keep_bind_info = RNA_boolean_get(op->ptr, "keep_bind_info"); + min_chain_length = RNA_int_get(op->ptr, "min_chain_length"); RNA_string_get(op->ptr, "filepath", filename); @@ -418,7 +446,8 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) find_chains, auto_connect, fix_orientation, - min_chain_length)) + min_chain_length, + keep_bind_info) ) { return OPERATOR_FINISHED; } @@ -455,6 +484,13 @@ static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr) row = uiLayoutRow(box, false); uiItemR(row, imfptr, "min_chain_length", 0, NULL, ICON_NONE); + + box = uiLayoutBox(layout); + row = uiLayoutRow(box, false); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "keep_bind_info", 0, NULL, ICON_NONE); + } static void wm_collada_import_draw(bContext *UNUSED(C), wmOperator *op) @@ -510,5 +546,9 @@ void WM_OT_collada_import(wmOperatorType *ot) 0, INT_MAX); + RNA_def_boolean(ot->srna, + "keep_bind_info", 0, "Keep Bind Info", + "Store Bindpose information in custom bone properties for later use during Collada export"); + } #endif diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 743efb246ab..7faa1dd99e1 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -57,6 +57,7 @@ #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_material.h" +#include "BKE_object.h" #include "BKE_report.h" #include "BKE_editmesh.h" #include "BKE_multires.h" @@ -596,6 +597,9 @@ int join_mesh_exec(bContext *C, wmOperator *op) BKE_key_sort(key); } + /* Due to dependnecy cycle some other object might access old derived data. */ + BKE_object_free_derived_caches(ob); + DAG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */ DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index d601f5c3b14..1aa1407797b 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -793,7 +793,7 @@ void OBJECT_OT_modifier_add(wmOperatorType *ot) /* identifiers */ ot->name = "Add Modifier"; - ot->description = "Add a modifier to the active object"; + ot->description = "Add a procedural operation/effect to the active object"; ot->idname = "OBJECT_OT_modifier_add"; /* api callbacks */ @@ -1484,7 +1484,6 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(ob); BMesh *bm = em->bm; - const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN); BMVert *bm_vert; BMIter bm_iter; GSet *visited; @@ -1493,6 +1492,8 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op)) BKE_mesh_ensure_skin_customdata(ob->data); + const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN); + BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT) && BLI_gset_add(visited, bm_vert)) diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index b5fbe4ba586..861e249b0ee 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -72,6 +72,7 @@ #include "BKE_global.h" #include "BKE_group.h" #include "BKE_fcurve.h" +#include "BKE_idprop.h" #include "BKE_lamp.h" #include "BKE_lattice.h" #include "BKE_library.h" @@ -2101,6 +2102,34 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo single_tex_users_expand(bmain); } + /* Relink datablock pointer properties */ + { + IDP_RelinkProperty(scene->id.properties); + + for (Base *base = scene->base.first; base; base = base->next) { + Object *ob = base->object; + if (!ID_IS_LINKED_DATABLOCK(ob)) { + IDP_RelinkProperty(ob->id.properties); + } + } + + if (scene->nodetree) { + IDP_RelinkProperty(scene->nodetree->id.properties); + for (bNode *node = scene->nodetree->nodes.first; node; node = node->next) { + IDP_RelinkProperty(node->prop); + } + } + + if (scene->gpd) { + IDP_RelinkProperty(scene->gpd->id.properties); + } + + IDP_RelinkProperty(scene->world->id.properties); + + if (scene->clip) { + IDP_RelinkProperty(scene->clip->id.properties); + } + } BKE_main_id_clear_newpoins(bmain); DAG_relations_tag_update(bmain); } diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 837573ad175..0878636d0fa 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -611,7 +611,7 @@ void WORLD_OT_new(wmOperatorType *ot) /* identifiers */ ot->name = "New World"; ot->idname = "WORLD_OT_new"; - ot->description = "Add a new world"; + ot->description = "Create a new world Data-Block"; /* api callbacks */ ot->exec = new_world_exec; diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 93bac3f6660..216cbe9d7f4 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -566,7 +566,7 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo float rast_x = x + off_x * xzoom; float rast_y = y + off_y * yzoom; - GLfloat scissor[4]; + GLfloat viewport[4]; int draw_w, draw_h; /* Determine the smallest number of pixels we need to draw @@ -581,9 +581,9 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo * fails if we zoom in on one really huge pixel so that it * covers the entire screen). */ - glGetFloatv(GL_SCISSOR_BOX, scissor); - draw_w = min_ii(img_w - off_x, ceil((scissor[2] - rast_x) / xzoom)); - draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom)); + glGetFloatv(GL_VIEWPORT, viewport); + draw_w = min_ii(img_w - off_x, ceil((viewport[2] - rast_x) / xzoom)); + draw_h = min_ii(img_h - off_y, ceil((viewport[3] - rast_y) / yzoom)); if (draw_w > 0 && draw_h > 0) { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index d88c36a8e24..c2e094fc161 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2808,7 +2808,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent bScreen *sc = CTX_wm_screen(C); uiPopupMenu *pup; uiLayout *layout; - PointerRNA ptr1, ptr2; + PointerRNA ptr; ScrEdge *actedge; const int winsize_x = WM_window_pixels_x(win); const int winsize_y = WM_window_pixels_y(win); @@ -2820,22 +2820,17 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE); layout = UI_popup_menu_layout(pup); - WM_operator_properties_create(&ptr1, "SCREEN_OT_area_join"); - - /* mouse cursor on edge, '4' can fail on wide edges... */ - RNA_int_set(&ptr1, "min_x", event->x + 4); - RNA_int_set(&ptr1, "min_y", event->y + 4); - RNA_int_set(&ptr1, "max_x", event->x - 4); - RNA_int_set(&ptr1, "max_y", event->y - 4); - - WM_operator_properties_create(&ptr2, "SCREEN_OT_area_split"); - + ptr = uiItemFullO(layout, "SCREEN_OT_area_split", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); /* store initial mouse cursor position */ - RNA_int_set(&ptr2, "mouse_x", event->x); - RNA_int_set(&ptr2, "mouse_y", event->y); - - uiItemFullO(layout, "SCREEN_OT_area_split", NULL, ICON_NONE, ptr2.data, WM_OP_INVOKE_DEFAULT, 0); - uiItemFullO(layout, "SCREEN_OT_area_join", NULL, ICON_NONE, ptr1.data, WM_OP_INVOKE_DEFAULT, 0); + RNA_int_set(&ptr, "mouse_x", event->x); + RNA_int_set(&ptr, "mouse_y", event->y); + + ptr = uiItemFullO(layout, "SCREEN_OT_area_join", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); + /* mouse cursor on edge, '4' can fail on wide edges... */ + RNA_int_set(&ptr, "min_x", event->x + 4); + RNA_int_set(&ptr, "min_y", event->y + 4); + RNA_int_set(&ptr, "max_x", event->x - 4); + RNA_int_set(&ptr, "max_y", event->y - 4); UI_popup_menu_end(C, pup); diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index c2c52f58181..e273d3a40f0 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -670,7 +670,7 @@ static void SOUND_OT_mixdown(wmOperatorType *ot) /* identifiers */ ot->name = "Mixdown"; - ot->description = "Mixes the scene's audio to a sound file"; + ot->description = "Mix the scene's audio to a sound file"; ot->idname = "SOUND_OT_mixdown"; /* api callbacks */ diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index b7871225306..646541c7bd9 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -72,7 +72,7 @@ void clip_graph_tracking_values_iterate_track( BKE_movieclip_get_size(clip, &sc->user, &width, &height); for (coord = 0; coord < 2; coord++) { - int i, prevfra = 0; + int i, prevfra = track->markers[0].framenr; bool open = false; float prevval = 0.0f; @@ -179,6 +179,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track) ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); bool has_bundle = false; char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2]; + const bool used_for_stabilization = (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)); if (track == act_track) tracking->act_track = NULL; @@ -200,7 +201,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track) WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); - if (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)) { + if (used_for_stabilization) { WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip); } diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index d7aa1040e0f..71d49e0dc2e 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -169,12 +169,15 @@ void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path) static void fsmenu_entry_generate_name(struct FSMenuEntry *fsentry, char *name, size_t name_size) { - char temp[FILE_MAX]; + int offset = 0; + int len = name_size; - BLI_strncpy(temp, fsentry->path, FILE_MAX); - BLI_add_slash(temp); - BLI_getlastdir(temp, name, name_size); - BLI_del_slash(name); + if (BLI_path_name_at_index(fsentry->path, -1, &offset, &len)) { + /* use as size */ + len += 1; + } + + BLI_strncpy(name, &fsentry->path[offset], MIN2(len, name_size)); if (!name[0]) { name[0] = '/'; name[1] = '\0'; diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index d31a475e45e..e4f5802a395 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1320,9 +1320,6 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point PropertyRNA *prop; const char *layer_name; char scene_name[MAX_ID_NAME - 2]; - wmOperatorType *ot = WM_operatortype_find("RENDER_OT_render", 1); - - BLI_assert(ot != 0); uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL); @@ -1339,11 +1336,9 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point scn_ptr = RNA_pointer_get(ptr, "scene"); RNA_string_get(&scn_ptr, "name", scene_name); - WM_operator_properties_create_ptr(&op_ptr, ot); + op_ptr = uiItemFullO(row, "RENDER_OT_render", "", ICON_RENDER_STILL, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&op_ptr, "layer", layer_name); RNA_string_set(&op_ptr, "scene", scene_name); - uiItemFullO_ptr(row, ot, "", ICON_RENDER_STILL, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0); - } @@ -1792,6 +1787,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi Scene *scene = CTX_data_scene(C); PointerRNA imfptr = RNA_pointer_get(ptr, "format"); PointerRNA active_input_ptr, op_ptr; + wmOperatorType *ot; uiLayout *row, *col; int active_index; const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER; @@ -1830,11 +1826,10 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi active_input_ptr.id.data = ptr->id.data; col = uiLayoutColumn(row, true); - op_ptr = uiItemFullO(col, "NODE_OT_output_file_move_active_socket", "", - ICON_TRIA_UP, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); + ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false); + op_ptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&op_ptr, "direction", 1); - op_ptr = uiItemFullO(col, "NODE_OT_output_file_move_active_socket", "", - ICON_TRIA_DOWN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); + op_ptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&op_ptr, "direction", 2); if (active_input_ptr.data) { @@ -2166,14 +2161,7 @@ static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), Poi static void node_composit_buts_switch_view_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *UNUSED(ptr)) { - PointerRNA op_ptr; - wmOperatorType *ot = WM_operatortype_find("NODE_OT_switch_view_update", 1); - - BLI_assert(ot != 0); - - WM_operator_properties_create_ptr(&op_ptr, ot); - - uiItemFullO_ptr(layout, ot, "Update Views", ICON_FILE_REFRESH, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0); + uiItemFullO(layout, "NODE_OT_switch_view_update", "Update Views", ICON_FILE_REFRESH, NULL, WM_OP_INVOKE_DEFAULT, 0); } static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index d49df2afbd4..bcd0f6623e1 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -44,6 +44,8 @@ #include "BKE_main.h" #include "BKE_node.h" #include "BKE_report.h" +#include "BKE_scene.h" +#include "BKE_texture.h" #include "ED_node.h" /* own include */ #include "ED_screen.h" @@ -312,7 +314,10 @@ static int node_add_file_exec(bContext *C, wmOperator *op) switch (snode->nodetree->type) { case NTREE_SHADER: - type = SH_NODE_TEX_IMAGE; + if (BKE_scene_use_new_shading_nodes(CTX_data_scene(C))) + type = SH_NODE_TEX_IMAGE; + else + type = SH_NODE_TEXTURE; break; case NTREE_TEXTURE: type = TEX_NODE_IMAGE; @@ -333,7 +338,14 @@ static int node_add_file_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - node->id = (ID *)ima; + if (type == SH_NODE_TEXTURE) { + Tex *tex = BKE_texture_add(CTX_data_main(C), DATA_(ima->id.name)); + tex->ima = ima; + node->id = (ID *)tex; + WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, node->id); + } + else + node->id = (ID *)ima; /* When adding new image file via drag-drop we need to load imbuf in order * to get proper image source. diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c index f0567924edd..925298451ce 100644 --- a/source/blender/editors/space_node/node_buttons.c +++ b/source/blender/editors/space_node/node_buttons.c @@ -133,6 +133,7 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa) int in_out; uiLayout *layout = pa->layout, *row, *split, *col; PointerRNA ptr, sockptr, opptr; + wmOperatorType *ot; if (!ntree) return; @@ -146,23 +147,25 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa) split = uiLayoutRow(row, true); col = uiLayoutColumn(split, true); + ot = WM_operatortype_find("NODE_OT_tree_socket_add", false); uiItemL(col, IFACE_("Inputs:"), ICON_NONE); uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "inputs", &ptr, "inputs", &ptr, "active_input", NULL, 0, 0, 0, 0); - opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); + opptr = uiItemFullO_ptr(col, ot, "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&opptr, "in_out", SOCK_IN); col = uiLayoutColumn(split, true); uiItemL(col, IFACE_("Outputs:"), ICON_NONE); uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "outputs", &ptr, "outputs", &ptr, "active_output", NULL, 0, 0, 0, 0); - opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); + opptr = uiItemFullO_ptr(col, ot, "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&opptr, "in_out", SOCK_OUT); + ot = WM_operatortype_find("NODE_OT_tree_socket_move", false); col = uiLayoutColumn(row, true); - opptr = uiItemFullO(col, "NODE_OT_tree_socket_move", "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); + opptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&opptr, "direction", 1); - opptr = uiItemFullO(col, "NODE_OT_tree_socket_move", "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); + opptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&opptr, "direction", 2); if (sock) { diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 42d9e4356ee..121fe812016 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1052,8 +1052,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT; x += 2.0f * aspect; y += 2.0f * aspect; - arg.x = x = x; - arg.y = y = y; + arg.x = x; + arg.y = y; if (tselem->type) { switch (tselem->type) { diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 8c3b9a55089..335eb95da0e 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -519,7 +519,8 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot) ot->flag = 0; - RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", ""); + prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", ""); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace"); RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf); @@ -2071,74 +2072,62 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false); uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE); uiLayout *layout = UI_popup_menu_layout(pup); - PointerRNA ptr; - WM_operator_properties_create_ptr(&ptr, ot); + /* Cannot use uiItemEnumO()... have multiple properties to set. */ + ptr = uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&ptr, "parent", parname); RNA_string_set(&ptr, "child", childname); RNA_enum_set(&ptr, "type", PAR_OBJECT); - /* Cannot use uiItemEnumO()... have multiple properties to set. */ - uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); - + /* par becomes parent, make the associated menus */ if (par->type == OB_ARMATURE) { - WM_operator_properties_create_ptr(&ptr, ot); + ptr = uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&ptr, "parent", parname); RNA_string_set(&ptr, "child", childname); RNA_enum_set(&ptr, "type", PAR_ARMATURE); - uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); - - WM_operator_properties_create_ptr(&ptr, ot); + + ptr = uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&ptr, "parent", parname); RNA_string_set(&ptr, "child", childname); RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME); - uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); - - WM_operator_properties_create_ptr(&ptr, ot); + + ptr = uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&ptr, "parent", parname); RNA_string_set(&ptr, "child", childname); RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE); - uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); - - WM_operator_properties_create_ptr(&ptr, ot); + + ptr = uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&ptr, "parent", parname); RNA_string_set(&ptr, "child", childname); RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO); - uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); - - WM_operator_properties_create_ptr(&ptr, ot); + + ptr = uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&ptr, "parent", parname); RNA_string_set(&ptr, "child", childname); RNA_enum_set(&ptr, "type", PAR_BONE); - uiItemFullO_ptr(layout, ot, IFACE_("Bone"), - 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); } else if (par->type == OB_CURVE) { - WM_operator_properties_create_ptr(&ptr, ot); + ptr = uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&ptr, "parent", parname); RNA_string_set(&ptr, "child", childname); RNA_enum_set(&ptr, "type", PAR_CURVE); - uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); - - WM_operator_properties_create_ptr(&ptr, ot); + + ptr = uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&ptr, "parent", parname); RNA_string_set(&ptr, "child", childname); RNA_enum_set(&ptr, "type", PAR_FOLLOW); - uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); - - WM_operator_properties_create_ptr(&ptr, ot); + + ptr = uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&ptr, "parent", parname); RNA_string_set(&ptr, "child", childname); RNA_enum_set(&ptr, "type", PAR_PATH_CONST); - uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); } else if (par->type == OB_LATTICE) { - WM_operator_properties_create_ptr(&ptr, ot); + ptr = uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_string_set(&ptr, "parent", parname); RNA_string_set(&ptr, "child", childname); RNA_enum_set(&ptr, "type", PAR_LATTICE); - uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); } UI_popup_menu_end(C, pup); diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index ede6b7ce469..46f212e3679 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -38,6 +38,8 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "DNA_scene_types.h" #include "DNA_mask_types.h" @@ -445,6 +447,7 @@ void SEQUENCER_OT_movieclip_strip_add(struct wmOperatorType *ot) sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME); prop = RNA_def_enum(ot->srna, "clip", DummyRNA_NULL_items, 0, "Clip", ""); RNA_def_enum_funcs(prop, RNA_movieclip_itemf); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_MOVIECLIP); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index be2e4ab05e0..335d0649729 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -1824,16 +1824,16 @@ static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], con glBegin(mode); glVertex3fv(near_plane[2]); - glVertex3fv(near_plane[1]); - glVertex3fv(far_plane[1]); glVertex3fv(far_plane[2]); + glVertex3fv(far_plane[3]); + glVertex3fv(near_plane[3]); glEnd(); glBegin(mode); - glVertex3fv(far_plane[0]); - glVertex3fv(near_plane[0]); - glVertex3fv(near_plane[3]); glVertex3fv(far_plane[3]); + glVertex3fv(near_plane[3]); + glVertex3fv(near_plane[0]); + glVertex3fv(far_plane[0]); glEnd(); } @@ -4212,7 +4212,6 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D if (is_obact && BKE_paint_select_vert_test(ob)) { const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0; - glColor3f(0.0f, 0.0f, 0.0f); glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); if (!use_depth) glDisable(GL_DEPTH_TEST); diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 351c7ccec15..34e01405e7e 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -814,10 +814,6 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa) if (dv && dv->totweight) { ToolSettings *ts = scene->toolsettings; - wmOperatorType *ot_weight_set_active = WM_operatortype_find("OBJECT_OT_vertex_weight_set_active", true); - wmOperatorType *ot_weight_paste = WM_operatortype_find("OBJECT_OT_vertex_weight_paste", true); - wmOperatorType *ot_weight_delete = WM_operatortype_find("OBJECT_OT_vertex_weight_delete", true); - wmOperatorType *ot; PointerRNA op_ptr, tools_ptr; PointerRNA *but_ptr; @@ -856,7 +852,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa) /* The Weight Group Name */ - ot = ot_weight_set_active; + ot = WM_operatortype_find("OBJECT_OT_vertex_weight_set_active", true); but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, dg->name, xco, yco, (x = UI_UNIT_X * 5), UI_UNIT_Y, ""); but_ptr = UI_but_operator_ptr_get(but); @@ -882,23 +878,16 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa) xco += x; /* The weight group paste function */ - - ot = ot_weight_paste; - WM_operator_properties_create_ptr(&op_ptr, ot); - RNA_int_set(&op_ptr, "weight_group", i); icon = (locked) ? ICON_BLANK1 : ICON_PASTEDOWN; - uiItemFullO_ptr(row, ot, "", icon, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0); + op_ptr = uiItemFullO(row, "OBJECT_OT_vertex_weight_paste", "", icon, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_int_set(&op_ptr, "weight_group", i); /* The weight entry delete function */ - - ot = ot_weight_delete; - WM_operator_properties_create_ptr(&op_ptr, ot); - RNA_int_set(&op_ptr, "weight_group", i); icon = (locked) ? ICON_LOCKED : ICON_X; - uiItemFullO_ptr(row, ot, "", icon, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0); + op_ptr = uiItemFullO(row, "OBJECT_OT_vertex_weight_delete", "", icon, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_int_set(&op_ptr, "weight_group", i); yco -= UI_UNIT_Y; - } } } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 8230a0de6b9..fe8274064e5 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1405,6 +1405,8 @@ static bool view3d_localview_init( } } + DAG_on_visible_update(bmain, false); + return ok; } diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 0a984d90ae3..f23c913da1e 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -143,21 +143,17 @@ static void protectflag_to_drawflags(short protectflag, short *drawflags) } /* for pose mode */ -static void stats_pose(Scene *scene, RegionView3D *rv3d, bPoseChannel *pchan) +static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan) { - Bone *bone = pchan->bone; - - if (bone) { - calc_tw_center(scene, pchan->pose_head); - protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag); - } + protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag); } /* for editmode*/ -static void stats_editbone(RegionView3D *rv3d, EditBone *ebo) +static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *ebo) { - if (ebo->flag & BONE_EDITMODE_LOCKED) + if (ebo->flag & BONE_EDITMODE_LOCKED) { protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag); + } } /* could move into BLI_math however this is only useful for display/editing purposes */ @@ -192,73 +188,71 @@ static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], con } -static int test_rotmode_euler(short rotmode) +static bool test_rotmode_euler(short rotmode) { return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1; } bool gimbal_axis(Object *ob, float gmat[3][3]) { - if (ob) { - if (ob->mode & OB_MODE_POSE) { - bPoseChannel *pchan = BKE_pose_channel_active(ob); - - if (pchan) { - float mat[3][3], tmat[3][3], obmat[3][3]; - if (test_rotmode_euler(pchan->rotmode)) { - eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode); - } - else if (pchan->rotmode == ROT_MODE_AXISANGLE) { - axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle); - } - else { /* quat */ - return 0; - } - - - /* apply bone transformation */ - mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat); + if (ob->mode & OB_MODE_POSE) { + bPoseChannel *pchan = BKE_pose_channel_active(ob); - if (pchan->parent) { - float parent_mat[3][3]; - - copy_m3_m4(parent_mat, pchan->parent->pose_mat); - mul_m3_m3m3(mat, parent_mat, tmat); - - /* needed if object transformation isn't identity */ - copy_m3_m4(obmat, ob->obmat); - mul_m3_m3m3(gmat, obmat, mat); - } - else { - /* needed if object transformation isn't identity */ - copy_m3_m4(obmat, ob->obmat); - mul_m3_m3m3(gmat, obmat, tmat); - } - - normalize_m3(gmat); - return 1; - } - } - else { - if (test_rotmode_euler(ob->rotmode)) { - eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode); + if (pchan) { + float mat[3][3], tmat[3][3], obmat[3][3]; + if (test_rotmode_euler(pchan->rotmode)) { + eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode); } - else if (ob->rotmode == ROT_MODE_AXISANGLE) { - axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle); + else if (pchan->rotmode == ROT_MODE_AXISANGLE) { + axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle); } else { /* quat */ return 0; } - if (ob->parent) { + + /* apply bone transformation */ + mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat); + + if (pchan->parent) { float parent_mat[3][3]; - copy_m3_m4(parent_mat, ob->parent->obmat); - normalize_m3(parent_mat); - mul_m3_m3m3(gmat, parent_mat, gmat); + + copy_m3_m4(parent_mat, pchan->parent->pose_mat); + mul_m3_m3m3(mat, parent_mat, tmat); + + /* needed if object transformation isn't identity */ + copy_m3_m4(obmat, ob->obmat); + mul_m3_m3m3(gmat, obmat, mat); + } + else { + /* needed if object transformation isn't identity */ + copy_m3_m4(obmat, ob->obmat); + mul_m3_m3m3(gmat, obmat, tmat); } + + normalize_m3(gmat); return 1; } } + else { + if (test_rotmode_euler(ob->rotmode)) { + eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode); + } + else if (ob->rotmode == ROT_MODE_AXISANGLE) { + axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle); + } + else { /* quat */ + return 0; + } + + if (ob->parent) { + float parent_mat[3][3]; + copy_m3_m4(parent_mat, ob->parent->obmat); + normalize_m3(parent_mat); + mul_m3_m3m3(gmat, parent_mat, gmat); + } + return 1; + } return 0; } @@ -385,7 +379,7 @@ static int calc_manipulator_stats(const bContext *C) calc_tw_center(scene, ebo->head); totsel++; } - stats_editbone(rv3d, ebo); + protectflag_to_drawflags_ebone(rv3d, ebo); } else { for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { @@ -405,7 +399,7 @@ static int calc_manipulator_stats(const bContext *C) totsel++; } if (ebo->flag & BONE_SELECTED) { - stats_editbone(rv3d, ebo); + protectflag_to_drawflags_ebone(rv3d, ebo); } } } @@ -530,7 +524,8 @@ static int calc_manipulator_stats(const bContext *C) /* doesn't check selection or visibility intentionally */ Bone *bone = pchan->bone; if (bone) { - stats_pose(scene, rv3d, pchan); + calc_tw_center(scene, pchan->pose_head); + protectflag_to_drawflags_pchan(rv3d, pchan); totsel = 1; ok = true; } @@ -543,7 +538,8 @@ 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)) { - stats_pose(scene, rv3d, pchan); + calc_tw_center(scene, pchan->pose_head); + protectflag_to_drawflags_pchan(rv3d, pchan); } } ok = true; diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 058af768885..674d2c376bb 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -451,7 +451,7 @@ void initTransformOrientation(bContext *C, TransInfo *t) case V3D_MANIP_GIMBAL: unit_m3(t->spacemtx); - if (gimbal_axis(ob, t->spacemtx)) { + if (ob && gimbal_axis(ob, t->spacemtx)) { BLI_strncpy(t->spacename, IFACE_("gimbal"), sizeof(t->spacename)); break; } diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 3c9becc60dc..b33528b4149 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -1122,15 +1122,14 @@ static bool snapDerivedMesh( float dist_px_sq = dist_squared_to_projected_aabb_simple( lpmat, snapdata->win_half, ray_min_dist, snapdata->mval, ray_org_local, ray_normal_local, bb->vec[0], bb->vec[6]); - if (dist_px_sq > SQUARE(*dist_px)) - { + if (dist_px_sq > SQUARE(*dist_px)) { return retval; } } else { /* 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], NULL, NULL)) + ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], NULL, NULL)) { return retval; } diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 0d92d22a173..6db23686832 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -98,6 +98,7 @@ typedef enum GPUBuiltin { GPU_PARTICLE_ANG_VELOCITY = (1 << 12), GPU_LOC_TO_VIEW_MATRIX = (1 << 13), GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14), + GPU_OBJECT_INFO = (1 << 15) } GPUBuiltin; typedef enum GPUOpenGLBuiltin { @@ -213,6 +214,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link); void GPU_material_enable_alpha(GPUMaterial *material); +GPUBuiltin GPU_get_material_builtins(GPUMaterial *material); GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]); /* High level functions to create and use GPU materials */ @@ -230,7 +232,7 @@ void GPU_material_bind( float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock); void GPU_material_bind_uniforms( GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4], - float autobumpscale, GPUParticleInfo *pi); + float autobumpscale, GPUParticleInfo *pi, float object_info[3]); void GPU_material_unbind(GPUMaterial *material); bool GPU_material_bound(GPUMaterial *material); struct Scene *GPU_material_scene(GPUMaterial *material); @@ -345,6 +347,7 @@ struct GPUParticleInfo float location[3]; float velocity[3]; float angular_velocity[3]; + int random_id; }; #ifdef WITH_OPENSUBDIV diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c index a2b89239344..8505bd847a0 100644 --- a/source/blender/gpu/intern/gpu_basic_shader.c +++ b/source/blender/gpu/intern/gpu_basic_shader.c @@ -407,7 +407,7 @@ static GPUShader *gpu_basic_shader(int options) return shader; } -static void GPU_basic_shader_uniform_autoset(GPUShader *shader, int options) +static void gpu_basic_shader_uniform_autoset(GPUShader *shader, int options) { if (options & GPU_SHADER_LINE) { glGetIntegerv(GL_VIEWPORT, &GPU_MATERIAL_STATE.viewport[0]); @@ -443,7 +443,7 @@ void GPU_basic_shader_bind(int options) if (shader) { GPU_shader_bind(shader); - GPU_basic_shader_uniform_autoset(shader, options); + gpu_basic_shader_uniform_autoset(shader, options); } } else { diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 370841327aa..3325240a2d1 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -743,7 +743,7 @@ void GPU_triangle_setup(struct DerivedMesh *dm) GLStates |= GPU_BUFFER_ELEMENT_STATE; } -static int GPU_typesize(int type) +static int gpu_typesize(int type) { switch (type) { case GL_FLOAT: @@ -766,7 +766,7 @@ int GPU_attrib_element_size(GPUAttrib data[], int numdata) int i, elementsize = 0; for (i = 0; i < numdata; i++) { - int typesize = GPU_typesize(data[i].type); + int typesize = gpu_typesize(data[i].type); if (typesize != 0) elementsize += typesize * data[i].size; } @@ -803,7 +803,7 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda glVertexAttribPointer(data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, BUFFER_OFFSET(offset)); - offset += data[i].size * GPU_typesize(data[i].type); + offset += data[i].size * gpu_typesize(data[i].type); attribData[i].index = data[i].index; attribData[i].size = data[i].size; diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 211394e7932..b5512aa108d 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -360,7 +360,7 @@ static void codegen_print_datatype(DynStr *ds, const GPUType type, float *data) BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]); for (i = 0; i < type; i++) { - BLI_dynstr_appendf(ds, "%f", data[i]); + BLI_dynstr_appendf(ds, "%.12f", data[i]); if (i == type - 1) BLI_dynstr_append(ds, ")"); else @@ -410,6 +410,8 @@ const char *GPU_builtin_name(GPUBuiltin builtin) return "unfparticlevel"; else if (builtin == GPU_PARTICLE_ANG_VELOCITY) return "unfparticleangvel"; + else if (builtin == GPU_OBJECT_INFO) + return "unfobjectinfo"; else return ""; } diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index 964c2b5051e..2f2a16f9e1d 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -798,7 +798,9 @@ bool GPU_fx_do_composite_pass( ssao_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_SSAO, is_persp); if (ssao_shader) { const GPUSSAOSettings *fx_ssao = fx->settings.ssao; - float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, fx_ssao->attenuation, 0.0f}; + /* adjust attenuation to be scale invariant */ + float attenuation = fx_ssao->attenuation / (fx_ssao->distance_max * fx_ssao->distance_max); + float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, attenuation, 0.0f}; float sample_params[3]; sample_params[0] = fx->ssao_sample_count_cache; diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 7936811ab4d..79934190cbc 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -45,6 +45,7 @@ #include "BLI_math.h" #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BLI_hash.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" @@ -1203,7 +1204,7 @@ void GPU_paint_set_mipmap(bool mipmap) /* check if image has been downscaled and do scaled partial update */ -static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h) +static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h) { if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) || is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) @@ -1296,7 +1297,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0; IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data); - if (GPU_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) { + if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) { MEM_freeN(buffer); BKE_image_release_ibuf(ima, ibuf, NULL); return; @@ -1320,7 +1321,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i return; } - if (GPU_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) { + if (gpu_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) { BKE_image_release_ibuf(ima, ibuf, NULL); return; } @@ -1870,7 +1871,7 @@ void GPU_begin_object_materials( GPU_object_material_unbind(); } -static int GPU_get_particle_info(GPUParticleInfo *pi) +static int gpu_get_particle_info(GPUParticleInfo *pi) { DupliObject *dob = GMS.dob; if (dob->particle_system) { @@ -1899,6 +1900,21 @@ static int GPU_get_particle_info(GPUParticleInfo *pi) return 0; } +static void GPU_get_object_info(float oi[3], Material *mat) +{ + Object *ob = GMS.gob; + oi[0] = ob->index; + oi[1] = mat->index; + unsigned int random; + if (GMS.dob) { + random = GMS.dob->random_id; + } + else { + random = BLI_hash_int_2d(BLI_hash_string(GMS.gob->id.name + 2), 0); + } + oi[2] = random * (1.0f/(float)0xFFFFFFFF); +} + int GPU_object_material_bind(int nr, void *attribs) { GPUVertexAttribs *gattribs = attribs; @@ -1958,21 +1974,27 @@ int GPU_object_material_bind(int nr, void *attribs) /* bind glsl material and get attributes */ Material *mat = GMS.gmatbuf[nr]; GPUParticleInfo partile_info; + float object_info[3] = {0}; float auto_bump_scale; GPUMaterial *gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv); GPU_material_vertex_attributes(gpumat, gattribs); - if (GMS.dob) - GPU_get_particle_info(&partile_info); + if (GMS.dob) { + gpu_get_particle_info(&partile_info); + } + + if (GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) { + GPU_get_object_info(object_info, mat); + } GPU_material_bind( gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock); auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f; - GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info); + GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info); GMS.gboundmat = mat; /* for glsl use alpha blend mode, unless it's set to solid and diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index f62ef677434..e7a8beae5cc 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -52,7 +52,7 @@ struct GPUFrameBuffer { GPUTexture *depthtex; }; -static void GPU_print_framebuffer_error(GLenum status, char err_out[256]) +static void gpu_print_framebuffer_error(GLenum status, char err_out[256]) { const char *err = "unknown"; @@ -164,7 +164,7 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot if (error == GL_INVALID_OPERATION) { GPU_framebuffer_restore(); - GPU_print_framebuffer_error(error, err_out); + gpu_print_framebuffer_error(error, err_out); return 0; } @@ -331,7 +331,7 @@ bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { GPU_framebuffer_restore(); - GPU_print_framebuffer_error(status, err_out); + gpu_print_framebuffer_error(status, err_out); return false; } diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 4e2043471b6..1f3ae7f708a 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -122,6 +122,8 @@ struct GPUMaterial { int partvel; int partangvel; + int objectinfoloc; + ListBase lamps; bool bound; @@ -225,7 +227,7 @@ static void gpu_material_set_attrib_id(GPUMaterial *material) attribs->totlayer = b; } -static int GPU_material_construct_end(GPUMaterial *material, const char *passname) +static int gpu_material_construct_end(GPUMaterial *material, const char *passname) { if (material->outlink) { GPUNodeLink *outlink = material->outlink; @@ -268,6 +270,8 @@ static int GPU_material_construct_end(GPUMaterial *material, const char *passnam material->partvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_VELOCITY)); if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY)); + if (material->builtins & GPU_OBJECT_INFO) + material->objectinfoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_INFO)); return 1; } else { @@ -398,9 +402,14 @@ void GPU_material_bind( } } +GPUBuiltin GPU_get_material_builtins(GPUMaterial *material) +{ + return material->builtins; +} + void GPU_material_bind_uniforms( GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4], - float autobumpscale, GPUParticleInfo *pi) + float autobumpscale, GPUParticleInfo *pi, float object_info[3]) { if (material->pass) { GPUShader *shader = GPU_pass_shader(material->pass); @@ -449,6 +458,9 @@ void GPU_material_bind_uniforms( if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) { GPU_shader_uniform_vector(shader, material->partangvel, 3, 1, pi->angular_velocity); } + if (material->builtins & GPU_OBJECT_INFO) { + GPU_shader_uniform_vector(shader, material->objectinfoloc, 3, 1, object_info); + } } } @@ -1891,7 +1903,7 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv GPU_material_output_link(mat, outlink); - GPU_material_construct_end(mat, "matcap_pass"); + gpu_material_construct_end(mat, "matcap_pass"); /* note that even if building the shader fails in some way, we still keep * it to avoid trying to compile again and again, and simple do not use @@ -2044,7 +2056,7 @@ static void do_world_tex(GPUShadeInput *shi, struct World *wo, GPUNodeLink **hor } } -static void GPU_material_old_world(struct GPUMaterial *mat, struct World *wo) +static void gpu_material_old_world(struct GPUMaterial *mat, struct World *wo) { GPUShadeInput shi; GPUShadeResult shr; @@ -2112,17 +2124,18 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo) mat->type = GPU_MATERIAL_TYPE_WORLD; /* create nodes */ - if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes) + if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes) { ntreeGPUMaterialNodes(wo->nodetree, mat, NODE_NEW_SHADING); + } else { - GPU_material_old_world(mat, wo); + gpu_material_old_world(mat, wo); } if (GPU_material_do_color_management(mat)) if (mat->outlink) GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink); - GPU_material_construct_end(mat, wo->id.name); + gpu_material_construct_end(mat, wo->id.name); /* note that even if building the shader fails in some way, we still keep * it to avoid trying to compile again and again, and simple do not use @@ -2188,7 +2201,7 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_open if (mat->outlink) GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink); - GPU_material_construct_end(mat, ma->id.name); + gpu_material_construct_end(mat, ma->id.name); /* note that even if building the shader fails in some way, we still keep * it to avoid trying to compile again and again, and simple do not use diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 14f2764b009..b579f87698c 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -39,6 +39,7 @@ #include "GPU_glew.h" #include "GPU_shader.h" #include "GPU_texture.h" +#include "GPU_material.h" /* TODO(sergey): Find better default values for this constants. */ #define MAX_DEFINE_LENGTH 1024 diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 54f0003c086..1c97c2ce811 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -79,7 +79,7 @@ static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixel return pixels; } -static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h) +static void gpu_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h) { void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels"); @@ -193,7 +193,7 @@ static GPUTexture *GPU_texture_create_nD( pixels ? pixels : fpixels); if (tex->w > w) { - GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1); + gpu_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1); } } } @@ -210,10 +210,12 @@ static GPUTexture *GPU_texture_create_nD( glTexSubImage2D(tex->target, 0, 0, 0, w, h, format, type, pixels ? pixels : fpixels); - if (tex->w > w) - GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h); - if (tex->h > h) - GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h); + if (tex->w > w) { + gpu_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h); + } + if (tex->h > h) { + gpu_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h); + } } } diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl index 50c8e255162..f19ff4ec65a 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl @@ -75,7 +75,7 @@ float calculate_ssao_factor(float depth) float f = dot(dir, normal); /* use minor bias here to avoid self shadowing */ - if (f > 0.05 * len + 0.0001) + if (f > 0.05 * len) factor += f * 1.0 / (len * (1.0 + len * len * ssao_params.z)); } } diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 0f3ffa8244b..c354b274f00 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -3563,12 +3563,12 @@ void node_light_falloff(float strength, float tsmooth, out float quadratic, out constant = strength; } -void node_object_info(out vec3 location, out float object_index, out float material_index, out float random) +void node_object_info(mat4 obmat, vec3 info, out vec3 location, out float object_index, out float material_index, out float random) { - location = vec3(0.0); - object_index = 0.0; - material_index = 0.0; - random = 0.0; + location = obmat[3].xyz; + object_index = info.x; + material_index = info.y; + random = info.z; } void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal) diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 48cba3e0800..0881a24422d 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -1406,7 +1406,7 @@ static void *do_display_buffer_apply_thread(void *handle_v) bool is_data = handle->is_data; if (cm_processor == NULL) { - if (display_buffer_byte) { + if (display_buffer_byte && display_buffer_byte != handle->byte_buffer) { IMB_buffer_byte_from_byte(display_buffer_byte, handle->byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB, false, width, height, width, width); } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 2c6f3d2fc66..da0f505c4f3 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -82,8 +82,6 @@ enum { IDP_FLOAT = 2, IDP_ARRAY = 5, IDP_GROUP = 6, - /* the ID link property type hasn't been implemented yet, this will require - * some cleanup of blenkernel, most likely. */ IDP_ID = 7, IDP_DOUBLE = 8, IDP_IDPARRAY = 9, diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 621807d111c..3676066a399 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -164,8 +164,8 @@ typedef struct MLoop { * MEdge *ed = &medge[mloop[lt->tri[j]].e]; * unsigned int tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v}; * - * if (ELEM(ed->v1, tri_edge[0], tri_edge[1]) && - * ELEM(ed->v2, tri_edge[0], tri_edge[1])) + * if (((ed->v1 == tri_edge[0]) && (ed->v1 == tri_edge[1])) || + * ((ed->v1 == tri_edge[1]) && (ed->v1 == tri_edge[0]))) * { * printf("real edge found %u %u\n", tri_edge[0], tri_edge[1]); * } diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 32b43c7ea55..823a7f0812f 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -277,6 +277,7 @@ typedef struct MirrorModifierData { short axis DNA_DEPRECATED; /* deprecated, use flag instead */ short flag; float tolerance; + float uv_offset[2]; struct Object *mirror_ob; } MirrorModifierData; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index d24c7faa9f5..6d79e6d49f8 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -335,6 +335,8 @@ typedef struct DupliObject { /* particle this dupli was generated from */ struct ParticleSystem *particle_system; + unsigned int random_id; + unsigned int pad; } DupliObject; /* **************** OBJECT ********************* */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index fc970c40c12..61b580c0904 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -468,13 +468,18 @@ typedef struct UserDef { int audioformat; int audiochannels; - int scrollback; /* console scrollback limit */ - int dpi; /* range 48-128? */ - char node_margin; /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */ + int scrollback; /* console scrollback limit */ + int dpi; /* range 48-128? */ + float ui_scale; /* interface scale */ + int pad1; + char node_margin; /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */ char pad2; short transopts; short menuthreshold1, menuthreshold2; - + + /* startup template */ + char app_template[64]; + struct ListBase themes; struct ListBase uifonts; struct ListBase uistyles; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index f9aaec69ce7..a1af3f98274 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -767,6 +767,8 @@ void RNA_struct_blender_type_set(StructRNA *srna, void *blender_type); struct IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create); bool RNA_struct_idprops_check(StructRNA *srna); bool RNA_struct_idprops_register_check(const StructRNA *type); +bool RNA_struct_idprops_datablock_allowed(const StructRNA *type); +bool RNA_struct_idprops_contains_datablock(const StructRNA *type); bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier); PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier); diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index 2a680b6eaeb..6e62313b00a 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -167,6 +167,7 @@ void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable); void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable); void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func); +void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func); void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getlength); void RNA_def_property_boolean_funcs(PropertyRNA *prop, const char *get, const char *set); diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index dee8df7d933..cd04f9e8a6d 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -434,6 +434,8 @@ typedef enum StructFlag { STRUCT_GENERATED = (1 << 4), STRUCT_FREE_POINTERS = (1 << 5), 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 */ } StructFlag; typedef int (*StructValidateFunc)(struct PointerRNA *ptr, void *data, int *have_function); diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 4552c773097..9d68c05dda0 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -507,7 +507,7 @@ static void rna_float_print(FILE *f, float num) { if (num == -FLT_MAX) fprintf(f, "-FLT_MAX"); else if (num == FLT_MAX) fprintf(f, "FLT_MAX"); - else if ((int64_t)num == num) fprintf(f, "%.1ff", num); + else if ((ABS(num) < INT64_MAX) && ((int64_t)num == num)) fprintf(f, "%.1ff", num); else fprintf(f, "%.10ff", num); } diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 671902c5cc7..6ed2c55138c 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -802,7 +802,11 @@ static void rna_def_ID_properties(BlenderRNA *brna) RNA_def_struct_name_property(srna, prop); #endif - /* IDP_ID -- not implemented yet in id properties */ + /* IDP_ID */ + prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY | PROP_NEVER_UNLINK); + RNA_def_property_struct_type(prop, "ID"); + /* ID property groups > level 0, since level 0 group is merged * with native RNA properties. the builtin_properties will take diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index bb839fd77f8..c3d2d92fc5e 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -50,6 +50,7 @@ #include "BKE_idcode.h" #include "BKE_idprop.h" #include "BKE_fcurve.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_report.h" @@ -380,6 +381,7 @@ static bool rna_idproperty_verify_valid(PointerRNA *ptr, PropertyRNA *prop, IDPr return false; break; case IDP_GROUP: + case IDP_ID: if (prop->type != PROP_POINTER) return false; break; @@ -395,7 +397,8 @@ static PropertyRNA *typemap[IDP_NUMTYPES] = { (PropertyRNA *)&rna_PropertyGroupItem_int, (PropertyRNA *)&rna_PropertyGroupItem_float, NULL, NULL, NULL, - (PropertyRNA *)&rna_PropertyGroupItem_group, NULL, + (PropertyRNA *)&rna_PropertyGroupItem_group, + (PropertyRNA *)&rna_PropertyGroupItem_id, (PropertyRNA *)&rna_PropertyGroupItem_double, (PropertyRNA *)&rna_PropertyGroupItem_idp_array }; @@ -587,6 +590,21 @@ bool RNA_struct_idprops_register_check(const StructRNA *type) return (type->flag & STRUCT_NO_IDPROPERTIES) == 0; } +bool RNA_struct_idprops_datablock_allowed(const StructRNA *type) +{ + return (type->flag & (STRUCT_NO_DATABLOCK_IDPROPERTIES | STRUCT_NO_IDPROPERTIES)) == 0; +} + +/** + * Whether given type implies datablock usage by IDProperties. + * This is used to prevent classes allowed to have IDProperties, but not datablock ones, to indirectly use some + * (e.g. by assigning an IDP_GROUP containing some IDP_ID pointers...). + */ +bool RNA_struct_idprops_contains_datablock(const StructRNA *type) +{ + return (type->flag & (STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES | STRUCT_ID)) != 0; +} + /* remove an id-property */ bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier) { @@ -628,8 +646,11 @@ PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier) /* id prop lookup, not so common */ PropertyRNA *r_prop = NULL; PointerRNA r_ptr; /* only support single level props */ - if (RNA_path_resolve(ptr, identifier, &r_ptr, &r_prop) && (r_ptr.type == ptr->type) && (r_ptr.data == ptr->data)) + if (RNA_path_resolve_property(ptr, identifier, &r_ptr, &r_prop) && + (r_ptr.type == ptr->type) && (r_ptr.data == ptr->data)) + { return r_prop; + } } else { /* most common case */ @@ -1201,13 +1222,20 @@ int RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *va if (prop->type == PROP_POINTER) { PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop; - if (pprop->poll) - return pprop->poll(ptr, *value); + + if (pprop->poll) { + if (rna_idproperty_check(&prop, ptr)) { + return ((PropPointerPollFuncPy) pprop->poll)(ptr, *value, prop); + } + else { + return pprop->poll(ptr, *value); + } + } return 1; } - printf("%s %s: is not a pointer property.\n", __func__, prop->identifier); + printf("%s: %s is not a pointer property.\n", __func__, prop->identifier); return 0; } @@ -2967,6 +2995,10 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop) if ((idprop = rna_idproperty_check(&prop, ptr))) { pprop = (PointerPropertyRNA *)prop; + if (RNA_struct_is_ID(pprop->type)) { + return rna_pointer_inherit_refine(ptr, pprop->type, IDP_Id(idprop)); + } + /* for groups, data is idprop itself */ if (pprop->typef) return rna_pointer_inherit_refine(ptr, pprop->typef(ptr), idprop); @@ -2989,22 +3021,32 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop) void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value) { - /*IDProperty *idprop;*/ - + PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop; BLI_assert(RNA_property_type(prop) == PROP_POINTER); - if ((/*idprop = */ rna_idproperty_check(&prop, ptr))) { - /* not supported */ - /* rna_idproperty_touch(idprop); */ + /* Check types */ + if (ptr_value.type != NULL && !RNA_struct_is_a(ptr_value.type, pprop->type)) { + printf("%s: expected %s type, not %s.\n", __func__, pprop->type->identifier, ptr_value.type->identifier); + return; } - else { - PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop; - if (pprop->set && - !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) && - !((prop->flag & PROP_ID_SELF_CHECK) && ptr->id.data == ptr_value.id.data)) - { - pprop->set(ptr, ptr_value); + /* RNA */ + if (pprop->set && + !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) && + !((prop->flag & PROP_ID_SELF_CHECK) && ptr->id.data == ptr_value.id.data)) + { + pprop->set(ptr, ptr_value); + } + /* IDProperty */ + else if (prop->flag & PROP_EDITABLE) { + IDPropertyTemplate val = {0}; + IDProperty *group; + + val.id = ptr_value.data; + + group = RNA_struct_idprops(ptr, true); + if (group) { + IDP_ReplaceInGroup(group, IDP_New(IDP_ID, &val, prop->identifier)); } } } @@ -5547,6 +5589,9 @@ static char *rna_pointer_as_string__bldata(PointerRNA *ptr) return BLI_strdup("None"); } else if (RNA_struct_is_ID(ptr->type)) { + if (ptr->id.data == NULL) { + return BLI_strdup("None"); + } return RNA_path_full_ID_py(ptr->id.data); } else { @@ -5556,7 +5601,10 @@ static char *rna_pointer_as_string__bldata(PointerRNA *ptr) char *RNA_pointer_as_string(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *prop_ptr, PointerRNA *ptr_prop) { - if (RNA_property_flag(prop_ptr) & PROP_IDPROPERTY) { + if (ptr_prop->data == NULL) { + return BLI_strdup("None"); + } + else if (RNA_property_flag(prop_ptr) & PROP_IDPROPERTY) { return RNA_pointer_as_string_id(C, ptr_prop); } else { diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 0c4c7ddac81..d398ce95a52 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -34,6 +34,8 @@ #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "BKE_action.h" #include "RNA_access.h" @@ -731,6 +733,7 @@ static void rna_def_action(BlenderRNA *brna) RNA_def_property_ui_text(prop, "ID Root Type", "Type of ID block that action can be used on - " "DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); /* API calls */ RNA_api_action(srna); diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index 9adbf5f6b2e..f271bccd326 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -32,6 +32,8 @@ #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "MEM_guardedalloc.h" #include "RNA_access.h" @@ -742,6 +744,7 @@ static void rna_def_keyingset_path(BlenderRNA *brna) RNA_def_property_enum_default(prop, ID_OB); RNA_def_property_enum_funcs(prop, NULL, "rna_ksPath_id_type_set", NULL); RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); RNA_def_property_update(prop, NC_SCENE | ND_KEYINGSET | NA_EDITED, NULL); /* XXX: maybe a bit too noisy */ /* Group */ diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 1d232d2df39..49983b0bc2b 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -2168,6 +2168,16 @@ void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func) prop->update = (void *)func; } +void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func) +{ + if (prop->type == PROP_POINTER) { + ((PointerPropertyRNA *)prop)->poll = func; + } + else { + fprintf(stderr, "%s: %s is not a Pointer Property.\n", __func__, prop->identifier); + } +} + void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getlength) { if (!DefRNA.preprocess) { @@ -2982,6 +2992,9 @@ PropertyRNA *RNA_def_pointer_runtime(StructOrFunctionRNA *cont_, const char *ide prop = RNA_def_property(cont, identifier, PROP_POINTER, PROP_NONE); RNA_def_property_struct_runtime(prop, type); + if ((type->flag & STRUCT_ID) != 0) { + prop->flag |= PROP_EDITABLE; + } RNA_def_property_ui_text(prop, ui_name, ui_description); return prop; diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 4acdee490b8..bccc47aa95d 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -35,6 +35,8 @@ #include "BLI_math.h" +#include "BLT_translation.h" + #include "BKE_action.h" #include "RNA_access.h" @@ -1448,6 +1450,7 @@ static void rna_def_drivertarget(BlenderRNA *brna) RNA_def_property_enum_funcs(prop, NULL, "rna_DriverTarget_id_type_set", NULL); RNA_def_property_editable_func(prop, "rna_DriverTarget_id_type_editable"); RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data"); /* Target Properties - Property to Drive */ diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 76455adbc78..dfd5af788f6 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -344,6 +344,7 @@ extern IntPropertyRNA rna_PropertyGroupItem_int_array; extern FloatPropertyRNA rna_PropertyGroupItem_float; extern FloatPropertyRNA rna_PropertyGroupItem_float_array; extern PointerPropertyRNA rna_PropertyGroupItem_group; +extern PointerPropertyRNA rna_PropertyGroupItem_id; extern CollectionPropertyRNA rna_PropertyGroupItem_collection; extern CollectionPropertyRNA rna_PropertyGroupItem_idp_array; extern FloatPropertyRNA rna_PropertyGroupItem_double; diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index fce81e6967e..df591659fdb 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -94,6 +94,7 @@ typedef PointerRNA (*PropPointerGetFunc)(struct PointerRNA *ptr); typedef StructRNA *(*PropPointerTypeFunc)(struct PointerRNA *ptr); typedef void (*PropPointerSetFunc)(struct PointerRNA *ptr, const PointerRNA value); typedef int (*PropPointerPollFunc)(struct PointerRNA *ptr, const PointerRNA value); +typedef int (*PropPointerPollFuncPy)(struct PointerRNA *ptr, const PointerRNA value, const PropertyRNA *prop); typedef void (*PropCollectionBeginFunc)(struct CollectionPropertyIterator *iter, struct PointerRNA *ptr); typedef void (*PropCollectionNextFunc)(struct CollectionPropertyIterator *iter); typedef void (*PropCollectionEndFunc)(struct CollectionPropertyIterator *iter); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 36cf909b299..1a8dd05a7b5 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1526,6 +1526,20 @@ static void rna_def_modifier_mirror(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Mirror V", "Mirror the V texture coordinate around the 0.5 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_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_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "tolerance"); RNA_def_property_range(prop, 0, FLT_MAX); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 784004182dd..8d42d746e1c 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3327,6 +3327,7 @@ static void def_frame(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeFrame", "storage"); + RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_ID_NODETREE); prop = RNA_def_property(srna, "shrink", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_FRAME_SHRINK); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index b3c166a6810..ec6a03e713d 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2897,6 +2897,10 @@ static void rna_def_dupli_object(BlenderRNA *brna) RNA_def_property_enum_items(prop, dupli_items); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); RNA_def_property_ui_text(prop, "Dupli Type", "Duplicator type that generated this dupli object"); + + prop = RNA_def_property(srna, "random_id", PROP_INT, PROP_UNSIGNED); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Dupli random id", "Random id for this dupli object"); } static void rna_def_object_base(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index c680abe71a4..55852139065 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -321,13 +321,30 @@ static void rna_Object_ray_cast( float origin[3], float direction[3], float distance, int *r_success, float r_location[3], float r_normal[3], int *r_index) { - BVHTreeFromMesh treeData = {NULL}; - if (ob->derivedFinal == NULL) { BKE_reportf(reports, RPT_ERROR, "Object '%s' has no mesh data to be used for ray casting", ob->id.name + 2); return; } + *r_success = false; + + /* Test BoundBox first (efficiency) */ + BoundBox *bb = BKE_object_boundbox_get(ob); + if (bb) { + float distmin, distmax; + if (isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, &distmax)) { + float dist = distmin >= 0 ? distmin : distmax; + if (dist > distance) { + goto finally; + } + } + else { + goto finally; + } + } + + BVHTreeFromMesh treeData = {NULL}; + /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */ bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6); @@ -350,20 +367,18 @@ static void rna_Object_ray_cast( copy_v3_v3(r_location, hit.co); copy_v3_v3(r_normal, hit.no); *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]); - - goto finally; } } - } - - *r_success = false; - zero_v3(r_location); - zero_v3(r_normal); - *r_index = -1; + free_bvhtree_from_mesh(&treeData); + } + if (*r_success == false) { finally: - free_bvhtree_from_mesh(&treeData); + zero_v3(r_location); + zero_v3(r_normal); + *r_index = -1; + } } static void rna_Object_closest_point_on_mesh( diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index d4d8e23fdf5..9b202120b82 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -284,32 +284,36 @@ static void rna_Scene_collada_export( int use_blender_profile, int sort_by_name, int export_transformation_type, - int open_sim) + int open_sim, + int limit_precision, + int keep_bind_info) { - collada_export(scene, - 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, - - triangulate, - use_object_instantiation, - use_blender_profile, - sort_by_name, - - export_transformation_type, - open_sim); + collada_export(scene, + 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, + + triangulate, + use_object_instantiation, + use_blender_profile, + sort_by_name, + + export_transformation_type, + open_sim, + limit_precision, + keep_bind_info); } #endif @@ -374,59 +378,60 @@ void RNA_api_scene(StructRNA *srna) RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */ - RNA_def_boolean(func, - "apply_modifiers", 0, "Apply Modifiers", - "Apply modifiers to exported mesh (non destructive))"); + RNA_def_boolean(func, "apply_modifiers", false, + "Apply Modifiers", "Apply modifiers to exported mesh (non destructive))"); RNA_def_int(func, "export_mesh_type", 0, INT_MIN, INT_MAX, - "Resolution", "Modifier resolution for export", INT_MIN, INT_MAX); + "Resolution", "Modifier resolution for export", INT_MIN, INT_MAX); - RNA_def_boolean(func, "selected", 0, "Selection Only", - "Export only selected elements"); + RNA_def_boolean(func, "selected", false, "Selection Only", "Export only selected elements"); - RNA_def_boolean(func, "include_children", 0, "Include Children", - "Export all children of selected objects (even if not selected)"); + RNA_def_boolean(func, "include_children", false, + "Include Children", "Export all children of selected objects (even if not selected)"); - RNA_def_boolean(func, "include_armatures", 0, "Include Armatures", - "Export related armatures (even if not selected)"); + RNA_def_boolean(func, "include_armatures", false, + "Include Armatures", "Export related armatures (even if not selected)"); - RNA_def_boolean(func, "include_shapekeys", 1, "Include Shape Keys", - "Export all Shape Keys from Mesh Objects"); + RNA_def_boolean(func, "include_shapekeys", true, "Include Shape Keys", "Export all Shape Keys from Mesh Objects"); - RNA_def_boolean(func, "deform_bones_only", 0, "Deform Bones only", - "Only export deforming bones with armatures"); + RNA_def_boolean(func, "deform_bones_only", false, + "Deform Bones only", "Only export deforming bones with armatures"); + RNA_def_boolean(func, "active_uv_only", false, "Only Selected UV Map", "Export only the selected UV Map"); - RNA_def_boolean(func, "active_uv_only", 0, "Only Selected UV Map", - "Export only the selected UV Map"); + RNA_def_boolean(func, "include_uv_textures", false, + "Include UV Textures", "Export textures assigned to the object UV Maps"); - RNA_def_boolean(func, "include_uv_textures", 0, "Include UV Textures", - "Export textures assigned to the object UV Maps"); + RNA_def_boolean(func, "include_material_textures", false, + "Include Material Textures", "Export textures assigned to the object Materials"); - RNA_def_boolean(func, "include_material_textures", 0, "Include Material Textures", - "Export textures assigned to the object Materials"); + RNA_def_boolean(func, "use_texture_copies", true, + "Copy", "Copy textures to same folder where the .dae file is exported"); - RNA_def_boolean(func, "use_texture_copies", 1, "Copy", - "Copy textures to same folder where the .dae file is exported"); + RNA_def_boolean(func, "triangulate", true, "Triangulate", "Export Polygons (Quads & NGons) as Triangles"); + RNA_def_boolean(func, "use_object_instantiation", true, + "Use Object Instances", "Instantiate multiple Objects from same Data"); - RNA_def_boolean(func, "triangulate", 1, "Triangulate", - "Export Polygons (Quads & NGons) as Triangles"); + RNA_def_boolean(func, "use_blender_profile", true, "Use Blender Profile", + "Export additional Blender specific information (for material, shaders, bones, etc.)"); - RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances", - "Instantiate multiple Objects from same Data"); + RNA_def_boolean(func, "sort_by_name", false, "Sort by Object name", "Sort exported data by Object name"); - RNA_def_boolean(func, "use_blender_profile", 1, "Use Blender Profile", - "Export additional Blender specific information (for material, shaders, bones, etc.)"); + RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX, + "Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX); - RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name", - "Sort exported data by Object name"); + RNA_def_boolean(func, "open_sim", false, + "Export to SL/OpenSim", "Compatibility mode for SL, OpenSim and other compatible online worlds"); - RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX, - "Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX); + RNA_def_boolean(func, "limit_precision", false, + "Limit Precision", + "Reduce the precision of the exported data to 6 digits"); + + RNA_def_boolean(func, "keep_bind_info", false, + "Keep Bind Info", + "Store bind pose information in custom bone properties for later use during Collada export"); - RNA_def_boolean(func, "open_sim", 0, "Export to SL/OpenSim", - "Compatibility mode for SL, OpenSim and other compatible online worlds"); #endif #ifdef WITH_ALEMBIC diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 7a3c862f04c..54b82fc89d6 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -1039,6 +1039,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); /* Registration */ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 6927abcb4f8..629a42e92bd 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -138,23 +138,11 @@ static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe } /* also used by buffer swap switching */ -static void rna_userdef_dpi_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +static void rna_userdef_dpi_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { /* font's are stored at each DPI level, without this we can easy load 100's of fonts */ BLF_cache_clear(); - BKE_blender_userdef_refresh(); - WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */ - WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */ -} - -static void rna_userdef_virtual_pixel_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) -{ - /* font's are stored at each DPI level, without this we can easy load 100's of fonts */ - BLF_cache_clear(); - - BKE_blender_userdef_refresh(); - /* force setting drawable again */ wmWindowManager *wm = bmain->wm.first; if (wm) { @@ -3180,6 +3168,7 @@ static void rna_def_userdef_addon_pref(BlenderRNA *brna) RNA_def_struct_refine_func(srna, "rna_AddonPref_refine"); RNA_def_struct_register_funcs(srna, "rna_AddonPref_register", "rna_AddonPref_unregister", NULL); RNA_def_struct_idprops_func(srna, "rna_AddonPref_idprops"); + RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); /* Mandatory! */ /* registration */ RNA_define_verify_sdna(0); @@ -3337,6 +3326,12 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "View & Controls", "Preferences related to viewing data"); /* View */ + prop = RNA_def_property(srna, "ui_scale", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_ui_text(prop, "UI Scale", "Changes the size of the fonts and buttons in the interface"); + RNA_def_property_range(prop, 0.25f, 4.0f); + RNA_def_property_ui_range(prop, 0.5f, 2.0f, 1, 1); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); /* display */ prop = RNA_def_property(srna, "show_tooltips", PROP_BOOLEAN, PROP_NONE); @@ -3928,12 +3923,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; - static EnumPropertyItem virtual_pixel_mode_items[] = { - {VIRTUAL_PIXEL_NATIVE, "NATIVE", 0, "Native", "Use native pixel size of the display"}, - {VIRTUAL_PIXEL_DOUBLE, "DOUBLE", 0, "Double", "Use double the native pixel size of the display"}, - {0, NULL, 0, NULL, NULL} - }; - srna = RNA_def_struct(brna, "UserPreferencesSystem", NULL); RNA_def_struct_sdna(srna, "UserDef"); RNA_def_struct_nested(brna, srna, "UserPreferences"); @@ -3948,16 +3937,8 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update"); prop = RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "dpi"); - RNA_def_property_range(prop, 48, 144); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "DPI", "Font size and resolution for display"); - RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); - - prop = RNA_def_property(srna, "virtual_pixel_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "virtual_pixel"); - RNA_def_property_enum_items(prop, virtual_pixel_mode_items); - RNA_def_property_ui_text(prop, "Virtual Pixel Mode", "Modify the pixel size for hi-res devices"); - RNA_def_property_update(prop, 0, "rna_userdef_virtual_pixel_update"); prop = RNA_def_property(srna, "pixel_size", PROP_FLOAT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -4690,6 +4671,11 @@ void RNA_def_userdef(BlenderRNA *brna) "Active section of the user preferences shown in the user interface"); RNA_def_property_update(prop, 0, "rna_userdef_update"); + /* don't expose this directly via the UI, modify via an operator */ + prop = RNA_def_property(srna, "app_template", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "app_template"); + RNA_def_property_ui_text(prop, "Application Template", ""); + prop = RNA_def_property(srna, "themes", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "themes", NULL); RNA_def_property_struct_type(prop, "Theme"); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 35c9c9bcc89..b458b2e69d5 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -1556,6 +1556,7 @@ static void rna_def_operator(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Operator Properties", "Input properties of an Operator"); RNA_def_struct_refine_func(srna, "rna_OperatorProperties_refine"); RNA_def_struct_idprops_func(srna, "rna_OperatorProperties_idprops"); + RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); } static void rna_def_macro_operator(BlenderRNA *brna) diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index d956763fc1f..f0edcc31a10 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -112,7 +112,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, if (!mcmd->reader) { mcmd->reader = CacheReader_open_alembic_object(cache_file->handle, - mcmd->reader, + NULL, ob, mcmd->object_path); if (!mcmd->reader) { diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index dd127cc255c..9705edc580c 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -274,8 +274,8 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, int j = maxLoops; dmloopuv += j; /* second set of loops only */ for (; j-- > 0; dmloopuv++) { - if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0]; - if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1]; + 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]; } } } diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index 776cf02754e..da9b926d1f4 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -1120,6 +1120,11 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un tdm = smd->target->derivedFinal; } + if (!tdm) { + modifier_setError(md, "No valid target mesh"); + return; + } + tnumverts = tdm->getNumVerts(tdm); tnumpoly = tdm->getNumPolys(tdm); @@ -1139,12 +1144,10 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un /* Poly count checks */ if (smd->numverts != numverts) { modifier_setError(md, "Verts changed from %u to %u", smd->numverts, numverts); - tdm->release(tdm); return; } else if (smd->numpoly != tnumpoly) { modifier_setError(md, "Target polygons changed from %u to %u", smd->numpoly, tnumpoly); - tdm->release(tdm); return; } @@ -1170,8 +1173,6 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un MEM_freeN(data.targetCos); } - - tdm->release(tdm); } static void deformVerts(ModifierData *md, Object *ob, diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c index 48d1688c386..e0bf34f42e4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c @@ -63,7 +63,7 @@ static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *n CLAMP_MIN(strength, 0.0f); - float *N = shi->vno; + float *N = shi->nmapnorm; int uv_index = 0; switch (nm->space) { case SHD_NORMAL_MAP_TANGENT: diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.c index d1905246fd4..165d565a5b4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_object_info.c +++ b/source/blender/nodes/shader/nodes/node_shader_object_info.c @@ -39,7 +39,16 @@ static bNodeSocketTemplate sh_node_object_info_out[] = { static int node_shader_gpu_object_info(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { - return GPU_stack_link(mat, "node_object_info", in, out); + return GPU_stack_link(mat, "node_object_info", in, out, GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_OBJECT_INFO)); +} + +static void node_shader_exec_object_info(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out) +{ + ShaderCallData *scd = (ShaderCallData *)data; + copy_v4_v4(out[0]->vec, RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB)[3]); + out[1]->vec[0] = RE_object_instance_get_object_pass_index(scd->shi->obi); + out[2]->vec[0] = scd->shi->mat->index; + out[3]->vec[0] = RE_object_instance_get_random_id(scd->shi->obi) * (1.0f/(float)0xFFFFFFFF);; } /* node type definition */ @@ -53,6 +62,7 @@ void register_node_type_sh_object_info(void) node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_object_info); + node_type_exec(&ntype, NULL, NULL, node_shader_exec_object_info); nodeRegisterType(&ntype); } diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp index 359395b63c4..b694b6e994d 100644 --- a/source/blender/physics/intern/BPH_mass_spring.cpp +++ b/source/blender/physics/intern/BPH_mass_spring.cpp @@ -333,19 +333,14 @@ static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothMo return 1; } -BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, float time) +BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) { Cloth *cloth = clmd->clothObject; ClothSimSettings *parms = clmd->sim_parms; Implicit_Data *data = cloth->implicit; - ClothVertex *verts = cloth->verts; bool no_compress = parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS; - zero_v3(s->f); - zero_m3(s->dfdx); - zero_m3(s->dfdv); - s->flags &= ~CLOTH_SPRING_FLAG_NEEDED; // calculate force of structural + shear springs @@ -361,31 +356,13 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, if (s->type & CLOTH_SPRING_TYPE_SEWING) { // TODO: verify, half verified (couldn't see error) // sewing springs usually have a large distance at first so clamp the force so we don't get tunnelling through colission objects - BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing, s->f, s->dfdx, s->dfdv); + BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing); } else { - BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f, s->f, s->dfdx, s->dfdv); + BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f); } #endif } - else if (s->type & CLOTH_SPRING_TYPE_GOAL) { -#ifdef CLOTH_FORCE_SPRING_GOAL - float goal_x[3], goal_v[3]; - float k, scaling; - - s->flags |= CLOTH_SPRING_FLAG_NEEDED; - - // current_position = xold + t * (newposition - xold) - /* divide by time_scale to prevent goal vertices' delta locations from being multiplied */ - interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time / parms->time_scale); - sub_v3_v3v3(goal_v, verts[s->ij].xconst, verts[s->ij].xold); // distance covered over dt==1 - - scaling = parms->goalspring + s->stiffness * fabsf(parms->max_struct - parms->goalspring); - k = verts[s->ij].goal * scaling / (parms->avg_spring_len + FLT_EPSILON); - - BPH_mass_spring_force_spring_goal(data, s->ij, goal_x, goal_v, k, parms->goalfrict * 0.01f, s->f, s->dfdx, s->dfdv); -#endif - } else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */ #ifdef CLOTH_FORCE_SPRING_BEND float kb, cb, scaling; @@ -398,7 +375,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, // Fix for [#45084] for cloth stiffness must have cb proportional to kb cb = kb * parms->bending_damping; - BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv); + BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb); #endif } else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) { @@ -474,9 +451,24 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB /* scale gravity force */ mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity); } + vert = cloth->verts; for (i = 0; i < cloth->mvert_num; i++, vert++) { BPH_mass_spring_force_gravity(data, i, vert->mass, gravity); + + /* Vertex goal springs */ + if ((!(vert->flags & CLOTH_VERT_FLAG_PINNED)) && (vert->goal > FLT_EPSILON)) { + float goal_x[3], goal_v[3]; + float k; + + /* divide by time_scale to prevent goal vertices' delta locations from being multiplied */ + interp_v3_v3v3(goal_x, vert->xold, vert->xconst, time / clmd->sim_parms->time_scale); + sub_v3_v3v3(goal_v, vert->xconst, vert->xold); /* distance covered over dt==1 */ + + k = vert->goal * clmd->sim_parms->goalspring / (clmd->sim_parms->avg_spring_len + FLT_EPSILON); + + BPH_mass_spring_force_spring_goal(data, i, goal_x, goal_v, k, clmd->sim_parms->goalfrict * 0.01f); + } } #endif @@ -544,8 +536,9 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB for (LinkNode *link = cloth->springs; link; link = link->next) { ClothSpring *spring = (ClothSpring *)link->link; // only handle active springs - if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE)) - cloth_calc_spring_force(clmd, spring, time); + if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE)) { + cloth_calc_spring_force(clmd, spring); + } } } diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h index d1a75ca5297..2f62ab98e12 100644 --- a/source/blender/physics/intern/implicit.h +++ b/source/blender/physics/intern/implicit.h @@ -114,19 +114,15 @@ void BPH_mass_spring_force_edge_wind(struct Implicit_Data *data, int v1, int v2, void BPH_mass_spring_force_vertex_wind(struct Implicit_Data *data, int v, float radius, const float (*winvec)[3]); /* Linear spring force between two points */ bool BPH_mass_spring_force_spring_linear(struct Implicit_Data *data, int i, int j, float restlen, - float stiffness, float damping, bool no_compress, float clamp_force, - float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]); + float stiffness, float damping, bool no_compress, float clamp_force); /* Bending force, forming a triangle at the base of two structural springs */ -bool BPH_mass_spring_force_spring_bending(struct Implicit_Data *data, int i, int j, float restlen, - float kb, float cb, - float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]); +bool BPH_mass_spring_force_spring_bending(struct Implicit_Data *data, int i, int j, float restlen, float kb, float cb); /* Angular bending force based on local target vectors */ bool BPH_mass_spring_force_spring_bending_angular(struct Implicit_Data *data, int i, int j, int k, const float target[3], float stiffness, float damping); /* Global goal spring */ bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3], - float stiffness, float damping, - float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]); + float stiffness, float damping); /* ======== Hair Volumetric Forces ======== */ diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c index 2ad8ee0547f..16cd335dc0c 100644 --- a/source/blender/physics/intern/implicit_blender.c +++ b/source/blender/physics/intern/implicit_blender.c @@ -1579,8 +1579,7 @@ BLI_INLINE void apply_spring(Implicit_Data *data, int i, int j, const float f[3] } bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, float restlen, - float stiffness, float damping, bool no_compress, float clamp_force, - float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]) + float stiffness, float damping, bool no_compress, float clamp_force) { float extent[3], length, dir[3], vel[3]; @@ -1608,25 +1607,15 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa apply_spring(data, i, j, f, dfdx, dfdv); - if (r_f) copy_v3_v3(r_f, f); - if (r_dfdx) copy_m3_m3(r_dfdx, dfdx); - if (r_dfdv) copy_m3_m3(r_dfdv, dfdv); - return true; } else { - if (r_f) zero_v3(r_f); - if (r_dfdx) zero_m3(r_dfdx); - if (r_dfdv) zero_m3(r_dfdv); - return false; } } /* See "Stable but Responsive Cloth" (Choi, Ko 2005) */ -bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen, - float kb, float cb, - float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]) +bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen, float kb, float cb) { float extent[3], length, dir[3], vel[3]; @@ -1646,17 +1635,9 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, flo apply_spring(data, i, j, f, dfdx, dfdv); - if (r_f) copy_v3_v3(r_f, f); - if (r_dfdx) copy_m3_m3(r_dfdx, dfdx); - if (r_dfdv) copy_m3_m3(r_dfdv, dfdv); - return true; } else { - if (r_f) zero_v3(r_f); - if (r_dfdx) zero_m3(r_dfdx); - if (r_dfdv) zero_m3(r_dfdv); - return false; } } @@ -1945,8 +1926,7 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in } bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3], - float stiffness, float damping, - float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]) + float stiffness, float damping) { float root_goal_x[3], root_goal_v[3], extent[3], length, dir[3], vel[3]; float f[3], dfdx[3][3], dfdv[3][3]; @@ -1973,17 +1953,9 @@ bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float g add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfdx); add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, dfdv); - if (r_f) copy_v3_v3(r_f, f); - if (r_dfdx) copy_m3_m3(r_dfdx, dfdx); - if (r_dfdv) copy_m3_m3(r_dfdv, dfdv); - return true; } else { - if (r_f) zero_v3(r_f); - if (r_dfdx) zero_m3(r_dfdx); - if (r_dfdv) zero_m3(r_dfdv); - return false; } } diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index 2e15b7b1413..5d6a7c578a2 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -43,6 +43,9 @@ #include "python_utildefines.h" +extern bool pyrna_id_FromPyObject(PyObject *obj, ID **id); +extern PyObject *pyrna_id_CreatePyObject(ID *id); +extern bool pyrna_id_CheckPyObject(PyObject *obj); /*********************** ID Property Main Wrapper Stuff ***************/ @@ -88,6 +91,11 @@ static PyObject *idprop_py_from_idp_group(ID *id, IDProperty *prop, IDProperty * return (PyObject *)group; } +static PyObject *idprop_py_from_idp_id(IDProperty *prop) +{ + return pyrna_id_CreatePyObject(prop->data.pointer); +} + static PyObject *idprop_py_from_idp_array(ID *id, IDProperty *prop) { BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &BPy_IDArray_Type); @@ -148,6 +156,7 @@ PyObject *BPy_IDGroup_WrapData(ID *id, IDProperty *prop, IDProperty *parent) case IDP_GROUP: return idprop_py_from_idp_group(id, prop, parent); case IDP_ARRAY: return idprop_py_from_idp_array(id, prop); case IDP_IDPARRAY: return idprop_py_from_idp_idparray(id, prop); /* this could be better a internal type */ + case IDP_ID: return idprop_py_from_idp_id(prop); default: Py_RETURN_NONE; } } @@ -335,19 +344,9 @@ static char idp_sequence_type(PyObject *seq_fast) return type; } -/** - * \note group can be a pointer array or a group. - * assume we already checked key is a string. - * - * \return success. - */ -bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob) +static const char *idp_try_read_name(PyObject *name_obj) { - IDProperty *prop = NULL; - IDPropertyTemplate val = {0}; - - const char *name; - + const char *name = NULL; if (name_obj) { Py_ssize_t name_size; name = _PyUnicode_AsStringAndSize(name_obj, &name_size); @@ -356,168 +355,307 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyErr_Format(PyExc_KeyError, "invalid id-property key, expected a string, not a %.200s", Py_TYPE(name_obj)->tp_name); - return false; + return NULL; } if (name_size > MAX_IDPROP_NAME) { PyErr_SetString(PyExc_KeyError, "the length of IDProperty names is limited to 63 characters"); - return false; + return NULL; } } else { name = ""; } + return name; +} - if (PyFloat_Check(ob)) { - val.d = PyFloat_AsDouble(ob); - prop = IDP_New(IDP_DOUBLE, &val, name); - } - else if (PyLong_Check(ob)) { - val.i = _PyLong_AsInt(ob); - if (val.i == -1 && PyErr_Occurred()) { - return false; - } - prop = IDP_New(IDP_INT, &val, name); +/* -------------------------------------------------------------------------- */ + +/** + * The 'idp_from_Py*' functions expect that the input type has been checked before + * and return NULL if the IDProperty can't be created. + */ + +static IDProperty *idp_from_PyFloat(const char *name, PyObject *ob) +{ + IDPropertyTemplate val = {0}; + val.d = PyFloat_AsDouble(ob); + return IDP_New(IDP_DOUBLE, &val, name); +} + +static IDProperty *idp_from_PyLong(const char *name, PyObject *ob) +{ + IDPropertyTemplate val = {0}; + val.i = _PyLong_AsInt(ob); + if (val.i == -1 && PyErr_Occurred()) { + return NULL; } - else if (PyUnicode_Check(ob)) { + return IDP_New(IDP_INT, &val, name); +} + +static IDProperty *idp_from_PyUnicode(const char *name, PyObject *ob) +{ + IDProperty *prop; + IDPropertyTemplate val = {0}; #ifdef USE_STRING_COERCE - Py_ssize_t value_size; - PyObject *value_coerce = NULL; - val.string.str = PyC_UnicodeAsByteAndSize(ob, &value_size, &value_coerce); - val.string.len = (int)value_size + 1; - val.string.subtype = IDP_STRING_SUB_UTF8; - prop = IDP_New(IDP_STRING, &val, name); - Py_XDECREF(value_coerce); + Py_ssize_t value_size; + PyObject *value_coerce = NULL; + val.string.str = PyC_UnicodeAsByteAndSize(ob, &value_size, &value_coerce); + val.string.len = (int)value_size + 1; + val.string.subtype = IDP_STRING_SUB_UTF8; + prop = IDP_New(IDP_STRING, &val, name); + Py_XDECREF(value_coerce); #else - val.str = _PyUnicode_AsString(ob); - prop = IDP_New(IDP_STRING, val, name); + val.str = _PyUnicode_AsString(ob); + prop = IDP_New(IDP_STRING, val, name); #endif - } - else if (PyBytes_Check(ob)) { - val.string.str = PyBytes_AS_STRING(ob); - val.string.len = PyBytes_GET_SIZE(ob); - val.string.subtype = IDP_STRING_SUB_BYTE; + return prop; +} + +static IDProperty *idp_from_PyBytes(const char *name, PyObject *ob) +{ + IDPropertyTemplate val = {0}; + val.string.str = PyBytes_AS_STRING(ob); + val.string.len = PyBytes_GET_SIZE(ob); + val.string.subtype = IDP_STRING_SUB_BYTE; + return IDP_New(IDP_STRING, &val, name); +} - prop = IDP_New(IDP_STRING, &val, name); - //prop = IDP_NewString(PyBytes_AS_STRING(ob), name, PyBytes_GET_SIZE(ob)); - //prop->subtype = IDP_STRING_SUB_BYTE; +static int idp_array_type_from_format_char(char format) +{ + if (format == 'i') return IDP_INT; + if (format == 'f') return IDP_FLOAT; + if (format == 'd') return IDP_DOUBLE; + return -1; +} + +static const char *idp_format_from_array_type(int type) +{ + if (type == IDP_INT) return "i"; + if (type == IDP_FLOAT) return "f"; + if (type == IDP_DOUBLE) return "d"; + return NULL; +} + +static IDProperty *idp_from_PySequence_Buffer(const char *name, Py_buffer *buffer) +{ + IDProperty *prop; + IDPropertyTemplate val = {0}; + + int format = idp_array_type_from_format_char(*buffer->format); + if (format == -1) { + /* should never happen as the type has been checked before */ + return NULL; } - else if (PySequence_Check(ob)) { - PyObject *ob_seq_fast; - PyObject **ob_seq_fast_items; - PyObject *item; - int i; + else { + val.array.type = format; + val.array.len = buffer->len / buffer->itemsize; + } + prop = IDP_New(IDP_ARRAY, &val, name); + memcpy(IDP_Array(prop), buffer->buf, buffer->len); + return prop; +} - if (!(ob_seq_fast = PySequence_Fast(ob, "py -> idprop"))) { - return false; - } +static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob) +{ + IDProperty *prop; + IDPropertyTemplate val = {0}; - ob_seq_fast_items = PySequence_Fast_ITEMS(ob_seq_fast); + PyObject **ob_seq_fast_items; + PyObject *item; + int i; - if ((val.array.type = idp_sequence_type(ob_seq_fast)) == (char)-1) { - Py_DECREF(ob_seq_fast); - PyErr_SetString(PyExc_TypeError, "only floats, ints and dicts are allowed in ID property arrays"); - return false; - } + ob_seq_fast_items = PySequence_Fast_ITEMS(ob); - /* validate sequence and derive type. - * we assume IDP_INT unless we hit a float - * number; then we assume it's */ + if ((val.array.type = idp_sequence_type(ob)) == (char)-1) { + PyErr_SetString(PyExc_TypeError, "only floats, ints and dicts are allowed in ID property arrays"); + return NULL; + } - val.array.len = PySequence_Fast_GET_SIZE(ob_seq_fast); + /* validate sequence and derive type. + * we assume IDP_INT unless we hit a float + * number; then we assume it's */ - switch (val.array.type) { - case IDP_DOUBLE: - { - double *prop_data; - - prop = IDP_New(IDP_ARRAY, &val, name); - prop_data = IDP_Array(prop); - for (i = 0; i < val.array.len; i++) { - item = ob_seq_fast_items[i]; - if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) { - Py_DECREF(ob_seq_fast); - return false; - } + val.array.len = PySequence_Fast_GET_SIZE(ob); + + switch (val.array.type) { + case IDP_DOUBLE: + { + double *prop_data; + prop = IDP_New(IDP_ARRAY, &val, name); + prop_data = IDP_Array(prop); + for (i = 0; i < val.array.len; i++) { + item = ob_seq_fast_items[i]; + if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) { + return NULL; } - break; } - case IDP_INT: - { - int *prop_data; - prop = IDP_New(IDP_ARRAY, &val, name); - 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()) { - Py_DECREF(ob_seq_fast); - return false; - } + break; + } + case IDP_INT: + { + int *prop_data; + prop = IDP_New(IDP_ARRAY, &val, name); + 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()) { + return NULL; } - break; } - case IDP_IDPARRAY: - { - prop = IDP_NewIDPArray(name); - for (i = 0; i < val.array.len; i++) { - item = ob_seq_fast_items[i]; - - if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) { - Py_DECREF(ob_seq_fast); - return false; - } + break; + } + case IDP_IDPARRAY: + { + prop = IDP_NewIDPArray(name); + for (i = 0; i < val.array.len; i++) { + item = ob_seq_fast_items[i]; + if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) { + return NULL; } - break; } - default: - /* should never happen */ - Py_DECREF(ob_seq_fast); - PyErr_SetString(PyExc_RuntimeError, "internal error with idp array.type"); - return false; + break; } + default: + /* should never happen */ + PyErr_SetString(PyExc_RuntimeError, "internal error with idp array.type"); + return NULL; + } + return prop; +} - Py_DECREF(ob_seq_fast); + +static IDProperty *idp_from_PySequence(const char *name, PyObject *ob) +{ + Py_buffer buffer; + bool use_buffer = false; + + if (PyObject_CheckBuffer(ob)) { + PyObject_GetBuffer(ob, &buffer, PyBUF_SIMPLE | PyBUF_FORMAT); + char format = *buffer.format; + if (ELEM(format, 'i', 'f', 'd')) { + use_buffer = true; + } + else { + PyBuffer_Release(&buffer); + } } - else if (PyMapping_Check(ob)) { - PyObject *keys, *vals, *key, *pval; - int i, len; - /*yay! we get into recursive stuff now!*/ - keys = PyMapping_Keys(ob); - vals = PyMapping_Values(ob); - - /* we allocate the group first; if we hit any invalid data, - * we can delete it easily enough.*/ - prop = IDP_New(IDP_GROUP, &val, name); - len = PyMapping_Length(ob); - for (i = 0; i < len; i++) { - key = PySequence_GetItem(keys, i); - pval = PySequence_GetItem(vals, i); - if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) { - IDP_FreeProperty(prop); - MEM_freeN(prop); - Py_XDECREF(keys); - Py_XDECREF(vals); - Py_XDECREF(key); - Py_XDECREF(pval); - /* error is already set */ - return false; - } + + if (use_buffer) { + IDProperty *prop = idp_from_PySequence_Buffer(name, &buffer); + PyBuffer_Release(&buffer); + return prop; + } + else { + PyObject *ob_seq_fast = PySequence_Fast(ob, "py -> idprop"); + if (ob_seq_fast != NULL) { + IDProperty *prop = idp_from_PySequence_Fast(name, ob_seq_fast); + Py_DECREF(ob_seq_fast); + return prop; + } + else { + return NULL; + } + } +} + +static IDProperty *idp_from_PyMapping(const char *name, PyObject *ob) +{ + IDProperty *prop; + IDPropertyTemplate val = {0}; + + PyObject *keys, *vals, *key, *pval; + int i, len; + /* yay! we get into recursive stuff now! */ + keys = PyMapping_Keys(ob); + vals = PyMapping_Values(ob); + + /* we allocate the group first; if we hit any invalid data, + * we can delete it easily enough.*/ + prop = IDP_New(IDP_GROUP, &val, name); + len = PyMapping_Length(ob); + for (i = 0; i < len; i++) { + key = PySequence_GetItem(keys, i); + pval = PySequence_GetItem(vals, i); + if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) { + IDP_FreeProperty(prop); + MEM_freeN(prop); + Py_XDECREF(keys); + Py_XDECREF(vals); Py_XDECREF(key); Py_XDECREF(pval); + /* error is already set */ + return NULL; } - Py_XDECREF(keys); - Py_XDECREF(vals); + Py_XDECREF(key); + Py_XDECREF(pval); + } + Py_XDECREF(keys); + Py_XDECREF(vals); + return prop; +} + +static IDProperty *idp_from_DatablockPointer(const char *name, PyObject *ob, IDPropertyTemplate *val) +{ + pyrna_id_FromPyObject(ob, &val->id); + return IDP_New(IDP_ID, val, name); +} + +static IDProperty *idp_from_PyObject(PyObject *name_obj, PyObject *ob) +{ + IDPropertyTemplate val = {0}; + const char *name = idp_try_read_name(name_obj); + if (name == NULL) { + return NULL; + } + + if (PyFloat_Check(ob)) { + return idp_from_PyFloat(name, ob); + } + else if (PyLong_Check(ob)) { + return idp_from_PyLong(name, ob); + } + else if (PyUnicode_Check(ob)) { + return idp_from_PyUnicode(name, ob); + } + else if (PyBytes_Check(ob)) { + return idp_from_PyBytes(name, ob); + } + else if (PySequence_Check(ob)) { + return idp_from_PySequence(name, ob); + } + else if (ob == Py_None || pyrna_id_CheckPyObject(ob)) { + return idp_from_DatablockPointer(name, ob, &val); + } + else if (PyMapping_Check(ob)) { + return idp_from_PyMapping(name, ob); } else { PyErr_Format(PyExc_TypeError, "invalid id-property type %.200s not supported", Py_TYPE(ob)->tp_name); + return NULL; + } +} + +/* -------------------------------------------------------------------------- */ + +/** + * \note group can be a pointer array or a group. + * assume we already checked key is a string. + * + * \return success. + */ +bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob) +{ + IDProperty *prop = idp_from_PyObject(name_obj, ob); + if (prop == NULL) { return false; } if (group->type == IDP_IDPARRAY) { IDP_AppendArray(group, prop); - // IDP_FreeProperty(item); /* IDP_AppendArray does a shallow copy (memcpy), only free memory */ + /* IDP_AppendArray does a shallow copy (memcpy), only free memory */ MEM_freeN(prop); } else { @@ -613,6 +751,8 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop) return idprop_py_from_idp_float(prop); case IDP_DOUBLE: return idprop_py_from_idp_double(prop); + case IDP_ID: + return idprop_py_from_idp_id(prop); case IDP_ARRAY: { PyObject *seq = PyList_New(prop->len); @@ -1371,6 +1511,44 @@ static PyMappingMethods BPy_IDArray_AsMapping = { (objobjargproc)BPy_IDArray_ass_subscript }; +static int itemsize_by_idarray_type(int array_type) +{ + if (array_type == IDP_INT) return sizeof(int); + if (array_type == IDP_FLOAT) return sizeof(float); + if (array_type == IDP_DOUBLE) return sizeof(double); + return -1; /* should never happen */ +} + +static int BPy_IDArray_getbuffer(BPy_IDArray *self, Py_buffer *view, int flags) +{ + IDProperty *prop = self->prop; + int itemsize = itemsize_by_idarray_type(prop->subtype); + int length = itemsize * prop->len; + + if (PyBuffer_FillInfo(view, (PyObject *)self, IDP_Array(prop), length, false, flags) == -1) { + return -1; + } + + view->itemsize = itemsize; + view->format = (char *)idp_format_from_array_type(prop->subtype); + + Py_ssize_t *shape = MEM_mallocN(sizeof(Py_ssize_t), __func__); + shape[0] = prop->len; + view->shape = shape; + + return 0; +} + +static void BPy_IDArray_releasebuffer(BPy_IDArray *UNUSED(self), Py_buffer *view) +{ + MEM_freeN(view->shape); +} + +static PyBufferProcs BPy_IDArray_Buffer = { + (getbufferproc)BPy_IDArray_getbuffer, + (releasebufferproc)BPy_IDArray_releasebuffer, +}; + PyTypeObject BPy_IDArray_Type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -1403,7 +1581,7 @@ PyTypeObject BPy_IDArray_Type = { NULL, /* setattrofunc tp_setattro; */ /* Functions to access object as input/output buffer */ - NULL, /* PyBufferProcs *tp_as_buffer; */ + &BPy_IDArray_Buffer, /* PyBufferProcs *tp_as_buffer; */ /*** Flags to define presence of optional/expanded features ***/ Py_TPFLAGS_DEFAULT, /* long tp_flags; */ diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index e61018865ab..2656e612b18 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -50,11 +50,13 @@ #include "../generic/py_capi_utils.h" /* initial definition of callback slots we'll probably have more than 1 */ -#define BPY_DATA_CB_SLOT_SIZE 3 - -#define BPY_DATA_CB_SLOT_UPDATE 0 -#define BPY_DATA_CB_SLOT_GET 1 -#define BPY_DATA_CB_SLOT_SET 2 +enum { + BPY_DATA_CB_SLOT_UPDATE = 0, + BPY_DATA_CB_SLOT_GET = 1, + BPY_DATA_CB_SLOT_SET = 2, + BPY_DATA_CB_SLOT_POLL = 3, + BPY_DATA_CB_SLOT_SIZE = 4, +}; extern BPy_StructRNA *bpy_context_module; @@ -71,6 +73,9 @@ static EnumPropertyItem property_flag_items[] = { " :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'LIBRARY_EDITABLE', 'PROPORTIONAL'," \ "'TEXTEDIT_UPDATE'].\n" \ " :type options: set\n" \ +" :arg poll: function to be called to determine whether an item is valid for this property.\n" \ +" The function must take 2 values (self,object) and return Bool.\n" \ +" :type poll: function\n" \ static EnumPropertyItem property_flag_enum_items[] = { {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""}, @@ -230,7 +235,7 @@ static PyObject *bpy_prop_deferred_return(PyObject *func, PyObject *kw) static void bpy_prop_update_cb(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop) { PyGILState_STATE gilstate; - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -279,7 +284,7 @@ static void bpy_prop_update_cb(struct bContext *C, struct PointerRNA *ptr, struc static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -337,7 +342,7 @@ static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -389,9 +394,54 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA * } } +static int bpy_prop_poll_cb(struct PointerRNA *self, PointerRNA candidate, struct PropertyRNA *prop) +{ + PyObject *py_self; + PyObject *py_candidate; + PyObject *py_func; + PyObject **py_data = RNA_property_py_data_get(prop); + PyObject *args; + PyObject *ret; + bool result; + const int is_write_ok = pyrna_write_check(); + PyGILState_STATE gilstate = PyGILState_Ensure(); + + BLI_assert(self != NULL); + + py_self = pyrna_struct_as_instance(self); + py_candidate = pyrna_struct_as_instance(&candidate); + py_func = py_data[BPY_DATA_CB_SLOT_POLL]; + + if (!is_write_ok) + pyrna_write_set(true); + + args = PyTuple_New(2); + PyTuple_SET_ITEM(args, 0, py_self); + PyTuple_SET_ITEM(args, 1, py_candidate); + + ret = PyObject_CallObject(py_func, args); + + Py_DECREF(args); + + if (ret == NULL) { + printf_func_error(py_func); + result = false; + } + else { + result = PyObject_IsTrue(ret); + Py_DECREF(ret); + } + + PyGILState_Release(gilstate); + if (!is_write_ok) + pyrna_write_set(false); + + return result; +} + static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int *values) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -452,7 +502,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr, struct Propert static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const int *values) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -513,7 +563,7 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct Propert static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -571,7 +621,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop) static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -625,7 +675,7 @@ static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int *values) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -686,7 +736,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const int *values) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -747,7 +797,7 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -805,7 +855,7 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, float value) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -859,7 +909,7 @@ static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pr static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, float *values) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -920,7 +970,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr, struct PropertyR static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const float *values) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -981,7 +1031,7 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyR static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, char *value) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -1040,7 +1090,7 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA *prop) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -1102,7 +1152,7 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const char *value) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -1163,7 +1213,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *p static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -1221,7 +1271,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value) { - PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop); + PyObject **py_data = RNA_property_py_data_get(prop); PyObject *py_func; PyObject *args; PyObject *self; @@ -1598,6 +1648,16 @@ static void bpy_prop_callback_assign_update(struct PropertyRNA *prop, PyObject * } } +static void bpy_prop_callback_assign_pointer(struct PropertyRNA *prop, PyObject *poll_cb) +{ + if (poll_cb && poll_cb != Py_None) { + PyObject **py_data = bpy_prop_py_data_get(prop); + + RNA_def_property_poll_runtime(prop, (void *) bpy_prop_poll_cb); + py_data[BPY_DATA_CB_SLOT_POLL] = poll_cb; + } +} + static void bpy_prop_callback_assign_boolean(struct PropertyRNA *prop, PyObject *get_cb, PyObject *set_cb) { BooleanPropertyGetFunc rna_get_cb = NULL; @@ -1904,7 +1964,7 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop, PyObject *ge " :type set: function\n" \ #define BPY_PROPDEF_TYPE_DOC \ -" :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n" \ +" :arg type: A subclass of :class:`bpy.types.PropertyGroup` or :class:`bpy.types.ID`.\n" \ " :type type: class\n" \ #if 0 @@ -2772,7 +2832,7 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) Py_RETURN_NONE; } -static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix) +StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix) { StructRNA *srna; @@ -2782,25 +2842,18 @@ static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix PyObject *msg = PyC_ExceptionBuffer(); const char *msg_char = _PyUnicode_AsString(msg); PyErr_Format(PyExc_TypeError, - "%.200s expected an RNA type derived from PropertyGroup, failed with: %s", + "%.200s expected an RNA type, failed with: %s", error_prefix, msg_char); Py_DECREF(msg); } else { PyErr_Format(PyExc_TypeError, - "%.200s expected an RNA type derived from PropertyGroup, failed with type '%s'", + "%.200s expected an RNA type, failed with type '%s'", error_prefix, Py_TYPE(value)->tp_name); } return NULL; } - if (!RNA_struct_is_a(srna, &RNA_PropertyGroup)) { - PyErr_Format(PyExc_TypeError, - "%.200s expected an RNA type derived from PropertyGroup", - error_prefix); - return NULL; - } - return srna; } @@ -2809,7 +2862,8 @@ PyDoc_STRVAR(BPy_PointerProperty_doc, "name=\"\", " "description=\"\", " "options={'ANIMATABLE'}, " - "update=None)\n" + "update=None,\n" + "poll=None)\n" "\n" " Returns a new pointer property definition.\n" "\n" @@ -2819,14 +2873,14 @@ BPY_PROPDEF_DESC_DOC BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_UPDATE_DOC ); -static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) +PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; BPY_PROPDEF_HEAD(PointerProperty); if (srna) { - static const char *kwlist[] = {"attr", "type", "name", "description", "options", "update", NULL}; + static const char *kwlist[] = {"attr", "type", "name", "description", "options", "poll", "update", NULL}; const char *id = NULL, *name = NULL, *description = ""; int id_len; PropertyRNA *prop; @@ -2834,33 +2888,47 @@ static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *k PyObject *type = Py_None; PyObject *pyopts = NULL; int opts = 0; - PyObject *update_cb = NULL; + PyObject *update_cb = NULL, *poll_cb = NULL; if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#O|ssO!O:PointerProperty", + "s#O|ssO!OOO:PointerProperty", (char **)kwlist, &id, &id_len, &type, &name, &description, &PySet_Type, &pyopts, - &update_cb)) + &poll_cb, &update_cb)) { return NULL; } BPY_PROPDEF_CHECK(PointerProperty, property_flag_items); - ptype = pointer_type_from_py(type, "PointerProperty(...):"); + ptype = pointer_type_from_py(type, "PointerProperty(...)"); if (!ptype) return NULL; - + if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup) && !RNA_struct_is_ID(ptype)) { + PyErr_Format(PyExc_TypeError, + "PointerProperty(...) expected an RNA type derived from %.200s or %.200s", + RNA_struct_ui_name(&RNA_ID), RNA_struct_ui_name(&RNA_PropertyGroup)); + return NULL; + } if (bpy_prop_callback_check(update_cb, "update", 2) == -1) { return NULL; } - + if (bpy_prop_callback_check(poll_cb, "poll", 2) == -1) { + return NULL; + } prop = RNA_def_pointer_runtime(srna, id, ptype, name ? name : id, description); if (pyopts) { bpy_prop_assign_flag(prop, opts); } + + if (RNA_struct_idprops_contains_datablock(ptype)) { + if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) { + RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES); + } + } bpy_prop_callback_assign_update(prop, update_cb); + bpy_prop_callback_assign_pointer(prop, poll_cb); RNA_def_property_duplicate_pointers(srna, prop); } Py_RETURN_NONE; @@ -2879,7 +2947,7 @@ BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC BPY_PROPDEF_OPTIONS_DOC ); -static PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) +PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -2910,10 +2978,23 @@ static PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject if (!ptype) return NULL; + if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup)) { + PyErr_Format(PyExc_TypeError, + "CollectionProperty(...) expected an RNA type derived from %.200s", + RNA_struct_ui_name(&RNA_ID), RNA_struct_ui_name(&RNA_PropertyGroup)); + return NULL; + } + prop = RNA_def_collection_runtime(srna, id, ptype, name ? name : id, description); if (pyopts) { bpy_prop_assign_flag(prop, opts); } + + if (RNA_struct_idprops_contains_datablock(ptype)) { + if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) { + RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES); + } + } RNA_def_property_duplicate_pointers(srna, prop); } Py_RETURN_NONE; diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h index c9934ca0cf3..614c1b4b708 100644 --- a/source/blender/python/intern/bpy_props.h +++ b/source/blender/python/intern/bpy_props.h @@ -30,6 +30,10 @@ PyObject *BPY_rna_props(void); +PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw); +PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw); +StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix); + #define PYRNA_STACK_ARRAY 32 #endif diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 2fd46ab94f0..00627030db3 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1934,16 +1934,10 @@ static int pyrna_py_to_prop( } else { /* data == NULL, assign to RNA */ - if (value == Py_None) { - PointerRNA valueptr = {{NULL}}; - RNA_property_pointer_set(ptr, prop, valueptr); - } - else if (RNA_struct_is_a(param->ptr.type, ptr_type)) { - RNA_property_pointer_set(ptr, prop, param->ptr); - } - else { + if (value == Py_None || RNA_struct_is_a(param->ptr.type, ptr_type)) + RNA_property_pointer_set(ptr, prop, value == Py_None ? PointerRNA_NULL : param->ptr); + else raise_error = true; - } } if (raise_error) { @@ -3277,6 +3271,16 @@ static int pyrna_struct_ass_subscript(BPy_StructRNA *self, PyObject *key, PyObje return -1; } + BPy_StructRNA *val = (BPy_StructRNA *)value; + if (val && self->ptr.type && val->ptr.type) { + if (!RNA_struct_idprops_datablock_allowed(self->ptr.type) && + RNA_struct_idprops_contains_datablock(val->ptr.type)) + { + PyErr_SetString(PyExc_TypeError, "bpy_struct[key] = val: datablock id properties not supported for this type"); + return -1; + } + } + return BPy_Wrap_SetMapItem(group, key, value); } @@ -6745,7 +6749,7 @@ PyObject *pyrna_id_CreatePyObject(ID *id) bool pyrna_id_FromPyObject(PyObject *obj, ID **id) { - if (BPy_StructRNA_Check(obj) && (RNA_struct_is_ID(((BPy_StructRNA *)obj)->ptr.type))) { + if (pyrna_id_CheckPyObject(obj)) { *id = ((BPy_StructRNA *)obj)->ptr.id.data; return true; } @@ -6755,6 +6759,11 @@ bool pyrna_id_FromPyObject(PyObject *obj, ID **id) } } +bool pyrna_id_CheckPyObject(PyObject *obj) +{ + return BPy_StructRNA_Check(obj) && (RNA_struct_is_ID(((BPy_StructRNA *) obj)->ptr.type)); +} + void BPY_rna_init(void) { #ifdef USE_MATHUTILS /* register mathutils callbacks, ok to run more than once. */ @@ -7089,6 +7098,21 @@ static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item args_fake = PyTuple_New(1); PyTuple_SET_ITEM(args_fake, 0, py_srna_cobject); + PyObject *type = PyDict_GetItemString(py_kw, "type"); + StructRNA *type_srna = srna_from_self(type, ""); + if (type_srna) { + if (!RNA_struct_idprops_datablock_allowed(srna) && + (*(PyCFunctionWithKeywords)PyCFunction_GET_FUNCTION(py_func) == BPy_PointerProperty || + *(PyCFunctionWithKeywords)PyCFunction_GET_FUNCTION(py_func) == BPy_CollectionProperty) && + RNA_struct_idprops_contains_datablock(type_srna)) + { + PyErr_Format(PyExc_ValueError, + "bpy_struct \"%.200s\" doesn't support datablock properties \n", + RNA_struct_identifier(srna)); + return -1; + } + } + py_ret = PyObject_Call(py_func, args_fake, py_kw); if (py_ret) { diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index e38d4f095d6..605f79b1ad8 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -179,6 +179,7 @@ PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop); /* extern'd by other modules which don't deal closely with RNA */ PyObject *pyrna_id_CreatePyObject(struct ID *id); bool pyrna_id_FromPyObject(PyObject *obj, struct ID **id); +bool pyrna_id_CheckPyObject(PyObject *obj); /* operators also need this to set args */ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const bool all_args, const char *error_prefix); diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 4e980e4c0e6..bd44e77e7c6 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -1301,7 +1301,7 @@ PyDoc_STRVAR(Matrix_to_scale_doc, " :return: Return the scale of a matrix.\n" " :rtype: :class:`Vector`\n" "\n" -" .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n" +" .. note:: This method does not return a negative scale on any axis because it is not possible to obtain this data from the matrix alone.\n" ); static PyObject *Matrix_to_scale(MatrixObject *self) { @@ -1390,11 +1390,11 @@ PyDoc_STRVAR(Matrix_invert_doc, "\n" " Set the matrix to its inverse.\n" "\n" -" :arg fallback: Set the matrix to this value when the inverse can't be calculated\n" +" :arg fallback: Set the matrix to this value when the inverse cannot be calculated\n" " (instead of raising a :exc:`ValueError` exception).\n" " :type fallback: :class:`Matrix`\n" "\n" -" .. seealso:: <https://en.wikipedia.org/wiki/Inverse_matrix>\n" +" .. seealso:: `Inverse matrix <https://en.wikipedia.org/wiki/Inverse_matrix>` on Wikipedia.\n" ); static PyObject *Matrix_invert(MatrixObject *self, PyObject *args) { @@ -1505,7 +1505,7 @@ PyDoc_STRVAR(Matrix_invert_safe_doc, " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n" " If tweaked matrix is still degenerated, set to the identity matrix instead.\n" "\n" -" .. seealso:: <https://en.wikipedia.org/wiki/Inverse_matrix>\n" +" .. seealso:: `Inverse Matrix <https://en.wikipedia.org/wiki/Inverse_matrix>` on Wikipedia.\n" ); static PyObject *Matrix_invert_safe(MatrixObject *self) { @@ -1554,9 +1554,9 @@ PyDoc_STRVAR(Matrix_adjugate_doc, "\n" " Set the matrix to its adjugate.\n" "\n" -" .. note:: When the matrix cant be adjugated a :exc:`ValueError` exception is raised.\n" +" .. note:: When the matrix cannot be adjugated a :exc:`ValueError` exception is raised.\n" "\n" -" .. seealso:: <https://en.wikipedia.org/wiki/Adjugate_matrix>\n" +" .. seealso:: `Adjugate matrix <https://en.wikipedia.org/wiki/Adjugate_matrix>` on Wikipedia.\n" ); static PyObject *Matrix_adjugate(MatrixObject *self) { @@ -1733,7 +1733,7 @@ PyDoc_STRVAR(Matrix_determinant_doc, " :return: Return the determinant of a matrix.\n" " :rtype: float\n" "\n" -" .. seealso:: <https://en.wikipedia.org/wiki/Determinant>\n" +" .. seealso:: `Determinant <https://en.wikipedia.org/wiki/Determinant>` on Wikipedia.\n" ); static PyObject *Matrix_determinant(MatrixObject *self) { @@ -1755,7 +1755,7 @@ PyDoc_STRVAR(Matrix_transpose_doc, "\n" " Set the matrix to its transpose.\n" "\n" -" .. seealso:: <https://en.wikipedia.org/wiki/Transpose>\n" +" .. seealso:: `Transpose <https://en.wikipedia.org/wiki/Transpose>` on Wikipedia.\n" ); static PyObject *Matrix_transpose(MatrixObject *self) { @@ -1887,10 +1887,10 @@ PyDoc_STRVAR(Matrix_identity_doc, "\n" " Set the matrix to the identity matrix.\n" "\n" -" .. note:: An object with zero location and rotation, a scale of one,\n" +" .. note:: An object with a location and rotation of zero, and a scale of one\n" " will have an identity matrix.\n" "\n" -" .. seealso:: <https://en.wikipedia.org/wiki/Identity_matrix>\n" +" .. seealso:: `Identity matrix <https://en.wikipedia.org/wiki/Identity_matrix>` on Wikipedia.\n" ); static PyObject *Matrix_identity(MatrixObject *self) { diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index f535aa5aa71..eaa4cf2c69c 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -381,7 +381,7 @@ bool RE_allow_render_generic_object(struct Object *ob); /* RE_updateRenderInstances flag */ enum { RE_OBJECT_INSTANCES_UPDATE_VIEW = (1 << 0), - RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1), + RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1) }; void RE_updateRenderInstances(Render *re, int flag); diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index ae389fdfd2e..b64c0c8fc52 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -178,6 +178,7 @@ typedef struct ShadeInput { unsigned int lay; int layflag, passflag, combinedflag; + short object_pass_index; struct Group *light_override; struct Material *mat_override; @@ -241,6 +242,9 @@ enum { const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4]; +float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi); +float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi); + enum { RE_VIEW_MATRIX, RE_VIEWINV_MATRIX, diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index b3a5ccdae17..f0323340899 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -382,6 +382,8 @@ typedef struct ObjectInstanceRen { float part_co[3]; float part_vel[3]; float part_avel[3]; + + unsigned int random_id; } ObjectInstanceRen; /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index b4a14f5337d..42e4d4f27f6 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -1112,14 +1112,15 @@ static int multitex(Tex *tex, const short which_output, struct ImagePool *pool, const bool skip_load_image, - const bool texnode_preview) + const bool texnode_preview, + const bool use_nodes) { float tmpvec[3]; int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */ texres->talpha = false; /* is set when image texture returns alpha (considered premul) */ - if (tex->use_nodes && tex->nodetree) { + if (use_nodes && tex->use_nodes && tex->nodetree) { retval = ntreeTexExecTree(tex->nodetree, texres, texvec, dxt, dyt, osatex, thread, tex, which_output, R.r.cfra, texnode_preview, NULL, NULL); } @@ -1239,7 +1240,8 @@ static int multitex_nodes_intern(Tex *tex, ImagePool *pool, const bool scene_color_manage, const bool skip_load_image, - const bool texnode_preview) + const bool texnode_preview, + const bool use_nodes) { if (tex==NULL) { memset(texres, 0, sizeof(TexResult)); @@ -1264,7 +1266,8 @@ static int multitex_nodes_intern(Tex *tex, which_output, pool, skip_load_image, - texnode_preview); + texnode_preview, + use_nodes); if (mtex->mapto & (MAP_COL+MAP_COLSPEC+MAP_COLMIR)) { ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool); @@ -1311,7 +1314,8 @@ static int multitex_nodes_intern(Tex *tex, which_output, pool, skip_load_image, - texnode_preview); + texnode_preview, + use_nodes); { ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool); @@ -1341,7 +1345,8 @@ static int multitex_nodes_intern(Tex *tex, which_output, pool, skip_load_image, - texnode_preview); + texnode_preview, + use_nodes); } } @@ -1354,7 +1359,8 @@ int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int os return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, shi, mtex, pool, R.scene_color_manage, (R.r.scemode & R_NO_IMAGE_LOAD) != 0, - (R.r.scemode & R_TEXNODE_PREVIEW) != 0); + (R.r.scemode & R_TEXNODE_PREVIEW) != 0, + true); } /* this is called for surface shading */ @@ -1378,7 +1384,8 @@ static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt mtex->which_output, pool, skip_load_image, - (R.r.scemode & R_TEXNODE_PREVIEW) != 0); + (R.r.scemode & R_TEXNODE_PREVIEW) != 0, + true); } } @@ -1408,7 +1415,8 @@ int multitex_ext(Tex *tex, pool, scene_color_manage, skip_load_image, - false); + false, + true); } /* extern-tex doesn't support nodes (ntreeBeginExec() can't be called when rendering is going on)\ @@ -1417,13 +1425,19 @@ int multitex_ext(Tex *tex, */ int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image) { - int use_nodes= tex->use_nodes, retval; - - tex->use_nodes = false; - retval= multitex_nodes_intern(tex, texvec, NULL, NULL, 0, texres, 0, 0, NULL, NULL, pool, scene_color_manage, skip_load_image, false); - tex->use_nodes= use_nodes; - - return retval; + return multitex_nodes_intern(tex, + texvec, + NULL, NULL, + 0, + texres, + 0, + 0, + NULL, NULL, + pool, + scene_color_manage, + skip_load_image, + false, + false); } @@ -2873,7 +2887,8 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_ mtex->which_output, re->pool, skip_load_image, - texnode_preview); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */ + texnode_preview, + true); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */ /* texture output */ @@ -3051,7 +3066,8 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4]) mtex->which_output, har->pool, skip_load_image, - texnode_preview); + texnode_preview, + true); /* texture output */ if (rgb && (mtex->texflag & MTEX_RGBTOINT)) { @@ -3274,7 +3290,8 @@ void do_sky_tex( mtex->which_output, R.pool, skip_load_image, - texnode_preview); + texnode_preview, + true); /* texture output */ if (rgb && (mtex->texflag & MTEX_RGBTOINT)) { @@ -3500,7 +3517,8 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r mtex->which_output, R.pool, skip_load_image, - texnode_preview); + texnode_preview, + true); /* texture output */ if (rgb && (mtex->texflag & MTEX_RGBTOINT)) { @@ -3614,7 +3632,8 @@ int externtex(MTex *mtex, mtex->which_output, pool, skip_load_image, - texnode_preview); + texnode_preview, + true); if (rgb) { texr.tin = IMB_colormanagement_get_luminance(&texr.tr); diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index 76e6ca8d467..199322795f3 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -66,6 +66,7 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_hash.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" @@ -1458,6 +1459,14 @@ ObjectInstanceRen *RE_addRenderInstance( } } + /* Fill object info */ + if (dob) { + obi->random_id = dob->random_id; + } + else { + obi->random_id = BLI_hash_int_2d(BLI_hash_string(obi->ob->id.name + 2), 0); + } + RE_updateRenderInstance(re, obi, RE_OBJECT_INSTANCES_UPDATE_OBMAT | RE_OBJECT_INSTANCES_UPDATE_VIEW); if (mat) { diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index a8fb72fb7f8..8dea0930b9e 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -2141,6 +2141,16 @@ const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int m return NULL; } +float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi) +{ + return obi->ob->index; +} + +float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi) +{ + return obi->random_id; +} + const float (*RE_render_current_get_matrix(int matrix_id))[4] { switch (matrix_id) { diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index b6245a8c0d1..925563a0777 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -128,10 +128,6 @@ if(WITH_PYTHON) ../python ) add_definitions(-DWITH_PYTHON) - - if(WITH_PYTHON_SECURITY) - add_definitions(-DWITH_PYTHON_SECURITY) - endif() endif() if(WITH_GAMEENGINE) diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 4351cd22b18..d0522fdd7d4 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -489,7 +489,7 @@ void wm_close_and_free_all(bContext *C, ListBase *wmlist) while ((wm = wmlist->first)) { wm_close_and_free(C, wm); BLI_remlink(wmlist, wm); - BKE_libblock_free_data(bmain, &wm->id); + BKE_libblock_free_data(bmain, &wm->id, true); MEM_freeN(wm); } } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 60a361122c2..028355f9af3 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -316,7 +316,7 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist) } /* in case UserDef was read, we re-initialize all, and do versioning */ -static void wm_init_userdef(bContext *C, const bool from_memory) +static void wm_init_userdef(bContext *C, const bool use_factory_settings) { Main *bmain = CTX_data_main(C); @@ -336,7 +336,7 @@ static void wm_init_userdef(bContext *C, const bool from_memory) } /* avoid re-saving for every small change to our prefs, allow overrides */ - if (from_memory) { + if (use_factory_settings) { BLO_update_defaults_userpref_blend(); } @@ -470,6 +470,10 @@ 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()"); + } /* sync addons, these may have changed from the defaults */ BPY_execute_string(C, "__import__('addon_utils').reset_all()"); @@ -632,22 +636,31 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) * Called on startup, (context entirely filled with NULLs) * or called for 'New File' both startup.blend and userpref.blend are checked. * - * \param from_memory: Ignore on-disk startup file, use bundled ``datatoc_startup_blend`` instead. + * \param use_factory_settings: Ignore on-disk startup file, use bundled ``datatoc_startup_blend`` instead. * Used for "Restore Factory Settings". * \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 from_memory, const char *filepath_startup_override) + bool use_factory_settings, bool use_empty_data, + const char *filepath_startup_override, const char *app_template_override) { ListBase wmbase; + bool success = false; + char filepath_startup[FILE_MAX]; char filepath_userdef[FILE_MAX]; - bool success = false; + + /* When 'app_template' is set: '{BLENDER_USER_CONFIG}/{app_template}' */ + char app_template_system[FILE_MAX]; + /* When 'app_template' is set: '{BLENDER_SYSTEM_SCRIPTS}/startup/bl_app_templates_system/{app_template}' */ + char app_template_config[FILE_MAX]; /* Indicates whether user preferences were really load from memory. * - * This is used for versioning code, and for this we can not rely on from_memory + * This is used for versioning code, and for this we can not rely on use_factory_settings * passed via argument. This is because there might be configuration folder * exists but it might not have userpref.blend and in this case we fallback to * reading home file from memory. @@ -658,7 +671,7 @@ int wm_homefile_read( eBLOReadSkip skip_flags = 0; /* options exclude eachother */ - BLI_assert((from_memory && filepath_startup_override) == 0); + BLI_assert((use_factory_settings && filepath_startup_override) == 0); if ((G.f & G_SCRIPT_OVERRIDE_PREF) == 0) { BKE_BIT_TEST_SET(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_SCRIPT_AUTOEXEC); @@ -669,34 +682,32 @@ int wm_homefile_read( UI_view2d_zoom_cache_reset(); G.relbase_valid = 0; - if (!from_memory) { - const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); - if (filepath_startup_override) { - BLI_strncpy(filepath_startup, filepath_startup_override, FILE_MAX); - if (cfgdir) { - BLI_make_file_string(G.main->name, filepath_userdef, cfgdir, BLENDER_USERPREF_FILE); - } - else { - filepath_userdef[0] = '\0'; - } - } - else if (cfgdir) { - BLI_make_file_string(G.main->name, filepath_startup, cfgdir, BLENDER_STARTUP_FILE); - BLI_make_file_string(G.main->name, filepath_userdef, cfgdir, BLENDER_USERPREF_FILE); + /* put aside screens to match with persistent windows later */ + wm_window_match_init(C, &wmbase); + + filepath_startup[0] = '\0'; + filepath_userdef[0] = '\0'; + app_template_system[0] = '\0'; + app_template_config[0] = '\0'; + + const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); + 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); } else { - filepath_startup[0] = '\0'; - filepath_userdef[0] = '\0'; - from_memory = true; + use_factory_settings = true; + } + + if (filepath_startup_override) { + BLI_strncpy(filepath_startup, filepath_startup_override, FILE_MAX); } } - - /* put aside screens to match with persistent windows later */ - wm_window_match_init(C, &wmbase); - + /* load preferences before startup.blend */ - if (!from_memory && BLI_exists(filepath_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); @@ -708,7 +719,43 @@ int wm_homefile_read( } } - if (!from_memory) { + const char *app_template = NULL; + + if (filepath_startup_override != NULL) { + /* pass */ + } + else if (app_template_override) { + app_template = app_template_override; + } + else if (!use_factory_settings && U.app_template[0]) { + app_template = U.app_template; + } + + if (app_template != NULL) { + 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) { + /* 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(filepath_startup, sizeof(filepath_startup), app_template_config, BLENDER_STARTUP_FILE, NULL); + if (BLI_access(filepath_startup, R_OK) != 0) { + filepath_startup[0] = '\0'; + } + } + else { + filepath_startup[0] = '\0'; + } + + if (filepath_startup[0] == '\0') { + BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_system, BLENDER_STARTUP_FILE, NULL); + } + } + + if (!use_factory_settings || (filepath_startup[0] != '\0')) { if (BLI_access(filepath_startup, R_OK) == 0) { success = (BKE_blendfile_read(C, filepath_startup, NULL, skip_flags) != BKE_BLENDFILE_READ_FAIL); } @@ -720,8 +767,8 @@ int wm_homefile_read( } if (success == false && filepath_startup_override && reports) { + /* We can not return from here because wm is already reset */ BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", filepath_startup_override); - /*We can not return from here because wm is already reset*/ } if (success == false) { @@ -731,15 +778,50 @@ int wm_homefile_read( if (BLI_listbase_is_empty(&wmbase)) { wm_clear_default_size(C); } - BKE_tempdir_init(U.tempdir); + } -#ifdef WITH_PYTHON_SECURITY - /* use alternative setting for security nuts - * otherwise we'd need to patch the binary blob - startup.blend.c */ - U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE; -#endif + if (use_empty_data) { + BKE_blendfile_read_make_empty(C); } - + + /* Load template preferences, + * unlike regular preferences we only use some of the settings, + * see: BKE_blender_userdef_set_app_template */ + if (app_template_system[0] != '\0') { + char temp_path[FILE_MAX]; + temp_path[0] = '\0'; + if (!use_factory_settings) { + BLI_path_join(temp_path, sizeof(temp_path), app_template_config, BLENDER_USERPREF_FILE, NULL); + if (BLI_access(temp_path, R_OK) != 0) { + temp_path[0] = '\0'; + } + } + + if (temp_path[0] == '\0') { + 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); + } + if (userdef_template) { + BKE_blender_userdef_set_app_template(userdef_template); + BKE_blender_userdef_free_data(userdef_template); + MEM_freeN(userdef_template); + } + } + + if (app_template_override) { + BLI_strncpy(U.app_template, app_template_override, sizeof(U.app_template)); + } + /* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise * can remove this eventually, only in a 2.53 and older, now its not written */ G.fileflags &= ~G_FILE_RELATIVE_REMAP; @@ -754,11 +836,14 @@ 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(); - - /* XXX */ - G.save_over = 0; // start with save preference untitled.blend - G.fileflags &= ~G_FILE_AUTOPLAY; /* disable autoplay in startup.blend... */ + if (!G.background) { + GPU_default_lights(); + } + + /* start with save preference untitled.blend */ + G.save_over = 0; + /* disable auto-play in startup.blend... */ + G.fileflags &= ~G_FILE_AUTOPLAY; wm_file_read_post(C, true); @@ -1274,6 +1359,13 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op) char filepath[FILE_MAX]; int fileflags; + const char *app_template = U.app_template[0] ? U.app_template : NULL; + const char * const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template); + if (cfgdir == NULL) { + BKE_report(op->reports, RPT_ERROR, "Unable to create user config path"); + return OPERATOR_CANCELLED; + } + BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE); /* check current window and close it if temp */ @@ -1283,7 +1375,8 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op) /* update keymaps in user preferences */ WM_keyconfig_update(wm); - BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE); + BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE, NULL); + printf("trying to save homefile at %s ", filepath); ED_editors_flush_edits(C, false); @@ -1361,21 +1454,44 @@ static int wm_userpref_write_exec(bContext *C, wmOperator *op) { wmWindowManager *wm = CTX_wm_manager(C); char filepath[FILE_MAX]; + const char *cfgdir; + bool ok = false; /* update keymaps in user preferences */ WM_keyconfig_update(wm); - BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE); - printf("trying to save userpref at %s ", filepath); - - if (BKE_blendfile_userdef_write(filepath, op->reports) == 0) { - printf("fail\n"); - return OPERATOR_CANCELLED; + if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) { + BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL); + printf("trying to save userpref at %s ", filepath); + if (BKE_blendfile_userdef_write(filepath, op->reports) != 0) { + printf("ok\n"); + ok = true; + } + else { + printf("fail\n"); + } + } + else { + BKE_report(op->reports, RPT_ERROR, "Unable to create userpref path"); } - printf("ok\n"); + if (U.app_template[0] && (cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) { + /* Also save app-template prefs */ + BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL); + printf("trying to save app-template userpref at %s ", filepath); + if (BKE_blendfile_userdef_write(filepath, op->reports) == 0) { + printf("fail\n"); + ok = true; + } + else { + printf("ok\n"); + } + } + else if (U.app_template[0]) { + BKE_report(op->reports, RPT_ERROR, "Unable to create app-template userpref path"); + } - return OPERATOR_FINISHED; + return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void WM_OT_save_userpref(wmOperatorType *ot) @@ -1410,11 +1526,11 @@ void WM_OT_read_history(wmOperatorType *ot) static int wm_homefile_read_exec(bContext *C, wmOperator *op) { - const bool from_memory = (STREQ(op->type->idname, "WM_OT_read_factory_settings")); + const bool use_factory_settings = (STREQ(op->type->idname, "WM_OT_read_factory_settings")); char filepath_buf[FILE_MAX]; const char *filepath = NULL; - if (!from_memory) { + if (!use_factory_settings) { PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath"); /* This can be used when loading of a start-up file should only change @@ -1436,9 +1552,27 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) G.fileflags &= ~G_FILE_NO_UI; } - if (wm_homefile_read(C, op->reports, from_memory, filepath)) { - /* Load a file but keep the splash open */ - if (!from_memory && RNA_boolean_get(op->ptr, "use_splash")) { + char app_template_buf[sizeof(U.app_template)]; + const char *app_template; + PropertyRNA *prop_app_template = RNA_struct_find_property(op->ptr, "app_template"); + const bool use_splash = !use_factory_settings && RNA_boolean_get(op->ptr, "use_splash"); + const bool use_empty_data = RNA_boolean_get(op->ptr, "use_empty"); + + 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; + } + else { + app_template = NULL; + } + + if (wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, filepath, app_template)) { + if (use_splash) { WM_init_splash(C); } return OPERATOR_FINISHED; @@ -1468,21 +1602,36 @@ void WM_OT_read_homefile(wmOperatorType *ot) "Load user interface setup from the .blend file"); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + /* So the splash can be kept open after loading a file (for templates). */ prop = RNA_def_boolean(ot->srna, "use_splash", false, "Splash", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + /* omit poll to run in background mode */ } void WM_OT_read_factory_settings(wmOperatorType *ot) { + PropertyRNA *prop; + ot->name = "Load Factory Settings"; ot->idname = "WM_OT_read_factory_settings"; ot->description = "Load default file and user preferences"; ot->invoke = WM_operator_confirm; ot->exec = wm_homefile_read_exec; + + prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + /* omit poll to run in background mode */ } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index be74a0c7362..9bafe72d805 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -192,7 +192,7 @@ void WM_init(bContext *C, int argc, const char **argv) wm_init_reports(C); /* get the default database, plus a wm */ - wm_homefile_read(C, NULL, G.factory_startup, NULL); + wm_homefile_read(C, NULL, G.factory_startup, false, NULL, NULL); BLT_lang_set(NULL); diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index e201fa433d4..db5fc23146f 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -121,6 +121,13 @@ static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi) if (ot->srna != kmi->ptr->type) { /* matches wm_keymap_item_properties_set but doesnt alloc new ptr */ WM_operator_properties_create_ptr(kmi->ptr, ot); + /* 'kmi->ptr->data' NULL'd above, keep using existing properties. + * Note: the operators property types may have changed, + * we will need a more comprehensive sanitize function to support this properly. + */ + if (kmi->properties) { + kmi->ptr->data = kmi->properties; + } WM_operator_properties_sanitize(kmi->ptr, 1); } } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 9d4c3986678..d827ccafda8 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -900,7 +900,7 @@ void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot) void WM_operator_properties_create(PointerRNA *ptr, const char *opstring) { - wmOperatorType *ot = WM_operatortype_find(opstring, 0); + wmOperatorType *ot = WM_operatortype_find(opstring, false); if (ot) WM_operator_properties_create_ptr(ptr, ot); @@ -1403,20 +1403,6 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2) } } -static void popup_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg)) -{ - wmOperator *op = op_ptr; - if (op->type->check) { - if (op->type->check(C, op)) { - /* check for popup and re-layout buttons */ - ARegion *ar_menu = CTX_wm_menu(C); - if (ar_menu) { - ED_region_tag_refresh_ui(ar_menu); - } - } - } -} - /* Dialogs are popups that require user verification (click OK) before exec */ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData) { @@ -1435,8 +1421,6 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData) layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); - UI_block_func_set(block, popup_check_cb, op, NULL); - uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE); /* clear so the OK button is left alone */ @@ -1475,8 +1459,6 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData) layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); - UI_block_func_set(block, popup_check_cb, op, NULL); - /* since ui is defined the auto-layout args are not used */ uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0); @@ -1523,7 +1505,7 @@ int WM_operator_ui_popup(bContext *C, wmOperator *op, int width, int height) data->width = width; data->height = height; data->free_op = true; /* if this runs and gets registered we may want not to free it */ - UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data); + UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data, op); return OPERATOR_RUNNING_MODAL; } @@ -1553,7 +1535,7 @@ static int wm_operator_props_popup_ex(bContext *C, wmOperator *op, if (!do_redo || !(U.uiflag & USER_GLOBALUNDO)) return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, UI_UNIT_Y); - UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op); + UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op, op); if (do_call) wm_block_redo_cb(C, op, 0); @@ -1595,7 +1577,7 @@ int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, int h data->free_op = true; /* if this runs and gets registered we may want not to free it */ /* op is not executed until popup OK but is clicked */ - UI_popup_block_ex(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data); + UI_popup_block_ex(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data, op); return OPERATOR_RUNNING_MODAL; } @@ -1762,6 +1744,36 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar ibuf = IMB_ibImageFromMemory((unsigned char *)datatoc_splash_png, datatoc_splash_png_size, IB_rect, NULL, "<splash screen>"); } + + /* overwrite splash with template image */ + if (U.app_template[0] != '\0') { + ImBuf *ibuf_template = NULL; + char splash_filepath[FILE_MAX]; + char template_directory[FILE_MAX]; + + if (BKE_appdir_app_template_id_search( + U.app_template, + template_directory, sizeof(template_directory))) + { + BLI_join_dirfile( + splash_filepath, sizeof(splash_filepath), template_directory, + (U.pixelsize == 2) ? "splash_2x.png" : "splash.png"); + ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL); + if (ibuf_template) { + const int x_expect = ibuf->x; + const int y_expect = 230 * (int)U.pixelsize; + /* don't cover the header text */ + if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) { + memcpy(ibuf->rect, ibuf_template->rect, ibuf_template->x * ibuf_template->y * sizeof(char[4])); + } + else { + printf("Splash expected %dx%d found %dx%d, ignoring: %s\n", + x_expect, y_expect, ibuf_template->x, ibuf_template->y, splash_filepath); + } + IMB_freeImBuf(ibuf_template); + } + } + } #endif block = UI_block_begin(C, ar, "_popup", UI_EMBOSS); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 2d43c47679d..aaf77946412 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -77,6 +77,7 @@ #include "GPU_extensions.h" #include "GPU_init_exit.h" #include "GPU_glew.h" +#include "BLF_api.h" /* for assert */ #ifndef NDEBUG @@ -311,7 +312,7 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) if (tmpwin == NULL) do_exit = 1; - if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved) { + if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved && !G.background) { if (do_exit) { if (!GHOST_confirmQuit(win->ghostwin)) return; @@ -374,14 +375,39 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win) } } -static float wm_window_get_virtual_pixelsize(void) +static void wm_window_set_dpi(wmWindow *win) { - return ((U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1.0f : 2.0f); -} + int auto_dpi = GHOST_GetDPIHint(win->ghostwin); -float wm_window_pixelsize(wmWindow *win) -{ - return (GHOST_GetNativePixelSize(win->ghostwin) * wm_window_get_virtual_pixelsize()); + /* Lazily init UI scale size, preserving backwards compatibility by + * computing UI scale from ratio of previous DPI and auto DPI */ + if (U.ui_scale == 0) { + int virtual_pixel = (U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1 : 2; + + if (U.dpi == 0) { + U.ui_scale = virtual_pixel; + } + else { + U.ui_scale = (virtual_pixel * U.dpi * 96.0f) / (auto_dpi * 72.0f); + } + + CLAMP(U.ui_scale, 0.25f, 4.0f); + } + + /* 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. */ + 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); + + /* Set user preferences globals for drawing, and for forward compatibility. */ + U.pixelsize = GHOST_GetNativePixelSize(win->ghostwin) * pixelsize; + U.dpi = dpi / pixelsize; + U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE; + + BKE_blender_userdef_refresh(); } /* belongs to below */ @@ -456,10 +482,8 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm glClear(GL_COLOR_BUFFER_BIT); } - /* displays with larger native pixels, like Macbook. Used to scale dpi with */ /* needed here, because it's used before it reads userdef */ - U.pixelsize = wm_window_pixelsize(win); - BKE_blender_userdef_refresh(); + wm_window_set_dpi(win); wm_window_swap_buffers(win); @@ -626,7 +650,6 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type) Scene *scene = CTX_data_scene(C); const char *title; rcti rect = *rect_init; - const short px_virtual = (short)wm_window_get_virtual_pixelsize(); /* changes rect to fit within desktop */ wm_window_check_position(&rect); @@ -644,9 +667,8 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type) win->posy = rect.ymin; } - /* multiply with virtual pixelsize, ghost handles native one (e.g. for retina) */ - win->sizex = BLI_rcti_size_x(&rect) * px_virtual; - win->sizey = BLI_rcti_size_y(&rect) * px_virtual; + win->sizex = BLI_rcti_size_x(&rect); + win->sizey = BLI_rcti_size_y(&rect); if (win->ghostwin) { wm_window_set_size(win, win->sizex, win->sizey); @@ -835,8 +857,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) GHOST_ActivateWindowDrawingContext(win->ghostwin); /* this can change per window */ - U.pixelsize = wm_window_pixelsize(win); - BKE_blender_userdef_refresh(); + wm_window_set_dpi(win); } } @@ -1035,6 +1056,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr if (type == GHOST_kEventWindowSize) { WM_jobs_stop(wm, win->screen, NULL); } + + wm_window_set_dpi(win); /* win32: gives undefined window size when minimized */ if (state != GHOST_kWindowStateMinimized) { @@ -1118,7 +1141,19 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr } break; } - + + case GHOST_kEventWindowDPIHintChanged: + { + wm_window_set_dpi(win); + /* font's are stored at each DPI level, without this we can easy load 100's of fonts */ + BLF_cache_clear(); + + BKE_blender_userdef_refresh(); + WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */ + WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */ + break; + } + case GHOST_kEventOpenMainFile: { PointerRNA props_ptr; @@ -1199,11 +1234,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr { // only update if the actual pixel size changes float prev_pixelsize = U.pixelsize; - U.pixelsize = wm_window_pixelsize(win); + wm_window_set_dpi(win); if (U.pixelsize != prev_pixelsize) { - BKE_blender_userdef_refresh(); - // close all popups since they are positioned with the pixel // size baked in and it's difficult to correct them wmWindow *oldWindow = CTX_wm_window(C); diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index 954d35722f3..9a1518e15b0 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -37,7 +37,8 @@ struct wmOperatorType; void wm_history_file_read(void); int wm_homefile_read( struct bContext *C, struct ReportList *reports, - bool from_memory, const char *filepath_startup_override); + bool use_factory_settings, bool use_empty_data, + const char *filepath_startup_override, const char *app_template_override); void wm_file_read_report(bContext *C); void WM_OT_save_homefile(struct wmOperatorType *ot); diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index c106f9d7851..f70ec6b47f6 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -63,8 +63,6 @@ void wm_window_swap_buffers (wmWindow *win); void wm_window_set_swap_interval(wmWindow *win, int interval); bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut); -float wm_window_pixelsize(wmWindow *win); - void wm_get_cursor_position (wmWindow *win, int *x, int *y); void wm_cursor_position_from_ghost (wmWindow *win, int *x, int *y); void wm_cursor_position_to_ghost (wmWindow *win, int *x, int *y); diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 0b1b264c3fc..42fce22e148 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -199,6 +199,7 @@ extern bool pyrna_id_FromPyObject(struct PyObject *obj, struct ID **id); extern const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid); extern const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid); extern struct PyObject *pyrna_id_CreatePyObject(struct ID *id); +extern bool pyrna_id_CheckPyObject(struct PyObject *obj); /* bpy_interface.c */ bool BPY_string_is_keyword(const char *str) { return false; } @@ -273,6 +274,8 @@ 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 const float (*RE_render_current_get_matrix(int matrix_id))[4] RET_NULL +float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi) RET_ZERO +float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi) RET_ZERO /* blenkernel */ bool BKE_paint_proj_mesh_data_check(struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil) RET_ZERO @@ -740,7 +743,9 @@ int collada_export(struct Scene *sce, int use_blender_profile, int sort_by_name, BC_export_transformation_type export_transformation_type, - int open_sim) RET_ZERO + int open_sim, + int limit_precision, + int keep_bind_info) RET_ZERO void ED_mesh_calc_tessface(struct Mesh *mesh, bool free_mpoly) RET_NONE @@ -756,6 +761,7 @@ void BPY_pyconstraint_exec(struct bPythonConstraint *con, struct bConstraintOb * void macro_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE bool pyrna_id_FromPyObject(struct PyObject *obj, struct ID **id) RET_ZERO struct PyObject *pyrna_id_CreatePyObject(struct ID *id) RET_NULL +bool pyrna_id_CheckPyObject(struct PyObject *obj) RET_ZERO void BPY_context_update(struct bContext *C) RET_NONE const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid) RET_ARG(msgid) diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp index 95679b5d3a6..9cbd61590b6 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.cpp +++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp @@ -169,7 +169,7 @@ void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) rasty->GetViewMatrix().getValue(&viewmat[0][0]); float auto_bump_scale = ms.m_pDerivedMesh!=0 ? ms.m_pDerivedMesh->auto_bump_scale : 1.0f; - GPU_material_bind_uniforms(gpumat, obmat, viewmat, obcol, auto_bump_scale, NULL); + GPU_material_bind_uniforms(gpumat, obmat, viewmat, obcol, auto_bump_scale, NULL, NULL); mAlphaBlend = GPU_material_alpha_blend(gpumat, obcol); } diff --git a/tests/gtests/CMakeLists.txt b/tests/gtests/CMakeLists.txt index 1d363f31119..ad77b1389f6 100644 --- a/tests/gtests/CMakeLists.txt +++ b/tests/gtests/CMakeLists.txt @@ -14,5 +14,7 @@ if(WITH_GTESTS) add_subdirectory(blenlib) add_subdirectory(guardedalloc) add_subdirectory(bmesh) + if(WITH_ALEMBIC) + add_subdirectory(alembic) + endif() endif() - diff --git a/tests/gtests/alembic/CMakeLists.txt b/tests/gtests/alembic/CMakeLists.txt new file mode 100644 index 00000000000..c1480910d42 --- /dev/null +++ b/tests/gtests/alembic/CMakeLists.txt @@ -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. +# +# The Original Code is Copyright (C) 2014, Blender Foundation +# All rights reserved. +# +# Contributor(s): Sybren A. Stüvel +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + .. + ../../../source/blender/blenlib + ../../../source/blender/alembic + ${ALEMBIC_INCLUDE_DIRS} + ${BOOST_INCLUDE_DIR} + ${HDF5_INCLUDE_DIRS} + ${OPENEXR_INCLUDE_DIRS} +) + +include_directories(${INC}) + +setup_libdirs() +get_property(BLENDER_SORTED_LIBS GLOBAL PROPERTY BLENDER_SORTED_LIBS_PROP) + +if(WITH_BUILDINFO) + set(_buildinfo_src "$<TARGET_OBJECTS:buildinfoobj>") +else() + set(_buildinfo_src "") +endif() + +# For motivation on doubling BLENDER_SORTED_LIBS, see ../bmesh/CMakeLists.txt +BLENDER_SRC_GTEST(abc_matrix "abc_matrix_test.cc;${_buildinfo_src}" "${BLENDER_SORTED_LIBS};${BLENDER_SORTED_LIBS}") + +unset(_buildinfo_src) + +setup_liblinks(abc_matrix_test) diff --git a/tests/gtests/alembic/abc_matrix_test.cc b/tests/gtests/alembic/abc_matrix_test.cc new file mode 100644 index 00000000000..08bce1ed50f --- /dev/null +++ b/tests/gtests/alembic/abc_matrix_test.cc @@ -0,0 +1,282 @@ +#include "testing/testing.h" + +// Keep first since utildefines defines AT which conflicts with fucking STL +#include "intern/abc_util.h" + +extern "C" { +#include "BLI_utildefines.h" +#include "BLI_math.h" +} + + +TEST(abc_matrix, CreateRotationMatrixY_YfromZ) { + // Input variables + float rot_x_mat[3][3]; + float rot_y_mat[3][3]; + float rot_z_mat[3][3]; + float euler[3] = {0.f, M_PI_4, 0.f}; + + // Construct expected matrices + float unit[3][3]; + float rot_z_min_quart_pi[3][3]; // rotation of -pi/4 radians over z-axis + + unit_m3(unit); + unit_m3(rot_z_min_quart_pi); + rot_z_min_quart_pi[0][0] = M_SQRT1_2; + rot_z_min_quart_pi[0][1] = -M_SQRT1_2; + rot_z_min_quart_pi[1][0] = M_SQRT1_2; + rot_z_min_quart_pi[1][1] = M_SQRT1_2; + + // Run tests + create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, + ABC_YUP_FROM_ZUP); + + EXPECT_M3_NEAR(rot_x_mat, unit, 1e-5f); + EXPECT_M3_NEAR(rot_y_mat, unit, 1e-5f); + EXPECT_M3_NEAR(rot_z_mat, rot_z_min_quart_pi, 1e-5f); +} + +TEST(abc_matrix, CreateRotationMatrixZ_YfromZ) { + // Input variables + float rot_x_mat[3][3]; + float rot_y_mat[3][3]; + float rot_z_mat[3][3]; + float euler[3] = {0.f, 0.f, M_PI_4}; + + // Construct expected matrices + float unit[3][3]; + float rot_y_quart_pi[3][3]; // rotation of pi/4 radians over y-axis + + unit_m3(unit); + unit_m3(rot_y_quart_pi); + rot_y_quart_pi[0][0] = M_SQRT1_2; + rot_y_quart_pi[0][2] = -M_SQRT1_2; + rot_y_quart_pi[2][0] = M_SQRT1_2; + rot_y_quart_pi[2][2] = M_SQRT1_2; + + // Run tests + create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, + ABC_YUP_FROM_ZUP); + + EXPECT_M3_NEAR(rot_x_mat, unit, 1e-5f); + EXPECT_M3_NEAR(rot_y_mat, rot_y_quart_pi, 1e-5f); + EXPECT_M3_NEAR(rot_z_mat, unit, 1e-5f); +} + +TEST(abc_matrix, CreateRotationMatrixXYZ_YfromZ) { + // Input variables + float rot_x_mat[3][3]; + float rot_y_mat[3][3]; + float rot_z_mat[3][3]; + // in degrees: X=10, Y=20, Z=30 + float euler[3] = {0.17453292012214f, 0.34906581044197f, 0.52359879016876f}; + + // Construct expected matrices + float rot_x_p10[3][3]; // rotation of +10 degrees over x-axis + float rot_y_p30[3][3]; // rotation of +30 degrees over y-axis + float rot_z_m20[3][3]; // rotation of -20 degrees over z-axis + + unit_m3(rot_x_p10); + rot_x_p10[1][1] = 0.9848077297210693f; + rot_x_p10[1][2] = 0.1736481785774231f; + rot_x_p10[2][1] = -0.1736481785774231f; + rot_x_p10[2][2] = 0.9848077297210693f; + + unit_m3(rot_y_p30); + rot_y_p30[0][0] = 0.8660253882408142f; + rot_y_p30[0][2] = -0.5f; + rot_y_p30[2][0] = 0.5f; + rot_y_p30[2][2] = 0.8660253882408142f; + + unit_m3(rot_z_m20); + rot_z_m20[0][0] = 0.9396926164627075f; + rot_z_m20[0][1] = -0.3420201241970062f; + rot_z_m20[1][0] = 0.3420201241970062f; + rot_z_m20[1][1] = 0.9396926164627075f; + + // Run tests + create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, + ABC_YUP_FROM_ZUP); + + EXPECT_M3_NEAR(rot_x_mat, rot_x_p10, 1e-5f); + EXPECT_M3_NEAR(rot_y_mat, rot_y_p30, 1e-5f); + EXPECT_M3_NEAR(rot_z_mat, rot_z_m20, 1e-5f); +} + +TEST(abc_matrix, CreateRotationMatrixXYZ_ZfromY) { + // Input variables + float rot_x_mat[3][3]; + float rot_y_mat[3][3]; + float rot_z_mat[3][3]; + // in degrees: X=10, Y=20, Z=30 + float euler[3] = {0.1745329201221466f, 0.3490658104419708f, 0.5235987901687622f}; + + // Construct expected matrices + float rot_x_p10[3][3]; // rotation of +10 degrees over x-axis + float rot_y_m30[3][3]; // rotation of -30 degrees over y-axis + float rot_z_p20[3][3]; // rotation of +20 degrees over z-axis + + unit_m3(rot_x_p10); + rot_x_p10[1][1] = 0.9848077297210693f; + rot_x_p10[1][2] = 0.1736481785774231f; + rot_x_p10[2][1] = -0.1736481785774231f; + rot_x_p10[2][2] = 0.9848077297210693f; + + unit_m3(rot_y_m30); + rot_y_m30[0][0] = 0.8660253882408142f; + rot_y_m30[0][2] = 0.5f; + rot_y_m30[2][0] = -0.5f; + rot_y_m30[2][2] = 0.8660253882408142f; + + unit_m3(rot_z_p20); + rot_z_p20[0][0] = 0.9396926164627075f; + rot_z_p20[0][1] = 0.3420201241970062f; + rot_z_p20[1][0] = -0.3420201241970062f; + rot_z_p20[1][1] = 0.9396926164627075f; + + // Run tests + create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, + ABC_ZUP_FROM_YUP); + + EXPECT_M3_NEAR(rot_x_mat, rot_x_p10, 1e-5f); + EXPECT_M3_NEAR(rot_y_mat, rot_y_m30, 1e-5f); + EXPECT_M3_NEAR(rot_z_mat, rot_z_p20, 1e-5f); +} + +TEST(abc_matrix, CopyM44AxisSwap_YfromZ) { + float result[4][4]; + + /* Construct an input matrix that performs a rotation like the tests + * above. This matrix was created by rotating a cube in Blender over + * (X=10, Y=20, Z=30 degrees in XYZ order) and translating over (1, 2, 3) */ + float input[4][4] = { + { 0.81379765272f, 0.4698463380336f, -0.342020124197f, 0.f}, + {-0.44096961617f, 0.8825641274452f, 0.163175910711f, 0.f}, + { 0.37852230668f, 0.0180283170193f, 0.925416588783f, 0.f}, + {1.f, 2.f, 3.f, 1.f}, + }; + + copy_m44_axis_swap(result, input, ABC_YUP_FROM_ZUP); + + /* Check the resulting rotation & translation. */ + float trans[4] = {1.f, 3.f, -2.f, 1.f}; + EXPECT_V4_NEAR(trans, result[3], 1e-5f); + + /* This matrix was created by rotating a cube in Blender over + * (X=10, Y=30, Z=-20 degrees in XZY order) and translating over (1, 3, -2) */ + float expect[4][4] = { + {0.813797652721f, -0.342020124197f, -0.469846338033f, 0.f}, + {0.378522306680f, 0.925416588783f, -0.018028317019f, 0.f}, + {0.440969616174f, -0.163175910711f, 0.882564127445f, 0.f}, + {1.f, 3.f, -2.f, 1.f}, + }; + EXPECT_M4_NEAR(expect, result, 1e-5f); +} + +TEST(abc_matrix, CopyM44AxisSwapWithScale_YfromZ) { + float result[4][4]; + + /* Construct an input matrix that performs a rotation like the tests + * above. This matrix was created by rotating a cube in Blender over + * (X=10, Y=20, Z=30 degrees in XYZ order), translating over (1, 2, 3), + * and scaling by (4, 5, 6). */ + float input[4][4] = { + { 3.25519061088f, 1.8793853521347f, -1.368080496788f, 0.f}, + {-2.20484805107f, 4.4128208160400f, 0.815879583358f, 0.f}, + { 2.27113389968f, 0.1081698983907f, 5.552499771118f, 0.f}, + {1.f, 2.f, 3.f, 1.f}, + }; + + copy_m44_axis_swap(result, input, ABC_YUP_FROM_ZUP); + + /* This matrix was created by rotating a cube in Blender over + * (X=10, Y=30, Z=-20 degrees in XZY order), translating over (1, 3, -2) + * and scaling over (4, 6, 5). */ + float expect[4][4] = { + {3.255190610885f, -1.368080496788f, -1.879385352134f, 0.f}, + {2.271133899688f, 5.552499771118f, -0.108169898390f, 0.f}, + {2.204848051071f, -0.815879583358f, 4.412820816040f, 0.f}, + {1.f, 3.f, -2.f, 1.f}, + }; + EXPECT_M4_NEAR(expect, result, 1e-5f); +} + +TEST(abc_matrix, CopyM44AxisSwap_ZfromY) { + float result[4][4]; + + /* This matrix was created by rotating a cube in Blender over + * (X=10, Y=30, Z=-20 degrees in XZY order) and translating over (1, 3, -2) */ + float input[4][4] = { + {0.813797652721f, -0.342020124197f, -0.469846338033f, 0.f}, + {0.378522306680f, 0.925416588783f, -0.018028317019f, 0.f}, + {0.440969616174f, -0.163175910711f, 0.882564127445f, 0.f}, + {1.f, 3.f, -2.f, 1.f}, + }; + + copy_m44_axis_swap(result, input, ABC_ZUP_FROM_YUP); + + /* This matrix was created by rotating a cube in Blender over + * (X=10, Y=20, Z=30 degrees in XYZ order) and translating over (1, 2, 3) */ + float expect[4][4] = { + {0.813797652721f, 0.469846338033f, -0.342020124197f, 0.f}, + {-0.44096961617f, 0.882564127445f, 0.163175910711f, 0.f}, + {0.378522306680f, 0.018028317019f, 0.925416588783f, 0.f}, + {1.f, 2.f, 3.f, 1.f}, + }; + + EXPECT_M4_NEAR(expect, result, 1e-5f); +} + +TEST(abc_matrix, CopyM44AxisSwapWithScale_ZfromY) { + float result[4][4]; + + /* This matrix was created by rotating a cube in Blender over + * (X=10, Y=30, Z=-20 degrees in XZY order), translating over (1, 3, -2) + * and scaling over (4, 6, 5). */ + float input[4][4] = { + {3.2551906108f, -1.36808049678f, -1.879385352134f, 0.f}, + {2.2711338996f, 5.55249977111f, -0.108169898390f, 0.f}, + {2.2048480510f, -0.81587958335f, 4.412820816040f, 0.f}, + {1.f, 3.f, -2.f, 1.f}, + }; + + copy_m44_axis_swap(result, input, ABC_ZUP_FROM_YUP); + + /* This matrix was created by rotating a cube in Blender over + * (X=10, Y=20, Z=30 degrees in XYZ order), translating over (1, 2, 3), + * and scaling by (4, 5, 6). */ + float expect[4][4] = { + {3.25519061088f, 1.879385352134f, -1.36808049678f, 0.f}, + {-2.2048480510f, 4.412820816040f, 0.81587958335f, 0.f}, + {2.27113389968f, 0.108169898390f, 5.55249977111f, 0.f}, + {1.f, 2.f, 3.f, 1.f}, + }; + + EXPECT_M4_NEAR(expect, result, 1e-5f); +} + +TEST(abc_matrix, CopyM44AxisSwapWithScale_gimbal_ZfromY) { + float result[4][4]; + + /* This matrix represents a rotation over (-90, -0, -0) degrees, + * and a translation over (-0, -0.1, -0). It is in Y=up. */ + float input[4][4] = { + { 1.000f, 0.000f, 0.000f, 0.000f}, + { 0.000f, 0.000f,-1.000f, 0.000f}, + { 0.000f, 1.000f, 0.000f, 0.000f}, + {-0.000f,-0.100f,-0.000f, 1.000f}, + }; + + copy_m44_axis_swap(result, input, ABC_ZUP_FROM_YUP); + + /* Since the rotation is only over the X-axis, it should not change. + * The translation does change. */ + float expect[4][4] = { + { 1.000f, 0.000f, 0.000f, 0.000f}, + { 0.000f, 0.000f,-1.000f, 0.000f}, + { 0.000f, 1.000f, 0.000f, 0.000f}, + {-0.000f, 0.000f,-0.100f, 1.000f}, + }; + + EXPECT_M4_NEAR(expect, result, 1e-5f); +} diff --git a/tests/gtests/blenlib/BLI_path_util_test.cc b/tests/gtests/blenlib/BLI_path_util_test.cc index d017ab18b4d..ef469da50b2 100644 --- a/tests/gtests/blenlib/BLI_path_util_test.cc +++ b/tests/gtests/blenlib/BLI_path_util_test.cc @@ -5,6 +5,7 @@ extern "C" { #include "BLI_fileops.h" #include "BLI_path_util.h" +#include "BLI_string.h" #include "../../../source/blender/imbuf/IMB_imbuf.h" #ifdef _WIN32 @@ -57,7 +58,7 @@ char *zLhm65070058860608_br_find_exe(const char *default_exe) /* BLI_cleanup_path */ #ifndef _WIN32 -TEST(path_util, PathUtilClean) +TEST(path_util, Clean) { /* "/./" -> "/" */ { @@ -113,8 +114,238 @@ TEST(path_util, PathUtilClean) } #endif + +#define AT_INDEX(str_input, index_input, str_expect) \ + { \ + char path[] = str_input; \ + const char *expect = str_expect; \ + int index_output, len_output; \ + const bool ret = BLI_path_name_at_index(path, index_input, &index_output, &len_output); \ + if (expect == NULL) { \ + EXPECT_EQ(ret, false); \ + } \ + else { \ + EXPECT_EQ(ret, true); \ + EXPECT_EQ(strlen(expect), len_output); \ + path[index_output + len_output] = '\0'; \ + EXPECT_STREQ(&path[index_output], expect); \ + } \ + }((void)0) + +/* BLI_path_name_at_index */ +TEST(path_util, NameAtIndex_Single) +{ + AT_INDEX("/a", 0, "a"); + AT_INDEX("/a/", 0, "a"); + AT_INDEX("a/", 0, "a"); + AT_INDEX("//a//", 0, "a"); + AT_INDEX("a/b", 0, "a"); + + AT_INDEX("/a", 1, NULL); + AT_INDEX("/a/", 1, NULL); + AT_INDEX("a/", 1, NULL); + AT_INDEX("//a//", 1, NULL); +} +TEST(path_util, NameAtIndex_SingleNeg) +{ + AT_INDEX("/a", -1, "a"); + AT_INDEX("/a/", -1, "a"); + AT_INDEX("a/", -1, "a"); + AT_INDEX("//a//", -1, "a"); + AT_INDEX("a/b", -1, "b"); + + AT_INDEX("/a", -2, NULL); + AT_INDEX("/a/", -2, NULL); + AT_INDEX("a/", -2, NULL); + AT_INDEX("//a//", -2, NULL); +} + +TEST(path_util, NameAtIndex_Double) +{ + AT_INDEX("/ab", 0, "ab"); + AT_INDEX("/ab/", 0, "ab"); + AT_INDEX("ab/", 0, "ab"); + AT_INDEX("//ab//", 0, "ab"); + AT_INDEX("ab/c", 0, "ab"); + + AT_INDEX("/ab", 1, NULL); + AT_INDEX("/ab/", 1, NULL); + AT_INDEX("ab/", 1, NULL); + AT_INDEX("//ab//", 1, NULL); +} + +TEST(path_util, NameAtIndex_DoublNeg) +{ + AT_INDEX("/ab", -1, "ab"); + AT_INDEX("/ab/", -1, "ab"); + AT_INDEX("ab/", -1, "ab"); + AT_INDEX("//ab//", -1, "ab"); + AT_INDEX("ab/c", -1, "c"); + + AT_INDEX("/ab", -2, NULL); + AT_INDEX("/ab/", -2, NULL); + AT_INDEX("ab/", -2, NULL); + AT_INDEX("//ab//", -2, NULL); +} + +TEST(path_util, NameAtIndex_Misc) +{ + AT_INDEX("/how/now/brown/cow", 0, "how"); + AT_INDEX("/how/now/brown/cow", 1, "now"); + AT_INDEX("/how/now/brown/cow", 2, "brown"); + AT_INDEX("/how/now/brown/cow", 3, "cow"); + AT_INDEX("/how/now/brown/cow", 4, NULL); + AT_INDEX("/how/now/brown/cow/", 4, NULL); +} + +TEST(path_util, NameAtIndex_MiscNeg) +{ + AT_INDEX("/how/now/brown/cow", 0, "how"); + AT_INDEX("/how/now/brown/cow", 1, "now"); + AT_INDEX("/how/now/brown/cow", 2, "brown"); + AT_INDEX("/how/now/brown/cow", 3, "cow"); + AT_INDEX("/how/now/brown/cow", 4, NULL); + AT_INDEX("/how/now/brown/cow/", 4, NULL); +} + +TEST(path_util, NameAtIndex_MiscComplex) +{ + AT_INDEX("how//now/brown/cow", 0, "how"); + AT_INDEX("//how///now\\/brown/cow", 1, "now"); + AT_INDEX("/how/now\\//brown\\/cow", 2, "brown"); + AT_INDEX("/how/now/brown/cow//\\", 3, "cow"); + AT_INDEX("/how/now/brown/\\cow", 4, NULL); + AT_INDEX("how/now/brown/\\cow\\", 4, NULL); +} + +TEST(path_util, NameAtIndex_MiscComplexNeg) +{ + AT_INDEX("how//now/brown/cow", -4, "how"); + AT_INDEX("//how///now\\/brown/cow", -3, "now"); + AT_INDEX("/how/now\\//brown\\/cow", -2, "brown"); + AT_INDEX("/how/now/brown/cow//\\", -1, "cow"); + AT_INDEX("/how/now/brown/\\cow", -5, NULL); + AT_INDEX("how/now/brown/\\cow\\", -5, NULL); +} + +TEST(path_util, NameAtIndex_NoneComplex) +{ + AT_INDEX("", 0, NULL); + AT_INDEX("/", 0, NULL); + AT_INDEX("//", 0, NULL); + AT_INDEX("///", 0, NULL); +} + +TEST(path_util, NameAtIndex_NoneComplexNeg) +{ + AT_INDEX("", -1, NULL); + AT_INDEX("/", -1, NULL); + AT_INDEX("//", -1, NULL); + AT_INDEX("///", -1, NULL); +} + +#undef AT_INDEX + +#define JOIN(str_expect, out_size, ...) \ + { \ + const char *expect = str_expect; \ + char result[(out_size) + 1024]; \ + /* check we don't write past the last byte */ \ + result[out_size] = '\0'; \ + BLI_path_join(result, out_size, __VA_ARGS__, NULL); \ + /* simplify expected string */ \ + BLI_str_replace_char(result, '\\', '/'); \ + EXPECT_STREQ(result, expect); \ + EXPECT_EQ(result[out_size], '\0'); \ + } ((void)0) + +/* BLI_path_join */ +TEST(path_util, JoinNop) +{ + JOIN("", 100, ""); + JOIN("", 100, "", ""); + JOIN("", 100, "", "", ""); + JOIN("/", 100, "/", "", ""); + JOIN("/", 100, "/", "/"); + JOIN("/", 100, "/", "", "/"); + JOIN("/", 100, "/", "", "/", ""); +} + +TEST(path_util, JoinSingle) +{ + JOIN("test", 100, "test"); + JOIN("", 100, ""); + JOIN("a", 100, "a"); + JOIN("/a", 100, "/a"); + JOIN("a/", 100, "a/"); + JOIN("/a/", 100, "/a/"); + JOIN("/a/", 100, "/a//"); + JOIN("//a/", 100, "//a//"); +} + +TEST(path_util, JoinTriple) +{ + JOIN("/a/b/c", 100, "/a", "b", "c"); + JOIN("/a/b/c", 100, "/a/", "/b/", "/c"); + JOIN("/a/b/c", 100, "/a/b/", "/c"); + JOIN("/a/b/c", 100, "/a/b/c"); + JOIN("/a/b/c", 100, "/", "a/b/c"); + + JOIN("/a/b/c/", 100, "/a/", "/b/", "/c/"); + JOIN("/a/b/c/", 100, "/a/b/c/"); + JOIN("/a/b/c/", 100, "/a/b/", "/c/"); + JOIN("/a/b/c/", 100, "/a/b/c", "/"); + JOIN("/a/b/c/", 100, "/", "a/b/c", "/"); +} + +TEST(path_util, JoinTruncateShort) +{ + JOIN("", 1, "/"); + JOIN("/", 2, "/"); + JOIN("a", 2, "", "aa"); + JOIN("a", 2, "", "a/"); + JOIN("a/b", 4, "a", "bc"); + JOIN("ab/", 4, "ab", "c"); + JOIN("/a/", 4, "/a", "b"); + JOIN("/a/", 4, "/a/", "b/"); + JOIN("/a/", 4, "/a", "/b/"); + JOIN("/a/", 4, "/", "a/b/"); + JOIN("//a", 4, "//", "a/b/"); + + JOIN("/a/b", 5, "/a", "b", "c"); +} + +TEST(path_util, JoinTruncateLong) +{ + JOIN("", 1, "//", "//longer", "path"); + JOIN("/", 2, "//", "//longer", "path"); + JOIN("//", 3, "//", "//longer", "path"); + JOIN("//l", 4, "//", "//longer", "path"); + /* snip */ + JOIN("//longe", 8, "//", "//longer", "path"); + JOIN("//longer", 9, "//", "//longer", "path"); + JOIN("//longer/", 10, "//", "//longer", "path"); + JOIN("//longer/p", 11, "//", "//longer", "path"); + JOIN("//longer/pa", 12, "//", "//longer", "path"); + JOIN("//longer/pat", 13, "//", "//longer", "path"); + JOIN("//longer/path", 14, "//", "//longer", "path"); // not truncated + JOIN("//longer/path", 14, "//", "//longer", "path/"); + JOIN("//longer/path/", 15, "//", "//longer", "path/"); // not truncated + JOIN("//longer/path/", 15, "//", "//longer", "path/", "trunc"); + JOIN("//longer/path/t", 16, "//", "//longer", "path/", "trunc"); +} + +TEST(path_util, JoinComplex) +{ + JOIN("/a/b/c/d/e/f/g/", 100, "/", "\\a/b", "//////c/d", "", "e\\\\", "f", "g//"); + JOIN("/aa/bb/cc/dd/ee/ff/gg/", 100, "/", "\\aa/bb", "//////cc/dd", "", "ee\\\\", "ff", "gg//"); + JOIN("1/2/3/", 100, "1", "////////", "", "2", "3\\"); +} + +#undef JOIN + /* BLI_path_frame */ -TEST(path_util, PathUtilFrame) +TEST(path_util, Frame) { bool ret; @@ -177,7 +408,7 @@ TEST(path_util, PathUtilFrame) } /* BLI_split_dirfile */ -TEST(path_util, PathUtilSplitDirfile) +TEST(path_util, SplitDirfile) { { const char *path = ""; diff --git a/tests/gtests/testing/testing.h b/tests/gtests/testing/testing.h index 1594ed3926c..d5a7b076970 100644 --- a/tests/gtests/testing/testing.h +++ b/tests/gtests/testing/testing.h @@ -12,6 +12,29 @@ EXPECT_NEAR(a[2], b[2], eps); \ } (void) 0 +#define EXPECT_V4_NEAR(a, b, eps) \ +{ \ + EXPECT_NEAR(a[0], b[0], eps); \ + EXPECT_NEAR(a[1], b[1], eps); \ + EXPECT_NEAR(a[2], b[2], eps); \ + EXPECT_NEAR(a[3], b[3], eps); \ + } (void) 0 + +#define EXPECT_M3_NEAR(a, b, eps) \ +do { \ + EXPECT_V3_NEAR(a[0], b[0], eps); \ + EXPECT_V3_NEAR(a[1], b[1], eps); \ + EXPECT_V3_NEAR(a[2], b[2], eps); \ +} while(false); + +#define EXPECT_M4_NEAR(a, b, eps) \ +do { \ + EXPECT_V3_NEAR(a[0], b[0], eps); \ + EXPECT_V3_NEAR(a[1], b[1], eps); \ + EXPECT_V3_NEAR(a[2], b[2], eps); \ + EXPECT_V4_NEAR(a[3], b[3], eps); \ +} while(false); + #define EXPECT_MATRIX_NEAR(a, b, tolerance) \ do { \ bool dims_match = (a.rows() == b.rows()) && (a.cols() == b.cols()); \ diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index f7ca9b02137..8ff2f77c38e 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -91,6 +91,10 @@ add_test(script_pyapi_idprop ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_idprop.py ) +add_test(script_pyapi_idprop_datablock ${TEST_BLENDER_EXE} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_idprop_datablock.py +) + # ------------------------------------------------------------------------------ # MODELING TESTS add_test(bevel ${TEST_BLENDER_EXE} @@ -438,3 +442,23 @@ if(WITH_CYCLES) MESSAGE(STATUS "Disabling Cycles tests because tests folder does not exist") endif() endif() + +if(WITH_ALEMBIC) + if(MSVC) + 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}/alembic_tests.py + --blender "${TEST_BLENDER_EXE_BARE}" + --testdir "${TEST_SRC_DIR}/alembic" + --alembic-root "${ALEMBIC_ROOT_DIR}" + ) + else() + add_test(alembic_tests + ${CMAKE_CURRENT_LIST_DIR}/alembic_tests.py + --blender "${TEST_BLENDER_EXE_BARE}" + --testdir "${TEST_SRC_DIR}/alembic" + --alembic-root "${ALEMBIC_ROOT_DIR}" + ) + endif() +endif() diff --git a/tests/python/alembic_tests.py b/tests/python/alembic_tests.py new file mode 100755 index 00000000000..209b34a8634 --- /dev/null +++ b/tests/python/alembic_tests.py @@ -0,0 +1,266 @@ +#!/usr/bin/env python3 +# ##### 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 ##### + +# <pep8 compliant> + +import argparse +import functools +import shutil +import pathlib +import subprocess +import sys +import tempfile +import unittest + + +def with_tempdir(wrapped): + """Creates a temporary directory for the function, cleaning up after it returns normally. + + When the wrapped function raises an exception, the contents of the temporary directory + remain available for manual inspection. + + The wrapped function is called with an extra positional argument containing + the pathlib.Path() of the temporary directory. + """ + + @functools.wraps(wrapped) + def decorator(*args, **kwargs): + dirname = tempfile.mkdtemp(prefix='blender-alembic-test') + try: + retval = wrapped(*args, pathlib.Path(dirname), **kwargs) + except: + print('Exception in %s, not cleaning up temporary directory %s' % (wrapped, dirname)) + raise + else: + shutil.rmtree(dirname) + return retval + + return decorator + + +class AbstractAlembicTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + import re + + parser = argparse.ArgumentParser() + parser.add_argument('--blender', required=True) + parser.add_argument('--testdir', required=True) + parser.add_argument('--alembic-root', required=True) + args, _ = parser.parse_known_args() + + cls.blender = args.blender + cls.testdir = pathlib.Path(args.testdir) + cls.alembic_root = pathlib.Path(args.alembic_root) + + # 'abcls' outputs ANSI colour codes, even when stdout is not a terminal. + # See https://github.com/alembic/alembic/issues/120 + cls.ansi_remove_re = re.compile(rb'\x1b[^m]*m') + + # 'abcls' array notation, like "name[16]" + cls.abcls_array = re.compile(r'^(?P<name>[^\[]+)(\[(?P<arraysize>\d+)\])?$') + + def run_blender(self, filepath: str, python_script: str, timeout: int=300) -> str: + """Runs Blender by opening a blendfile and executing a script. + + Returns Blender's stdout + stderr combined into one string. + + :param filepath: taken relative to self.testdir. + :param timeout: in seconds + """ + + blendfile = self.testdir / filepath + + command = ( + self.blender, + '--background', + '-noaudio', + '--factory-startup', + '--enable-autoexec', + str(blendfile), + '-E', 'CYCLES', + '--python-exit-code', '47', + '--python-expr', python_script, + ) + + proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + timeout=timeout) + output = proc.stdout.decode('utf8') + if proc.returncode: + self.fail('Error %d running Blender:\n%s' % (proc.returncode, output)) + + return output + + def abcprop(self, filepath: pathlib.Path, proppath: str) -> dict: + """Uses abcls to obtain compound property values from an Alembic object. + + A dict of subproperties is returned, where the values are just strings + as returned by abcls. + + The Python bindings for Alembic are old, and only compatible with Python 2.x, + so that's why we can't use them here, and have to rely on other tooling. + """ + + abcls = self.alembic_root / 'bin' / 'abcls' + + command = (str(abcls), '-vl', '%s%s' % (filepath, proppath)) + proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + timeout=30) + + coloured_output = proc.stdout + output = self.ansi_remove_re.sub(b'', coloured_output).decode('utf8') + + if proc.returncode: + self.fail('Error %d running abcls:\n%s' % (proc.returncode, output)) + + # Mapping from value type to callable that can convert a string to Python values. + converters = { + 'bool_t': int, + 'uint8_t': int, + 'float64_t': float, + } + + result = {} + + # Ideally we'd get abcls to output JSON, see https://github.com/alembic/alembic/issues/121 + lines = output.split('\n') + for info, value in zip(lines[0::2], lines[1::2]): + proptype, valtype_and_arrsize, name_and_extent = info.split() + + # Parse name and extent + m = self.abcls_array.match(name_and_extent) + if not m: + self.fail('Unparsable name/extent from abcls: %s' % name_and_extent) + name, extent = m.group('name'), m.group('arraysize') + + if extent != '1': + self.fail('Unsupported extent %s for property %s/%s' % (extent, proppath, name)) + + # Parse type and convert values + m = self.abcls_array.match(valtype_and_arrsize) + if not m: + self.fail('Unparsable value type from abcls: %s' % valtype_and_arrsize) + valtype, arraysize = m.group('name'), m.group('arraysize') + + try: + conv = converters[valtype] + except KeyError: + self.fail('Unsupported type %s for property %s/%s' % (valtype, proppath, name)) + + if arraysize is None: + result[name] = conv(value) + else: + values = [conv(v.strip()) for v in value.split(',')] + result[name] = values + + return result + + def assertAlmostEqualFloatArray(self, actual, expect, places=6, delta=None): + """Asserts that the arrays of floats are almost equal.""" + + self.assertEqual(len(actual), len(expect), + 'Actual array has %d items, expected %d' % (len(actual), len(expect))) + + for idx, (act, exp) in enumerate(zip(actual, expect)): + self.assertAlmostEqual(act, exp, places=places, delta=delta, + msg='%f != %f at index %d' % (act, exp, idx)) + + +class HierarchicalAndFlatExportTest(AbstractAlembicTest): + @with_tempdir + def test_hierarchical_export(self, tempdir: pathlib.Path): + abc = tempdir / 'cubes_hierarchical.abc' + script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \ + "renderable_only=True, visible_layers_only=True, flatten=False)" % abc + self.run_blender('cubes-hierarchy.blend', script) + + # Now check the resulting Alembic file. + xform = self.abcprop(abc, '/Cube/Cube_002/Cube_012/.xform') + self.assertEqual(1, xform['.inherits']) + self.assertAlmostEqualFloatArray( + xform['.vals'], + [1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 3.07484, -2.92265, 0.0586434, 1.0] + ) + + @with_tempdir + def test_flat_export(self, tempdir: pathlib.Path): + abc = tempdir / 'cubes_flat.abc' + script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \ + "renderable_only=True, visible_layers_only=True, flatten=True)" % abc + self.run_blender('cubes-hierarchy.blend', script) + + # Now check the resulting Alembic file. + xform = self.abcprop(abc, '/Cube_012/.xform') + self.assertEqual(0, xform['.inherits']) + + self.assertAlmostEqualFloatArray( + xform['.vals'], + [0.343134, 0.485243, 0.804238, 0, + 0.0, 0.856222, -0.516608, 0, + -0.939287, 0.177266, 0.293799, 0, + 1, 3, 4, 1], + ) + + +class DupliGroupExportTest(AbstractAlembicTest): + @with_tempdir + def test_hierarchical_export(self, tempdir: pathlib.Path): + abc = tempdir / 'dupligroup_hierarchical.abc' + script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \ + "renderable_only=True, visible_layers_only=True, flatten=False)" % abc + self.run_blender('dupligroup-scene.blend', script) + + # Now check the resulting Alembic file. + xform = self.abcprop(abc, '/Real_Cube/Linked_Suzanne/Cylinder/Suzanne/.xform') + self.assertEqual(1, xform['.inherits']) + self.assertAlmostEqualFloatArray( + xform['.vals'], + [1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 2.0, 0.0, 1.0] + ) + + @with_tempdir + def test_flat_export(self, tempdir: pathlib.Path): + abc = tempdir / 'dupligroup_hierarchical.abc' + script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \ + "renderable_only=True, visible_layers_only=True, flatten=True)" % abc + self.run_blender('dupligroup-scene.blend', script) + + # Now check the resulting Alembic file. + xform = self.abcprop(abc, '/Suzanne/.xform') + self.assertEqual(0, xform['.inherits']) + + self.assertAlmostEqualFloatArray( + xform['.vals'], + [1.5, 0.0, 0.0, 0.0, + 0.0, 1.5, 0.0, 0.0, + 0.0, 0.0, 1.5, 0.0, + 2.0, 3.0, 0.0, 1.0] + ) + + + + +if __name__ == '__main__': + unittest.main(argv=sys.argv[0:1]) diff --git a/tests/python/batch_import.py b/tests/python/batch_import.py index 8fc679a7c15..bbe3a70327f 100644 --- a/tests/python/batch_import.py +++ b/tests/python/batch_import.py @@ -48,29 +48,17 @@ import os import sys -def clear_scene(): - import bpy - unique_obs = set() - for scene in bpy.data.scenes: - for obj in scene.objects[:]: - scene.objects.unlink(obj) - unique_obs.add(obj) - - # remove obdata, for now only worry about the startup scene - for bpy_data_iter in (bpy.data.objects, bpy.data.meshes, bpy.data.lamps, bpy.data.cameras): - for id_data in bpy_data_iter: - bpy_data_iter.remove(id_data) - - -def batch_import(operator="", - path="", - save_path="", - match="", - start=0, - end=sys.maxsize, - ): +def batch_import( + operator="", + path="", + save_path="", + match="", + start=0, + end=sys.maxsize, +): import addon_utils _reset_all = addon_utils.reset_all # XXX, hack + _disable_all = addon_utils.disable_all # XXX, hack import fnmatch @@ -116,11 +104,12 @@ def batch_import(operator="", # hack so loading the new file doesn't undo our loaded addons addon_utils.reset_all = lambda: None # XXX, hack + addon_utils.disable_all = lambda: None # XXX, hack - bpy.ops.wm.read_factory_settings() + bpy.ops.wm.read_factory_settings(use_empty=True) addon_utils.reset_all = _reset_all # XXX, hack - clear_scene() + addon_utils.disable_all = _disable_all # XXX, hack result = op(filepath=f) diff --git a/tests/python/bl_mesh_modifiers.py b/tests/python/bl_mesh_modifiers.py index 526a54a49a2..bff2c31984c 100644 --- a/tests/python/bl_mesh_modifiers.py +++ b/tests/python/bl_mesh_modifiers.py @@ -31,7 +31,6 @@ import math USE_QUICK_RENDER = False -IS_BMESH = hasattr(__import__("bpy").types, "LoopColors") # ----------------------------------------------------------------------------- # utility functions @@ -203,13 +202,8 @@ def defaults_object(obj): mesh.show_normal_vertex = True - # lame! - if IS_BMESH: - for poly in mesh.polygons: - poly.use_smooth = True - else: - for face in mesh.faces: - face.use_smooth = True + for poly in mesh.polygons: + poly.use_smooth = True def defaults_modifier(mod): @@ -220,16 +214,14 @@ def defaults_modifier(mod): # ----------------------------------------------------------------------------- # models (utils) +def mesh_bmesh_poly_elems(poly, elems): + vert_start = poly.loop_start + vert_total = poly.loop_total + return elems[vert_start:vert_start + vert_total] -if IS_BMESH: - def mesh_bmesh_poly_elems(poly, elems): - vert_start = poly.loop_start - vert_total = poly.loop_total - return elems[vert_start:vert_start + vert_total] - - def mesh_bmesh_poly_vertices(poly): - return [loop.vertex_index - for loop in mesh_bmesh_poly_elems(poly, poly.id_data.loops)] +def mesh_bmesh_poly_vertices(poly): + return [loop.vertex_index + for loop in mesh_bmesh_poly_elems(poly, poly.id_data.loops)] def mesh_bounds(mesh): @@ -258,21 +250,14 @@ def mesh_uv_add(obj): uv_lay = obj.data.uv_textures.new() - if IS_BMESH: - # XXX, odd that we need to do this. until UV's and texface - # are separated we will need to keep it - uv_loops = obj.data.uv_layers[-1] - uv_list = uv_loops.data[:] - for poly in obj.data.polygons: - poly_uvs = mesh_bmesh_poly_elems(poly, uv_list) - for i, c in enumerate(poly_uvs): - c.uv = uvs[i % 4] - else: - for uv in uv_lay.data: - uv.uv1 = uvs[0] - uv.uv2 = uvs[1] - uv.uv3 = uvs[2] - uv.uv4 = uvs[3] + # XXX, odd that we need to do this. until UV's and texface + # are separated we will need to keep it + uv_loops = obj.data.uv_layers[-1] + uv_list = uv_loops.data[:] + for poly in obj.data.polygons: + poly_uvs = mesh_bmesh_poly_elems(poly, uv_list) + for i, c in enumerate(poly_uvs): + c.uv = uvs[i % 4] return uv_lay @@ -296,21 +281,12 @@ def mesh_vcol_add(obj, mode=0): mesh = obj.data - if IS_BMESH: - col_list = vcol_lay.data[:] - for poly in mesh.polygons: - face_verts = mesh_bmesh_poly_vertices(poly) - poly_cols = mesh_bmesh_poly_elems(poly, col_list) - for i, c in enumerate(poly_cols): - c.color = colors_get(face_verts[i]) - else: - for i, col in enumerate(vcol_lay.data): - face_verts = mesh.faces[i].vertices - col.color1 = colors_get(face_verts[0]) - col.color2 = colors_get(face_verts[1]) - col.color3 = colors_get(face_verts[2]) - if len(face_verts) == 4: - col.color4 = colors_get(face_verts[3]) + col_list = vcol_lay.data[:] + for poly in mesh.polygons: + face_verts = mesh_bmesh_poly_vertices(poly) + poly_cols = mesh_bmesh_poly_elems(poly, col_list) + for i, c in enumerate(poly_cols): + c.color = colors_get(face_verts[i]) return vcol_lay @@ -470,10 +446,7 @@ def modifier_build_add(scene, obj): defaults_modifier(mod) # ensure we display some faces - if IS_BMESH: - totface = len(obj.data.polygons) - else: - totface = len(obj.data.faces) + totface = len(obj.data.polygons) mod.frame_start = totface // 2 mod.frame_duration = totface diff --git a/tests/python/bl_pyapi_idprop.py b/tests/python/bl_pyapi_idprop.py index 0a9cb044571..7bf68c16cc7 100644 --- a/tests/python/bl_pyapi_idprop.py +++ b/tests/python/bl_pyapi_idprop.py @@ -3,6 +3,7 @@ # ./blender.bin --background -noaudio --python tests/python/bl_pyapi_idprop.py -- --verbose import bpy import unittest +import numpy as np from array import array @@ -75,7 +76,7 @@ class TestIdPropertyCreation(TestHelper, unittest.TestCase): mylist = [1.2, 3.4, 5.6] self.id["a"] = array("f", mylist) self.assertAlmostEqualSeq(self.id["a"].to_list(), mylist) - self.assertEqual(self.id["a"].typecode, "d") + self.assertEqual(self.id["a"].typecode, "f") def test_sequence_double_array(self): mylist = [1.2, 3.4, 5.6] @@ -138,6 +139,65 @@ class TestIdPropertyCreation(TestHelper, unittest.TestCase): self.id["a"] = self +class TestBufferProtocol(TestHelper, unittest.TestCase): + + def test_int(self): + self.id["a"] = array("i", [1, 2, 3, 4, 5]) + a = np.frombuffer(self.id["a"], self.id["a"].typecode) + self.assertEqual(len(a), 5) + a[2] = 10 + self.assertEqual(self.id["a"].to_list(), [1, 2, 10, 4, 5]) + + def test_float(self): + self.id["a"] = array("f", [1.0, 2.0, 3.0, 4.0]) + a = np.frombuffer(self.id["a"], self.id["a"].typecode) + self.assertEqual(len(a), 4) + a[-1] = 10 + self.assertEqual(self.id["a"].to_list(), [1.0, 2.0, 3.0, 10.0]) + + def test_double(self): + self.id["a"] = array("d", [1.0, 2.0, 3.0, 4.0]) + a = np.frombuffer(self.id["a"], self.id["a"].typecode) + a[1] = 10 + self.assertEqual(self.id["a"].to_list(), [1.0, 10.0, 3.0, 4.0]) + + def test_full_update(self): + self.id["a"] = array("i", [1, 2, 3, 4, 5, 6]) + a = np.frombuffer(self.id["a"], self.id["a"].typecode) + a[:] = [10, 20, 30, 40, 50, 60] + self.assertEqual(self.id["a"].to_list(), [10, 20, 30, 40, 50, 60]) + + def test_partial_update(self): + self.id["a"] = array("i", [1, 2, 3, 4, 5, 6, 7, 8]) + a = np.frombuffer(self.id["a"], self.id["a"].typecode) + a[1:5] = [10, 20, 30, 40] + self.assertEqual(self.id["a"].to_list(), [1, 10, 20, 30, 40, 6, 7, 8]) + + def test_copy(self): + self.id["a"] = array("i", [1, 2, 3, 4, 5]) + self.id["b"] = self.id["a"] + self.assertEqual(self.id["a"].to_list(), self.id["b"].to_list()) + + def test_memview_attributes(self): + mylist = [1, 2, 3] + self.id["a"] = mylist + + view1 = memoryview(self.id["a"]) + view2 = memoryview(array("i", mylist)) + + self.assertEqualMemviews(view1, view2) + + def assertEqualMemviews(self, view1, view2): + props_to_compare = ( + "contiguous", "format", "itemsize", "nbytes", "ndim", + "readonly", "shape", "strides", "suboffsets" + ) + for attr in props_to_compare: + self.assertEqual(getattr(view1, attr), getattr(view2, attr)) + + self.assertEqual(list(view1), list(view2)) + self.assertEqual(view1.tobytes(), view2.tobytes()) + if __name__ == '__main__': import sys sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []) diff --git a/tests/python/bl_pyapi_idprop_datablock.py b/tests/python/bl_pyapi_idprop_datablock.py new file mode 100644 index 00000000000..4acfb83bd95 --- /dev/null +++ b/tests/python/bl_pyapi_idprop_datablock.py @@ -0,0 +1,338 @@ +# ##### 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 ##### + +import bpy +import sys +import os +import tempfile +import traceback +import inspect +from bpy.types import UIList + +arr_len = 100 +ob_cp_count = 100 +lib_path = os.path.join(tempfile.gettempdir(), "lib.blend") +test_path = os.path.join(tempfile.gettempdir(), "test.blend") + + +def print_fail_msg_and_exit(msg): + def __LINE__(): + try: + raise Exception + except: + return sys.exc_info()[2].tb_frame.f_back.f_back.f_back.f_lineno + + def __FILE__(): + return inspect.currentframe().f_code.co_filename + + print("'%s': %d >> %s" % (__FILE__(), __LINE__(), msg), file=sys.stderr) + sys.stderr.flush() + sys.stdout.flush() + os._exit(1) + + +def abort_if_false(expr, msg=None): + if not expr: + if not msg: + msg = "test failed" + print_fail_msg_and_exit(msg) + + +class TestClass(bpy.types.PropertyGroup): + test_prop = bpy.props.PointerProperty(type=bpy.types.Object) + name = bpy.props.StringProperty() + + +def get_scene(lib_name, sce_name): + for s in bpy.data.scenes: + if s.name == sce_name: + if (s.library and s.library.name == lib_name) or \ + (lib_name == None and s.library == None): + return s + + +def check_crash(fnc, args=None): + try: + fnc(args) if args else fnc() + except: + return + print_fail_msg_and_exit("test failed") + + +def init(): + bpy.utils.register_class(TestClass) + bpy.types.Object.prop_array = bpy.props.CollectionProperty( + name="prop_array", + type=TestClass) + bpy.types.Object.prop = bpy.props.PointerProperty(type=bpy.types.Object) + + +def make_lib(): + bpy.ops.wm.read_factory_settings() + + # datablock pointer to the Camera object + bpy.data.objects["Cube"].prop = bpy.data.objects['Camera'] + + # array of datablock pointers to the Lamp object + for i in range(0, arr_len): + a = bpy.data.objects["Cube"].prop_array.add() + a.test_prop = bpy.data.objects['Lamp'] + a.name = a.test_prop.name + + # make unique named copy of the cube + ob = bpy.data.objects["Cube"].copy() + bpy.context.scene.objects.link(ob) + + bpy.data.objects["Cube.001"].name = "Unique_Cube" + + # duplicating of Cube + for i in range(0, ob_cp_count): + ob = bpy.data.objects["Cube"].copy() + bpy.context.scene.objects.link(ob) + + # nodes + bpy.data.scenes["Scene"].use_nodes = True + bpy.data.scenes["Scene"].node_tree.nodes['Render Layers']["prop"] =\ + bpy.data.objects['Camera'] + + # rename scene and save + bpy.data.scenes["Scene"].name = "Scene_lib" + bpy.ops.wm.save_as_mainfile(filepath=lib_path) + + +def check_lib(): + # check pointer + abort_if_false(bpy.data.objects["Cube"].prop == bpy.data.objects['Camera']) + + # check array of pointers in duplicated object + for i in range(0, arr_len): + abort_if_false(bpy.data.objects["Cube.001"].prop_array[i].test_prop == + bpy.data.objects['Lamp']) + + +def check_lib_linking(): + # open startup file + bpy.ops.wm.read_factory_settings() + + # link scene to the startup file + with bpy.data.libraries.load(lib_path, link=True) as (data_from, data_to): + data_to.scenes = ["Scene_lib"] + + o = bpy.data.scenes["Scene_lib"].objects['Unique_Cube'] + + abort_if_false(o.prop_array[0].test_prop == bpy.data.scenes["Scene_lib"].objects['Lamp']) + abort_if_false(o.prop == bpy.data.scenes["Scene_lib"].objects['Camera']) + abort_if_false(o.prop.library == o.library) + + bpy.ops.wm.save_as_mainfile(filepath=test_path) + + +def check_linked_scene_copying(): + # full copy of the scene with datablock props + bpy.ops.wm.open_mainfile(filepath=test_path) + bpy.data.screens['Default'].scene = bpy.data.scenes["Scene_lib"] + bpy.ops.scene.new(type='FULL_COPY') + + # check save/open + bpy.ops.wm.save_as_mainfile(filepath=test_path) + bpy.ops.wm.open_mainfile(filepath=test_path) + + intern_sce = get_scene(None, "Scene_lib") + extern_sce = get_scene("Lib", "Scene_lib") + + # check node's props + # we made full copy from linked scene, so pointers must equal each other + abort_if_false(intern_sce.node_tree.nodes['Render Layers']["prop"] and + intern_sce.node_tree.nodes['Render Layers']["prop"] == + extern_sce.node_tree.nodes['Render Layers']["prop"]) + + +def check_scene_copying(): + # full copy of the scene with datablock props + bpy.ops.wm.open_mainfile(filepath=lib_path) + bpy.data.screens['Default'].scene = bpy.data.scenes["Scene_lib"] + bpy.ops.scene.new(type='FULL_COPY') + + path = test_path + "_" + # check save/open + bpy.ops.wm.save_as_mainfile(filepath=path) + bpy.ops.wm.open_mainfile(filepath=path) + + first_sce = get_scene(None, "Scene_lib") + second_sce = get_scene(None, "Scene_lib.001") + + # check node's props + # must point to own scene camera + abort_if_false(not (first_sce.node_tree.nodes['Render Layers']["prop"] == + second_sce.node_tree.nodes['Render Layers']["prop"])) + + +# count users +def test_users_counting(): + bpy.ops.wm.read_factory_settings() + lamp_us = bpy.data.objects["Lamp"].data.users + n = 1000 + for i in range(0, n): + bpy.data.objects["Cube"]["a%s" % i] = bpy.data.objects["Lamp"].data + abort_if_false(bpy.data.objects["Lamp"].data.users == lamp_us + n) + + for i in range(0, int(n / 2)): + bpy.data.objects["Cube"]["a%s" % i] = 1 + abort_if_false(bpy.data.objects["Lamp"].data.users == lamp_us + int(n / 2)) + + +# linking +def test_linking(): + make_lib() + check_lib() + check_lib_linking() + check_linked_scene_copying() + check_scene_copying() + + +# check restrictions for datablock pointers for some classes; GUI for manual testing +def test_restrictions1(): + class TEST_Op(bpy.types.Operator): + bl_idname = 'scene.test_op' + bl_label = 'Test' + bl_options = {"INTERNAL"} + str_prop = bpy.props.StringProperty(name="str_prop") + + # disallow registration of datablock properties in operators + # will be checked in the draw method (test manually) + # also, see console: + # ValueError: bpy_struct "SCENE_OT_test_op" doesn't support datablock properties + id_prop = bpy.props.PointerProperty(type=bpy.types.Object) + + def execute(self, context): + return {'FINISHED'} + + # just panel for testing the poll callback with lots of objects + class TEST_PT_DatablockProp(bpy.types.Panel): + bl_label = "Datablock IDProp" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "render" + + def draw(self, context): + self.layout.prop_search(context.scene, "prop", bpy.data, + "objects") + self.layout.template_ID(context.scene, "prop1") + self.layout.prop_search(context.scene, "prop2", bpy.data, "node_groups") + + op = self.layout.operator("scene.test_op") + op.str_prop = "test string" + + def test_fnc(op): + op["ob"] = bpy.data.objects['Unique_Cube'] + check_crash(test_fnc, op) + abort_if_false(not hasattr(op, "id_prop")) + + bpy.utils.register_class(TEST_PT_DatablockProp) + bpy.utils.register_class(TEST_Op) + + def poll(self, value): + return value.name in bpy.data.scenes["Scene_lib"].objects + + def poll1(self, value): + return True + + bpy.types.Scene.prop = bpy.props.PointerProperty(type=bpy.types.Object) + bpy.types.Scene.prop1 = bpy.props.PointerProperty(type=bpy.types.Object, poll=poll) + bpy.types.Scene.prop2 = bpy.props.PointerProperty(type=bpy.types.NodeTree, poll=poll1) + + # check poll effect on UI (poll returns false => red alert) + bpy.context.scene.prop = bpy.data.objects["Lamp.001"] + bpy.context.scene.prop1 = bpy.data.objects["Lamp.001"] + + # check incorrect type assignment + def sub_test(): + # NodeTree id_prop + bpy.context.scene.prop2 = bpy.data.objects["Lamp.001"] + + check_crash(sub_test) + + bpy.context.scene.prop2 = bpy.data.node_groups.new("Shader", "ShaderNodeTree") + + print("Please, test GUI performance manually on the Render tab, '%s' panel" % + TEST_PT_DatablockProp.bl_label, file=sys.stderr) + sys.stderr.flush() + + +# check some possible regressions +def test_regressions(): + bpy.types.Object.prop_str = bpy.props.StringProperty(name="str") + bpy.data.objects["Unique_Cube"].prop_str = "test" + + bpy.types.Object.prop_gr = bpy.props.PointerProperty( + name="prop_gr", + type=TestClass, + description="test") + + bpy.data.objects["Unique_Cube"].prop_gr = None + + +# test restrictions for datablock pointers +def test_restrictions2(): + class TestClassCollection(bpy.types.PropertyGroup): + prop = bpy.props.CollectionProperty( + name="prop_array", + type=TestClass) + bpy.utils.register_class(TestClassCollection) + + class TestPrefs(bpy.types.AddonPreferences): + bl_idname = "testprefs" + # expecting crash during registering + my_prop2 = bpy.props.PointerProperty(type=TestClass) + + prop = bpy.props.PointerProperty( + name="prop", + type=TestClassCollection, + description="test") + + bpy.types.Addon.a = bpy.props.PointerProperty(type=bpy.types.Object) + + class TestUIList(UIList): + test = bpy.props.PointerProperty(type=bpy.types.Object) + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + layout.prop(item, "name", text="", emboss=False, icon_value=icon) + + check_crash(bpy.utils.register_class, TestPrefs) + check_crash(bpy.utils.register_class, TestUIList) + + bpy.utils.unregister_class(TestClassCollection) + + +def main(): + init() + test_users_counting() + test_linking() + test_restrictions1() + check_crash(test_regressions) + test_restrictions2() + + +if __name__ == "__main__": + try: + main() + except: + import traceback + + traceback.print_exc() + sys.stderr.flush() + os._exit(1) diff --git a/tests/python/bl_pyapi_mathutils.py b/tests/python/bl_pyapi_mathutils.py index 7761b6cb7b1..9ca0376192a 100644 --- a/tests/python/bl_pyapi_mathutils.py +++ b/tests/python/bl_pyapi_mathutils.py @@ -260,6 +260,11 @@ class KDTreeTesting(unittest.TestCase): k.balance() return k + def assertAlmostEqualVector(self, first, second, places=7, msg=None, delta=None): + self.assertAlmostEqual(first[0], second[0], places=places, msg=msg, delta=delta) + self.assertAlmostEqual(first[1], second[1], places=places, msg=msg, delta=delta) + self.assertAlmostEqual(first[2], second[2], places=places, msg=msg, delta=delta) + def test_kdtree_single(self): co = (0,) * 3 index = 2 @@ -360,12 +365,12 @@ class KDTreeTesting(unittest.TestCase): ret_regular = k_odd.find(co) self.assertEqual(ret_regular[1] % 2, 1) ret_filter = k_all.find(co, lambda i: (i % 2) == 1) - self.assertEqual(ret_regular, ret_filter) + self.assertAlmostEqualVector(ret_regular, ret_filter) ret_regular = k_evn.find(co) self.assertEqual(ret_regular[1] % 2, 0) ret_filter = k_all.find(co, lambda i: (i % 2) == 0) - self.assertEqual(ret_regular, ret_filter) + self.assertAlmostEqualVector(ret_regular, ret_filter) # filter out all values (search odd tree for even values and the reverse) diff --git a/tests/python/bl_run_operators.py b/tests/python/bl_run_operators.py index 7e92b424faa..7d5f4127378 100644 --- a/tests/python/bl_run_operators.py +++ b/tests/python/bl_run_operators.py @@ -65,6 +65,7 @@ op_blacklist = ( "wm.blenderplayer_start", "wm.recover_auto_save", "wm.quit_blender", + "wm.window_close", "wm.url_open", "wm.doc_view", "wm.doc_edit", @@ -308,16 +309,7 @@ def run_ops(operators, setup_func=None, reset=True): # contexts def ctx_clear_scene(): # copied from batch_import.py - unique_obs = set() - for scene in bpy.data.scenes: - for obj in scene.objects[:]: - scene.objects.unlink(obj) - unique_obs.add(obj) - - # remove obdata, for now only worry about the startup scene - for bpy_data_iter in (bpy.data.objects, bpy.data.meshes, bpy.data.lamps, bpy.data.cameras): - for id_data in bpy_data_iter: - bpy_data_iter.remove(id_data) + bpy.ops.wm.read_factory_settings(use_empty=True) def ctx_editmode_mesh(): |