diff options
105 files changed, 2884 insertions, 1832 deletions
diff --git a/GNUmakefile b/GNUmakefile index e3bb3eaff7a..93e2164dee8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -32,6 +32,7 @@ Convenience Targets * debug: Build a debug binary. * full: Enable all supported dependencies & options. * lite: Disable non essential features for a smaller binary and faster build. + * release Complete build with all options enabled including CUDA and Optix, matching the releases on blender.org * headless: Build without an interface (renderfarm or server automation). * cycles: Build Cycles standalone only, without Blender. * bpy: Build as a python module which can be loaded from python directly. @@ -207,6 +208,10 @@ ifneq "$(findstring lite, $(MAKECMDGOALS))" "" BUILD_DIR:=$(BUILD_DIR)_lite CMAKE_CONFIG_ARGS:=-C"$(BLENDER_DIR)/build_files/cmake/config/blender_lite.cmake" $(CMAKE_CONFIG_ARGS) endif +ifneq "$(findstring release, $(MAKECMDGOALS))" "" + BUILD_DIR:=$(BUILD_DIR)_release + CMAKE_CONFIG_ARGS:=-C"$(BLENDER_DIR)/build_files/cmake/config/blender_release.cmake" $(CMAKE_CONFIG_ARGS) +endif ifneq "$(findstring cycles, $(MAKECMDGOALS))" "" BUILD_DIR:=$(BUILD_DIR)_cycles CMAKE_CONFIG_ARGS:=-C"$(BLENDER_DIR)/build_files/cmake/config/cycles_standalone.cmake" $(CMAKE_CONFIG_ARGS) @@ -317,6 +322,7 @@ all: .FORCE debug: all full: all lite: all +release: all cycles: all headless: all bpy: all diff --git a/build_files/build_environment/cmake/usd.cmake b/build_files/build_environment/cmake/usd.cmake index 3e4535a6f92..c98a9cae959 100644 --- a/build_files/build_environment/cmake/usd.cmake +++ b/build_files/build_environment/cmake/usd.cmake @@ -78,14 +78,14 @@ if(WIN32) if(BUILD_MODE STREQUAL Release) ExternalProject_Add_Step(external_usd after_install COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/usd/ ${HARVEST_TARGET}/usd - COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/Release/libusd_m.lib ${HARVEST_TARGET}/usd/lib/libusd_m.lib + COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/Release/usd_m.lib ${HARVEST_TARGET}/usd/lib/libusd_m.lib DEPENDEES install ) endif() if(BUILD_MODE STREQUAL Debug) ExternalProject_Add_Step(external_usd after_install COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/usd/lib ${HARVEST_TARGET}/usd/lib - COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/Debug/libusd_m_d.lib ${HARVEST_TARGET}/usd/lib/libusd_m_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/Debug/usd_m_d.lib ${HARVEST_TARGET}/usd/lib/libusd_m_d.lib DEPENDEES install ) endif() diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake index c1dcf98318c..a140a26b023 100644 --- a/build_files/build_environment/cmake/versions.cmake +++ b/build_files/build_environment/cmake/versions.cmake @@ -297,9 +297,9 @@ set(EMBREE_VERSION 3.10.0) set(EMBREE_URI https://github.com/embree/embree/archive/v${EMBREE_VERSION}.zip) set(EMBREE_HASH 4bbe29e7eaa46417efc75fc5f1e8eb87) -set(USD_VERSION 19.11) +set(USD_VERSION 20.02) set(USD_URI https://github.com/PixarAnimationStudios/USD/archive/v${USD_VERSION}.tar.gz) -set(USD_HASH 79ff176167b3fe85f4953abd6cc5e0cc) +set(USD_HASH 8901815f01469a7f4496bd60315a9d10) set(OIDN_VERSION 1.0.0) set(OIDN_URI https://github.com/OpenImageDenoise/oidn/releases/download/v${OIDN_VERSION}/oidn-${OIDN_VERSION}.src.zip) diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 511ea341bb1..06d9cc4aa06 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -459,7 +459,7 @@ ALEMBIC_FORCE_BUILD=false ALEMBIC_FORCE_REBUILD=false ALEMBIC_SKIP=false -USD_VERSION="19.11" +USD_VERSION="20.02" USD_FORCE_BUILD=false USD_FORCE_REBUILD=false USD_SKIP=false diff --git a/build_files/build_environment/patches/usd.diff b/build_files/build_environment/patches/usd.diff index 6302f13796b..adee3d2e458 100644 --- a/build_files/build_environment/patches/usd.diff +++ b/build_files/build_environment/patches/usd.diff @@ -1,14 +1,3 @@ -diff -x .git -ur usd.orig/cmake/defaults/Options.cmake external_usd/cmake/defaults/Options.cmake ---- usd.orig/cmake/defaults/Options.cmake 2019-10-24 22:39:53.000000000 +0200 -+++ external_usd/cmake/defaults/Options.cmake 2019-11-28 13:00:33.197957712 +0100 -@@ -25,6 +25,7 @@ - option(PXR_VALIDATE_GENERATED_CODE "Validate script generated code" OFF) - option(PXR_HEADLESS_TEST_MODE "Disallow GUI based tests, useful for running under headless CI systems." OFF) - option(PXR_BUILD_TESTS "Build tests" ON) -+option(PXR_BUILD_USD_TOOLS "Build commandline tools" ON) - option(PXR_BUILD_IMAGING "Build imaging components" ON) - option(PXR_BUILD_EMBREE_PLUGIN "Build embree imaging plugin" OFF) - option(PXR_BUILD_OPENIMAGEIO_PLUGIN "Build OpenImageIO plugin" OFF) diff -x .git -ur usd.orig/cmake/defaults/Packages.cmake external_usd/cmake/defaults/Packages.cmake --- usd.orig/cmake/defaults/Packages.cmake 2019-10-24 22:39:53.000000000 +0200 +++ external_usd/cmake/defaults/Packages.cmake 2019-11-28 13:00:33.185957483 +0100 @@ -21,9 +10,9 @@ diff -x .git -ur usd.orig/cmake/defaults/Packages.cmake external_usd/cmake/defau add_definitions(${TBB_DEFINITIONS}) # --math -diff -x .git -ur usd.orig/pxr/base/lib/plug/initConfig.cpp external_usd/pxr/base/lib/plug/initConfig.cpp ---- usd.orig/pxr/base/lib/plug/initConfig.cpp 2019-10-24 22:39:53.000000000 +0200 -+++ external_usd/pxr/base/lib/plug/initConfig.cpp 2019-12-11 11:00:37.643323127 +0100 +diff -x .git -ur usd.orig/pxr/base/plug/initConfig.cpp external_usd/pxr/base/plug/initConfig.cpp +--- usd.orig/pxr/base/plug/initConfig.cpp 2019-10-24 22:39:53.000000000 +0200 ++++ external_usd/pxr/base/plug/initConfig.cpp 2019-12-11 11:00:37.643323127 +0100 @@ -69,8 +69,38 @@ ARCH_CONSTRUCTOR(Plug_InitConfig, 2, void) @@ -90,28 +79,9 @@ diff -x .git -ur usd.orig/pxr/base/lib/plug/initConfig.cpp external_usd/pxr/base + PXR_NS::usd_initialise_plugin_path(datafiles_usd_path); +} +} -diff -x .git -ur usd.orig/pxr/usd/CMakeLists.txt external_usd/pxr/usd/CMakeLists.txt ---- usd.orig/pxr/usd/CMakeLists.txt 2019-10-24 22:39:53.000000000 +0200 -+++ external_usd/pxr/usd/CMakeLists.txt 2019-11-28 13:00:33.197957712 +0100 -@@ -1,6 +1,5 @@ - set(DIRS - lib -- bin - plugin - ) - -@@ -8,3 +7,8 @@ - add_subdirectory(${d}) - endforeach() - -+if (PXR_BUILD_USD_TOOLS) -+ add_subdirectory(bin) -+else() -+ message(STATUS "Skipping commandline tools because PXR_BUILD_USD_TOOLS=OFF") -+endif() -diff -Naur external_usd_orig/pxr/base/lib/tf/preprocessorUtils.h external_usd/pxr/base/lib/tf/preprocessorUtils.h ---- external_usd_orig/pxr/base/lib/tf/preprocessorUtils.h 2019-10-24 14:39:53 -0600 -+++ external_usd/pxr/base/lib/tf/preprocessorUtils.h 2020-01-14 09:30:18 -0700 +diff -Naur external_usd_orig/pxr/base/tf/preprocessorUtils.h external_usd/pxr/base/tf/preprocessorUtils.h +--- external_usd_orig/pxr/base/tf/preprocessorUtils.h 2019-10-24 14:39:53 -0600 ++++ external_usd/pxr/base/tf/preprocessorUtils.h 2020-01-14 09:30:18 -0700 @@ -189,7 +189,7 @@ /// Exapnds to 1 if the argument is a tuple, and 0 otherwise. /// \ingroup group_tf_Preprocessor diff --git a/build_files/buildbot/buildbot_utils.py b/build_files/buildbot/buildbot_utils.py index 2dc1526c5e8..39a00980cc8 100644 --- a/build_files/buildbot/buildbot_utils.py +++ b/build_files/buildbot/buildbot_utils.py @@ -51,7 +51,7 @@ class Builder: elif name.startswith('linux'): self.platform = 'linux' if is_tool('scl'): - self.command_prefix = ['scl', 'enable', 'devtoolset-6', '--'] + self.command_prefix = ['scl', 'enable', 'devtoolset-9', '--'] else: self.command_prefix = [] elif name.startswith('win'): diff --git a/extern/audaspace/plugins/sdl/SDLDevice.cpp b/extern/audaspace/plugins/sdl/SDLDevice.cpp index 603e16001b8..8d7a605fa36 100644 --- a/extern/audaspace/plugins/sdl/SDLDevice.cpp +++ b/extern/audaspace/plugins/sdl/SDLDevice.cpp @@ -52,7 +52,7 @@ SDLDevice::SDLDevice(DeviceSpecs specs, int buffersize) : if(specs.channels == CHANNELS_INVALID) specs.channels = CHANNELS_STEREO; if(specs.format == FORMAT_INVALID) - specs.format = FORMAT_S16; + specs.format = FORMAT_FLOAT32; if(specs.rate == RATE_INVALID) specs.rate = RATE_48000; @@ -61,10 +61,25 @@ SDLDevice::SDLDevice(DeviceSpecs specs, int buffersize) : SDL_AudioSpec format, obtained; format.freq = m_specs.rate; - if(m_specs.format == FORMAT_U8) + switch(m_specs.format) + { + case FORMAT_U8: format.format = AUDIO_U8; - else + break; + case FORMAT_S16: format.format = AUDIO_S16SYS; + break; + case FORMAT_S32: + format.format = AUDIO_S32SYS; + break; + case FORMAT_FLOAT32: + format.format = AUDIO_F32SYS; + break; + default: + format.format = AUDIO_F32SYS; + break; + } + format.channels = m_specs.channels; format.samples = buffersize; format.callback = SDLDevice::SDL_mix; @@ -75,14 +90,25 @@ SDLDevice::SDLDevice(DeviceSpecs specs, int buffersize) : m_specs.rate = (SampleRate)obtained.freq; m_specs.channels = (Channels)obtained.channels; - if(obtained.format == AUDIO_U8) + + switch(obtained.format) + { + case AUDIO_U8: m_specs.format = FORMAT_U8; - else if(obtained.format == AUDIO_S16LSB || obtained.format == AUDIO_S16MSB) + break; + case AUDIO_S16SYS: m_specs.format = FORMAT_S16; - else - { + break; + case AUDIO_S32SYS: + m_specs.format = FORMAT_S32; + break; + case AUDIO_F32SYS: + m_specs.format = FORMAT_FLOAT32; + break; + default: SDL_CloseAudio(); AUD_THROW(DeviceException, "The sample format obtained from SDL is not supported."); + break; } create(); diff --git a/intern/cycles/device/cuda/device_cuda.h b/intern/cycles/device/cuda/device_cuda.h index 9f31ed12cf4..1aa2fdd0967 100644 --- a/intern/cycles/device/cuda/device_cuda.h +++ b/intern/cycles/device/cuda/device_cuda.h @@ -100,11 +100,7 @@ class CUDADevice : public Device { virtual BVHLayoutMask get_bvh_layout_mask() const; - void cuda_error_documentation(); - - bool cuda_error_(CUresult result, const string &stmt); - - void cuda_error_message(const string &message); + void set_error(const string &error) override; CUDADevice(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background_); diff --git a/intern/cycles/device/cuda/device_cuda_impl.cpp b/intern/cycles/device/cuda/device_cuda_impl.cpp index 64c7f5e7d34..7aa63ff48c3 100644 --- a/intern/cycles/device/cuda/device_cuda_impl.cpp +++ b/intern/cycles/device/cuda/device_cuda_impl.cpp @@ -135,8 +135,10 @@ BVHLayoutMask CUDADevice::get_bvh_layout_mask() const return BVH_LAYOUT_BVH2; } -void CUDADevice::cuda_error_documentation() +void CUDADevice::set_error(const string &error) { + Device::set_error(error); + if (first_error) { fprintf(stderr, "\nRefer to the Cycles GPU rendering documentation for possible solutions:\n"); fprintf(stderr, @@ -148,42 +150,13 @@ void CUDADevice::cuda_error_documentation() # define cuda_assert(stmt) \ { \ CUresult result = stmt; \ -\ if (result != CUDA_SUCCESS) { \ - string message = string_printf( \ - "CUDA error: %s in %s, line %d", cuewErrorString(result), #stmt, __LINE__); \ - if (error_msg == "") \ - error_msg = message; \ - fprintf(stderr, "%s\n", message.c_str()); \ - /*cuda_abort();*/ \ - cuda_error_documentation(); \ + const char *name = cuewErrorString(result); \ + set_error(string_printf("%s in %s (device_cuda_impl.cpp:%d)", name, #stmt, __LINE__)); \ } \ } \ (void)0 -bool CUDADevice::cuda_error_(CUresult result, const string &stmt) -{ - if (result == CUDA_SUCCESS) - return false; - - string message = string_printf("CUDA error at %s: %s", stmt.c_str(), cuewErrorString(result)); - if (error_msg == "") - error_msg = message; - fprintf(stderr, "%s\n", message.c_str()); - cuda_error_documentation(); - return true; -} - -# define cuda_error(stmt) cuda_error_(stmt, # stmt) - -void CUDADevice::cuda_error_message(const string &message) -{ - if (error_msg == "") - error_msg = message; - fprintf(stderr, "%s\n", message.c_str()); - cuda_error_documentation(); -} - CUDADevice::CUDADevice(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background_) : Device(info, stats, profiler, background_), texture_info(this, "__texture_info", MEM_GLOBAL) { @@ -212,12 +185,19 @@ CUDADevice::CUDADevice(DeviceInfo &info, Stats &stats, Profiler &profiler, bool functions.loaded = false; /* Intialize CUDA. */ - if (cuda_error(cuInit(0))) + CUresult result = cuInit(0); + if (result != CUDA_SUCCESS) { + set_error(string_printf("Failed to initialize CUDA runtime (%s)", cuewErrorString(result))); return; + } /* Setup device and context. */ - if (cuda_error(cuDeviceGet(&cuDevice, cuDevId))) + result = cuDeviceGet(&cuDevice, cuDevId); + if (result != CUDA_SUCCESS) { + set_error(string_printf("Failed to get CUDA device handle from ordinal (%s)", + cuewErrorString(result))); return; + } /* CU_CTX_MAP_HOST for mapping host memory when out of device memory. * CU_CTX_LMEM_RESIZE_TO_MAX for reserving local memory ahead of render, @@ -235,8 +215,6 @@ CUDADevice::CUDADevice(DeviceInfo &info, Stats &stats, Profiler &profiler, bool } /* Create context. */ - CUresult result; - if (background) { result = cuCtxCreate(&cuContext, ctx_flags, cuDevice); } @@ -249,8 +227,10 @@ CUDADevice::CUDADevice(DeviceInfo &info, Stats &stats, Profiler &profiler, bool } } - if (cuda_error_(result, "cuCtxCreate")) + if (result != CUDA_SUCCESS) { + set_error(string_printf("Failed to create CUDA context (%s)", cuewErrorString(result))); return; + } int major, minor; cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevId); @@ -280,10 +260,8 @@ bool CUDADevice::support_device(const DeviceRequestedFeatures & /*requested_feat /* We only support sm_30 and above */ if (major < 3) { - cuda_error_message( - string_printf("CUDA device supported only with compute capability 3.0 or up, found %d.%d.", - major, - minor)); + set_error(string_printf( + "CUDA backend requires compute capability 3.0 or up, but found %d.%d.", major, minor)); return false; } @@ -319,13 +297,19 @@ bool CUDADevice::check_peer_access(Device *peer_device) // Enable peer access in both directions { const CUDAContextScope scope(this); - if (cuda_error(cuCtxEnablePeerAccess(peer_device_cuda->cuContext, 0))) { + CUresult result = cuCtxEnablePeerAccess(peer_device_cuda->cuContext, 0); + if (result != CUDA_SUCCESS) { + set_error(string_printf("Failed to enable peer access on CUDA context (%s)", + cuewErrorString(result))); return false; } } { const CUDAContextScope scope(peer_device_cuda); - if (cuda_error(cuCtxEnablePeerAccess(cuContext, 0))) { + CUresult result = cuCtxEnablePeerAccess(cuContext, 0); + if (result != CUDA_SUCCESS) { + set_error(string_printf("Failed to enable peer access on CUDA context (%s)", + cuewErrorString(result))); return false; } } @@ -432,14 +416,14 @@ string CUDADevice::compile_kernel(const DeviceRequestedFeatures &requested_featu # ifdef _WIN32 if (!use_adaptive_compilation() && have_precompiled_kernels()) { if (major < 3) { - cuda_error_message( - string_printf("CUDA device requires compute capability 3.0 or up, " - "found %d.%d. Your GPU is not supported.", + set_error( + string_printf("CUDA backend requires compute capability 3.0 or up, but found %d.%d. " + "Your GPU is not supported.", major, minor)); } else { - cuda_error_message( + set_error( string_printf("CUDA binary kernel for this graphics card compute " "capability (%d.%d) not found.", major, @@ -452,7 +436,7 @@ string CUDADevice::compile_kernel(const DeviceRequestedFeatures &requested_featu /* Compile. */ const char *const nvcc = cuewCompilerPath(); if (nvcc == NULL) { - cuda_error_message( + set_error( "CUDA nvcc compiler not found. " "Install CUDA toolkit in default location."); return string(); @@ -504,7 +488,7 @@ string CUDADevice::compile_kernel(const DeviceRequestedFeatures &requested_featu command = "call " + command; # endif if (system(command.c_str()) != 0) { - cuda_error_message( + set_error( "Failed to execute compilation command, " "see console for details."); return string(); @@ -512,7 +496,7 @@ string CUDADevice::compile_kernel(const DeviceRequestedFeatures &requested_featu /* Verify if compilation succeeded */ if (!path_exists(cubin)) { - cuda_error_message( + set_error( "CUDA kernel compilation failed, " "see console for details."); return string(); @@ -565,16 +549,19 @@ bool CUDADevice::load_kernels(const DeviceRequestedFeatures &requested_features) else result = CUDA_ERROR_FILE_NOT_FOUND; - if (cuda_error_(result, "cuModuleLoad")) - cuda_error_message(string_printf("Failed loading CUDA kernel %s.", cubin.c_str())); + if (result != CUDA_SUCCESS) + set_error(string_printf( + "Failed to load CUDA kernel from '%s' (%s)", cubin.c_str(), cuewErrorString(result))); if (path_read_text(filter_cubin, cubin_data)) result = cuModuleLoadData(&cuFilterModule, cubin_data.c_str()); else result = CUDA_ERROR_FILE_NOT_FOUND; - if (cuda_error_(result, "cuModuleLoad")) - cuda_error_message(string_printf("Failed loading CUDA kernel %s.", filter_cubin.c_str())); + if (result != CUDA_SUCCESS) + set_error(string_printf("Failed to load CUDA kernel from '%s' (%s)", + filter_cubin.c_str(), + cuewErrorString(result))); if (result == CUDA_SUCCESS) { reserve_local_memory(requested_features); @@ -870,7 +857,7 @@ CUDADevice::CUDAMem *CUDADevice::generic_alloc(device_memory &mem, size_t pitch_ if (mem_alloc_result != CUDA_SUCCESS) { status = " failed, out of device and host memory"; - cuda_assert(mem_alloc_result); + set_error("System is out of GPU and shared host memory"); } if (mem.name) { @@ -2458,14 +2445,10 @@ void CUDADevice::task_cancel() # define cuda_assert(stmt) \ { \ CUresult result = stmt; \ -\ if (result != CUDA_SUCCESS) { \ - string message = string_printf("CUDA error: %s in %s", cuewErrorString(result), #stmt); \ - if (device->error_msg == "") \ - device->error_msg = message; \ - fprintf(stderr, "%s\n", message.c_str()); \ - /*cuda_abort();*/ \ - device->cuda_error_documentation(); \ + const char *name = cuewErrorString(result); \ + device->set_error( \ + string_printf("%s in %s (device_cuda_impl.cpp:%d)", name, #stmt, __LINE__)); \ } \ } \ (void)0 @@ -2647,14 +2630,15 @@ bool CUDASplitKernel::enqueue_split_kernel_data_init(const KernelDimensions &dim SplitKernelFunction *CUDASplitKernel::get_split_kernel_function(const string &kernel_name, const DeviceRequestedFeatures &) { - CUDAContextScope scope(device); - CUfunction func; + const CUDAContextScope scope(device); - cuda_assert( - cuModuleGetFunction(&func, device->cuModule, (string("kernel_cuda_") + kernel_name).data())); - if (device->have_error()) { - device->cuda_error_message( - string_printf("kernel \"kernel_cuda_%s\" not found in module", kernel_name.data())); + CUfunction func; + const CUresult result = cuModuleGetFunction( + &func, device->cuModule, (string("kernel_cuda_") + kernel_name).data()); + if (result != CUDA_SUCCESS) { + device->set_error(string_printf("Could not find kernel \"kernel_cuda_%s\" in module (%s)", + kernel_name.data(), + cuewErrorString(result))); return NULL; } diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp index db04c13d083..fbf6a914744 100644 --- a/intern/cycles/device/device_optix.cpp +++ b/intern/cycles/device/device_optix.cpp @@ -70,7 +70,7 @@ struct KernelParams { if (res != CUDA_SUCCESS) { \ const char *name; \ cuGetErrorName(res, &name); \ - set_error(string_printf("OptiX CUDA error %s in %s, line %d", name, #stmt, __LINE__)); \ + set_error(string_printf("%s in %s (device_optix.cpp:%d)", name, #stmt, __LINE__)); \ return; \ } \ } \ @@ -81,7 +81,7 @@ struct KernelParams { if (res != CUDA_SUCCESS) { \ const char *name; \ cuGetErrorName(res, &name); \ - set_error(string_printf("OptiX CUDA error %s in %s, line %d", name, #stmt, __LINE__)); \ + set_error(string_printf("%s in %s (device_optix.cpp:%d)", name, #stmt, __LINE__)); \ return false; \ } \ } \ @@ -92,7 +92,7 @@ struct KernelParams { enum OptixResult res = stmt; \ if (res != OPTIX_SUCCESS) { \ const char *name = optixGetErrorName(res); \ - set_error(string_printf("OptiX error %s in %s, line %d", name, #stmt, __LINE__)); \ + set_error(string_printf("%s in %s (device_optix.cpp:%d)", name, #stmt, __LINE__)); \ return; \ } \ } \ @@ -102,7 +102,7 @@ struct KernelParams { enum OptixResult res = stmt; \ if (res != OPTIX_SUCCESS) { \ const char *name = optixGetErrorName(res); \ - set_error(string_printf("OptiX error %s in %s, line %d", name, #stmt, __LINE__)); \ + set_error(string_printf("%s in %s (device_optix.cpp:%d)", name, #stmt, __LINE__)); \ return false; \ } \ } \ @@ -322,12 +322,12 @@ class OptiXDevice : public CUDADevice { // Disable baking for now, since its kernel is not well-suited for inlining and is very slow if (requested_features.use_baking) { - set_error("OptiX implementation does not support baking yet"); + set_error("OptiX backend does not support baking yet"); return false; } // Disable shader raytracing support for now, since continuation callables are slow if (requested_features.use_shader_raytrace) { - set_error("OptiX implementation does not support shader raytracing yet"); + set_error("OptiX backend does not support 'Ambient Occlusion' and 'Bevel' shader nodes yet"); return false; } @@ -386,14 +386,14 @@ class OptiXDevice : public CUDADevice { if (use_adaptive_compilation() || path_file_size(ptx_filename) == -1) { if (!getenv("OPTIX_ROOT_DIR")) { set_error( - "OPTIX_ROOT_DIR environment variable not set, must be set with the path to the " - "Optix SDK in order to compile the Optix kernel on demand."); + "Missing OPTIX_ROOT_DIR environment variable (which must be set with the path to " + "the Optix SDK to be able to compile Optix kernels on demand)."); return false; } ptx_filename = compile_kernel(requested_features, "kernel_optix", "optix", true); } if (ptx_filename.empty() || !path_read_text(ptx_filename, ptx_data)) { - set_error("Failed loading OptiX kernel " + ptx_filename + "."); + set_error("Failed to load OptiX kernel from '" + ptx_filename + "'"); return false; } diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 7c50140ecfe..f5bfebbaf78 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -833,7 +833,7 @@ bool Session::load_kernels(bool lock_scene) message = "Failed loading render kernel, see console for errors"; progress.set_error(message); - progress.set_status("Error", message); + progress.set_status(message); progress.set_update(); return false; } @@ -872,7 +872,7 @@ void Session::run() /* progress update */ if (progress.get_cancel()) - progress.set_status("Cancel", progress.get_cancel_message()); + progress.set_status(progress.get_cancel_message()); else progress.set_update(); } diff --git a/intern/ghost/intern/GHOST_XrContext.cpp b/intern/ghost/intern/GHOST_XrContext.cpp index 3aab420a9b6..16687c34679 100644 --- a/intern/ghost/intern/GHOST_XrContext.cpp +++ b/intern/ghost/intern/GHOST_XrContext.cpp @@ -126,6 +126,7 @@ void GHOST_XrContext::storeInstanceProperties() const std::map<std::string, GHOST_TXrOpenXRRuntimeID> runtime_map = { {"Monado(XRT) by Collabora et al", OPENXR_RUNTIME_MONADO}, {"Oculus", OPENXR_RUNTIME_OCULUS}, + {"SteamVR/OpenXR", OPENXR_RUNTIME_STEAMVR}, {"Windows Mixed Reality Runtime", OPENXR_RUNTIME_WMR}}; decltype(runtime_map)::const_iterator runtime_map_iter; diff --git a/intern/ghost/intern/GHOST_XrContext.h b/intern/ghost/intern/GHOST_XrContext.h index 7dbd0a0d011..9be57cd90cc 100644 --- a/intern/ghost/intern/GHOST_XrContext.h +++ b/intern/ghost/intern/GHOST_XrContext.h @@ -49,6 +49,7 @@ struct GHOST_XrCustomFuncs { enum GHOST_TXrOpenXRRuntimeID { OPENXR_RUNTIME_MONADO, OPENXR_RUNTIME_OCULUS, + OPENXR_RUNTIME_STEAMVR, OPENXR_RUNTIME_WMR, /* Windows Mixed Reality */ OPENXR_RUNTIME_UNKNOWN diff --git a/intern/ghost/intern/GHOST_XrSession.cpp b/intern/ghost/intern/GHOST_XrSession.cpp index edc4960cf32..7ae819dbfb2 100644 --- a/intern/ghost/intern/GHOST_XrSession.cpp +++ b/intern/ghost/intern/GHOST_XrSession.cpp @@ -380,7 +380,8 @@ static bool ghost_xr_draw_view_expects_srgb_buffer(const GHOST_XrContext *contex /* Monado seems to be faulty and doesn't do OETF transform correctly. So expect a SRGB buffer to * compensate. You get way too dark rendering without this, it's pretty obvious (even in the * default startup scene). */ - return (context->getOpenXRRuntimeID() == OPENXR_RUNTIME_MONADO); + GHOST_TXrOpenXRRuntimeID runtime_id = context->getOpenXRRuntimeID(); + return (runtime_id == OPENXR_RUNTIME_MONADO) || (runtime_id == OPENXR_RUNTIME_STEAMVR); } void GHOST_XrSession::drawView(GHOST_XrSwapchain &swapchain, diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py index 0bf667482c4..79089b7cb89 100644 --- a/release/scripts/startup/bl_ui/properties_physics_cloth.py +++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py @@ -237,7 +237,10 @@ class PHYSICS_PT_cloth_pressure(PhysicButtonsPanel, Panel): col.prop(cloth, "target_volume") col = flow.column() - col.prop(cloth, "pressure_factor", text="Factor") + col.prop(cloth, "pressure_factor") + + col = flow.column() + col.prop(cloth, "fluid_density") col = flow.column() col.prop_search(cloth, "vertex_group_pressure", ob, "vertex_groups", text="Vertex Group") diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py index 0cd99efcca9..210d850ad06 100644 --- a/release/scripts/startup/bl_ui/properties_physics_common.py +++ b/release/scripts/startup/bl_ui/properties_physics_common.py @@ -46,8 +46,8 @@ def physics_add(layout, md, name, type, typeicon, toggles): icon='X', ) if toggles: - row.prop(md, "show_render", text="") row.prop(md, "show_viewport", text="") + row.prop(md, "show_render", text="") else: row.operator( "object.modifier_add", diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py index f6f22ad464f..553d79fb349 100644 --- a/release/scripts/startup/bl_ui/space_text.py +++ b/release/scripts/startup/bl_ui/space_text.py @@ -400,7 +400,7 @@ class TEXT_MT_edit(Menu): layout.separator() layout.operator("text.start_find", text="Find & Replace...") - layout.operator("text.find_set_selected", text="Find Next") + layout.operator("text.find_set_selected") layout.operator("text.jump", text="Jump To...") layout.separator() diff --git a/source/blender/blenkernel/BKE_anim_path.h b/source/blender/blenkernel/BKE_anim_path.h index 64bcedefa58..4de853303ad 100644 --- a/source/blender/blenkernel/BKE_anim_path.h +++ b/source/blender/blenkernel/BKE_anim_path.h @@ -36,13 +36,13 @@ struct Path; void free_path(struct Path *path); void calc_curvepath(struct Object *ob, struct ListBase *nurbs); -int where_on_path(struct Object *ob, - float ctime, - float vec[4], - float dir[3], - float quat[4], - float *radius, - float *weight); +bool where_on_path(const struct Object *ob, + float ctime, + float r_vec[4], + float r_dir[3], + float r_quat[4], + float *r_radius, + float *r_weight); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index c22e7a24afe..6fb6675a05a 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -28,15 +28,18 @@ extern "C" { #endif +struct BMEditMesh; struct Bone; struct Depsgraph; struct ListBase; struct Main; +struct Mesh; struct Object; struct PoseTree; struct Scene; struct bArmature; struct bConstraint; +struct bGPDstroke; struct bPose; struct bPoseChannel; @@ -342,6 +345,45 @@ void BKE_pose_eval_proxy_copy_bone(struct Depsgraph *depsgraph, struct Object *object, int pchan_index); +/* -------------------------------------------------------------------- */ +/** \name Deform 3D Coordinates by Armature (armature_deform.c) + * \{ */ + +/* Note that we could have a 'BKE_armature_deform_coords' that doesn't take object data + * currently there are no callers for this though. */ + +void BKE_armature_deform_coords_with_gpencil_stroke(const struct Object *ob_arm, + const struct Object *ob_target, + float (*vert_coords)[3], + float (*vert_deform_mats)[3][3], + int vert_coords_len, + int deformflag, + float (*vert_coords_prev)[3], + const char *defgrp_name, + struct bGPDstroke *gps_target); + +void BKE_armature_deform_coords_with_mesh(const struct Object *ob_arm, + const struct Object *ob_target, + float (*vert_coords)[3], + float (*vert_deform_mats)[3][3], + int vert_coords_len, + int deformflag, + float (*vert_coords_prev)[3], + const char *defgrp_name, + const struct Mesh *me_target); + +void BKE_armature_deform_coords_with_editmesh(const struct Object *ob_arm, + const struct Object *ob_target, + float (*vert_coords)[3], + float (*vert_deform_mats)[3][3], + int vert_coords_len, + int deformflag, + float (*vert_coords_prev)[3], + const char *defgrp_name, + struct BMEditMesh *em_target); + +/** \} */ + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index f5073ff7aa5..f25482570b1 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -93,9 +93,10 @@ typedef struct Cloth { struct Implicit_Data *implicit; /* our implicit solver connects to this pointer */ struct EdgeSet *edgeset; /* used for selfcollisions */ int last_frame; - float initial_mesh_volume; /* Initial volume of the mesh. Used for pressure */ - struct MEdge *edges; /* Used for hair collisions. */ - struct GHash *sew_edge_graph; /* Sewing edges represented using a GHash */ + float initial_mesh_volume; /* Initial volume of the mesh. Used for pressure */ + float average_acceleration[3]; /* Moving average of overall acceleration. */ + struct MEdge *edges; /* Used for hair collisions. */ + struct GHash *sew_edge_graph; /* Sewing edges represented using a GHash */ } Cloth; /** diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 40f73ccfe84..d32ab474229 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -29,11 +29,13 @@ extern "C" { #endif +struct BMEditMesh; struct BezTriple; struct Curve; struct Depsgraph; struct GHash; struct ListBase; +struct MDeformVert; struct Main; struct Nurb; struct Object; @@ -278,7 +280,15 @@ enum { void BKE_curve_batch_cache_dirty_tag(struct Curve *cu, int mode); void BKE_curve_batch_cache_free(struct Curve *cu); -/* curve_decimate.c */ +extern void (*BKE_curve_batch_cache_dirty_tag_cb)(struct Curve *cu, int mode); +extern void (*BKE_curve_batch_cache_free_cb)(struct Curve *cu); + +/* -------------------------------------------------------------------- */ +/** \name Decimate Curve (curve_decimate.c) + * + * Simplify curve data. + * \{ */ + unsigned int BKE_curve_decimate_bezt_array(struct BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu, @@ -293,8 +303,38 @@ void BKE_curve_decimate_nurb(struct Nurb *nu, const float error_sq_max, const unsigned int error_target_len); -extern void (*BKE_curve_batch_cache_dirty_tag_cb)(struct Curve *cu, int mode); -extern void (*BKE_curve_batch_cache_free_cb)(struct Curve *cu); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Deform 3D Coordinates by Curve (curve_deform.c) + * \{ */ + +void BKE_curve_deform_coords(const struct Object *ob_curve, + const struct Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const struct MDeformVert *dvert, + const int defgrp_index, + const short flag, + const short defaxis); + +void BKE_curve_deform_coords_with_editmesh(const Object *ob_curve, + const Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const int defgrp_index, + const short flag, + const short defaxis, + struct BMEditMesh *em_target); + +void BKE_curve_deform_co(const struct Object *ob_curve, + const struct Object *ob_target, + const float orco[3], + float vec[3], + const int no_rot_axis, + float r_mat[3][3]); + +/** \} */ #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h index c86b877b575..04b85aebb39 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -40,14 +40,16 @@ struct bDeformGroup; struct bDeformGroup *BKE_object_defgroup_new(struct Object *ob, const char *name); void BKE_defgroup_copy_list(struct ListBase *lb1, const struct ListBase *lb2); struct bDeformGroup *BKE_defgroup_duplicate(const struct bDeformGroup *ingroup); -struct bDeformGroup *BKE_object_defgroup_find_name(struct Object *ob, const char *name); -int *BKE_object_defgroup_flip_map(struct Object *ob, int *flip_map_len, const bool use_default); -int *BKE_object_defgroup_flip_map_single(struct Object *ob, +struct bDeformGroup *BKE_object_defgroup_find_name(const struct Object *ob, const char *name); +int *BKE_object_defgroup_flip_map(const struct Object *ob, + int *flip_map_len, + const bool use_default); +int *BKE_object_defgroup_flip_map_single(const struct Object *ob, int *flip_map_len, const bool use_default, int defgroup); -int BKE_object_defgroup_flip_index(struct Object *ob, int index, const bool use_default); -int BKE_object_defgroup_name_index(struct Object *ob, const char *name); +int BKE_object_defgroup_flip_index(const struct Object *ob, int index, const bool use_default); +int BKE_object_defgroup_name_index(const struct Object *ob, const char *name); void BKE_object_defgroup_unique_name(struct bDeformGroup *dg, struct Object *ob); struct MDeformWeight *BKE_defvert_find_index(const struct MDeformVert *dv, const int defgroup); diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 3cd8c69a263..bb23ad63020 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -30,6 +30,7 @@ extern "C" { #endif +struct BMEditMesh; struct BPoint; struct Depsgraph; struct Lattice; @@ -45,48 +46,9 @@ struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name); struct Lattice *BKE_lattice_copy(struct Main *bmain, const struct Lattice *lt); void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du); -struct LatticeDeformData *init_latt_deform(struct Object *oblatt, - struct Object *ob) ATTR_WARN_UNUSED_RESULT; -void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight); -void end_latt_deform(struct LatticeDeformData *lattice_deform_data); - bool object_deform_mball(struct Object *ob, struct ListBase *dispbase); void outside_lattice(struct Lattice *lt); -void curve_deform_verts(struct Object *cuOb, - struct Object *target, - float (*vert_coords)[3], - int numVerts, - struct MDeformVert *dvert, - const int defgrp_index, - short flag, - short defaxis); -void curve_deform_vector(struct Object *cuOb, - struct Object *target, - float orco[3], - float vec[3], - float mat[3][3], - int no_rot_axis); - -void lattice_deform_verts(struct Object *laOb, - struct Object *target, - struct Mesh *mesh, - float (*vert_coords)[3], - int numVerts, - short flag, - const char *vgroup, - float influence); -void armature_deform_verts(struct Object *armOb, - struct Object *target, - const struct Mesh *mesh, - float (*vert_coords)[3], - float (*defMats)[3][3], - int numVerts, - int deformflag, - float (*prevCos)[3], - const char *defgrp_name, - struct bGPDstroke *gps); - float (*BKE_lattice_vert_coords_alloc(const struct Lattice *lt, int *r_vert_len))[3]; void BKE_lattice_vert_coords_get(const struct Lattice *lt, float (*vert_coords)[3]); void BKE_lattice_vert_coords_apply_with_mat4(struct Lattice *lt, @@ -97,7 +59,7 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); -struct MDeformVert *BKE_lattice_deform_verts_get(struct Object *lattice); +struct MDeformVert *BKE_lattice_deform_verts_get(const struct Object *lattice); struct BPoint *BKE_lattice_active_point_get(struct Lattice *lt); struct BoundBox *BKE_lattice_boundbox_get(struct Object *ob); @@ -137,6 +99,44 @@ void BKE_lattice_batch_cache_free(struct Lattice *lt); extern void (*BKE_lattice_batch_cache_dirty_tag_cb)(struct Lattice *lt, int mode); extern void (*BKE_lattice_batch_cache_free_cb)(struct Lattice *lt); +/* -------------------------------------------------------------------- */ +/** \name Deform 3D Coordinates by Lattice (lattice_deform.c) + * \{ */ + +struct LatticeDeformData *BKE_lattice_deform_data_create( + const struct Object *oblatt, const struct Object *ob) ATTR_WARN_UNUSED_RESULT; +void BKE_lattice_deform_data_eval_co(struct LatticeDeformData *lattice_deform_data, + float co[3], + float weight); +void BKE_lattice_deform_data_destroy(struct LatticeDeformData *lattice_deform_data); + +void BKE_lattice_deform_coords(const struct Object *ob_lattice, + const struct Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const short flag, + const char *defgrp_name, + float influence); + +void BKE_lattice_deform_coords_with_mesh(const struct Object *ob_lattice, + const struct Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const short flag, + const char *defgrp_name, + const float influence, + const struct Mesh *me_target); + +void BKE_lattice_deform_coords_with_editmesh(const struct Object *ob_lattice, + const struct Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const short flag, + const char *defgrp_name, + const float influence, + struct BMEditMesh *em_target); +/** \} */ + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_mesh_wrapper.h b/source/blender/blenkernel/BKE_mesh_wrapper.h index ec6a1e3457c..00e2dd08726 100644 --- a/source/blender/blenkernel/BKE_mesh_wrapper.h +++ b/source/blender/blenkernel/BKE_mesh_wrapper.h @@ -31,7 +31,7 @@ extern "C" { struct Mesh *BKE_mesh_wrapper_from_editmesh_with_coords( struct BMEditMesh *em, const struct CustomData_MeshMasks *cd_mask_extra, - float (*vertexCos)[3], + const float (*vert_coords)[3], const struct Mesh *me_settings); struct Mesh *BKE_mesh_wrapper_from_editmesh(struct BMEditMesh *em, const struct CustomData_MeshMasks *cd_mask_extra, diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 4d30c5c7fce..144e091d971 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -24,6 +24,7 @@ * \ingroup bke */ +#include "BLI_ghash.h" #include "BLI_utildefines.h" #include "DNA_object_enums.h" @@ -268,6 +269,7 @@ typedef struct SculptClothLengthConstraint { typedef struct SculptClothSimulation { SculptClothLengthConstraint *length_constraints; int tot_length_constraints; + GSet *created_length_constraints; int capacity_length_constraints; float *length_constraint_tweak; diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 45cd4933f80..92e0904c568 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -74,6 +74,7 @@ set(SRC intern/anim_visualization.c intern/appdir.c intern/armature.c + intern/armature_deform.c intern/armature_update.c intern/asset_engine.c intern/autoexec.c @@ -100,6 +101,7 @@ set(SRC intern/crazyspace.c intern/curve.c intern/curve_decimate.c + intern/curve_deform.c intern/curveprofile.c intern/customdata.c intern/customdata_file.c @@ -139,6 +141,7 @@ set(SRC intern/key.c intern/keyconfig.c intern/lattice.c + intern/lattice_deform.c intern/layer.c intern/layer_utils.c intern/lib_id.c diff --git a/source/blender/blenkernel/intern/anim_path.c b/source/blender/blenkernel/intern/anim_path.c index e073bd6fc82..628e54971ce 100644 --- a/source/blender/blenkernel/intern/anim_path.c +++ b/source/blender/blenkernel/intern/anim_path.c @@ -42,9 +42,11 @@ static CLG_LogRef LOG = {"bke.anim"}; /* ******************************************************************** */ /* Curve Paths - for curve deforms and/or curve following */ -/* free curve path data - * NOTE: frees the path itself! - * NOTE: this is increasingly inaccurate with non-uniform BevPoint subdivisions [#24633] +/** + * Free curve path data + * + * \note Frees the path itself! + * \note This is increasingly inaccurate with non-uniform #BevPoint subdivisions T24633. */ void free_path(Path *path) { @@ -54,8 +56,9 @@ void free_path(Path *path) MEM_freeN(path); } -/* calculate a curve-deform path for a curve - * - only called from displist.c -> do_makeDispListCurveTypes +/** + * Calculate a curve-deform path for a curve + * - Only called from displist.c -> #do_makeDispListCurveTypes */ void calc_curvepath(Object *ob, ListBase *nurbs) { @@ -192,39 +195,40 @@ static int interval_test(const int min, const int max, int p1, const int cycl) return p1; } -/* calculate the deformation implied by the curve path at a given parametric position, +/** + * Calculate the deformation implied by the curve path at a given parametric position, * and returns whether this operation succeeded. * - * note: ctime is normalized range <0-1> + * \param ctime: Time is normalized range <0-1>. * - * returns OK: 1/0 + * \return success. */ -int where_on_path(Object *ob, - float ctime, - float vec[4], - float dir[3], - float quat[4], - float *radius, - float *weight) +bool where_on_path(const Object *ob, + float ctime, + float r_vec[4], + float r_dir[3], + float r_quat[4], + float *r_radius, + float *r_weight) { Curve *cu; - Nurb *nu; - BevList *bl; - Path *path; - PathPoint *pp, *p0, *p1, *p2, *p3; + const Nurb *nu; + const BevList *bl; + const Path *path; + const PathPoint *pp, *p0, *p1, *p2, *p3; float fac; float data[4]; int cycl = 0, s0, s1, s2, s3; - ListBase *nurbs; + const ListBase *nurbs; if (ob == NULL || ob->type != OB_CURVE) { - return 0; + return false; } cu = ob->data; if (ob->runtime.curve_cache == NULL || ob->runtime.curve_cache->path == NULL || ob->runtime.curve_cache->path->data == NULL) { CLOG_WARN(&LOG, "no path!"); - return 0; + return false; } path = ob->runtime.curve_cache->path; pp = path->data; @@ -232,10 +236,10 @@ int where_on_path(Object *ob, /* test for cyclic */ bl = ob->runtime.curve_cache->bev.first; if (!bl) { - return 0; + return false; } if (!bl->nr) { - return 0; + return false; } if (bl->poly > -1) { cycl = 1; @@ -262,7 +266,7 @@ int where_on_path(Object *ob, /* NOTE: commented out for follow constraint * - * If it's ever be uncommented watch out for curve_deform_verts() + * If it's ever be uncommented watch out for BKE_curve_deform_coords() * which used to temporary set CU_FOLLOW flag for the curve and no * longer does it (because of threading issues of such a thing. */ @@ -270,10 +274,10 @@ int where_on_path(Object *ob, key_curve_tangent_weights(1.0f - fac, data, KEY_BSPLINE); - interp_v3_v3v3v3v3(dir, p0->vec, p1->vec, p2->vec, p3->vec, data); + interp_v3_v3v3v3v3(r_dir, p0->vec, p1->vec, p2->vec, p3->vec, data); - /* make compatible with vectoquat */ - negate_v3(dir); + /* Make compatible with #vec_to_quat. */ + negate_v3(r_dir); //} nurbs = BKE_curve_editNurbs_get(cu); @@ -296,16 +300,16 @@ int where_on_path(Object *ob, key_curve_position_weights(1.0f - fac, data, KEY_BSPLINE); } - vec[0] = data[0] * p0->vec[0] + data[1] * p1->vec[0] + data[2] * p2->vec[0] + - data[3] * p3->vec[0]; /* X */ - vec[1] = data[0] * p0->vec[1] + data[1] * p1->vec[1] + data[2] * p2->vec[1] + - data[3] * p3->vec[1]; /* Y */ - vec[2] = data[0] * p0->vec[2] + data[1] * p1->vec[2] + data[2] * p2->vec[2] + - data[3] * p3->vec[2]; /* Z */ - vec[3] = data[0] * p0->vec[3] + data[1] * p1->vec[3] + data[2] * p2->vec[3] + - data[3] * p3->vec[3]; /* Tilt, should not be needed since we have quat still used */ + r_vec[0] = /* X */ + data[0] * p0->vec[0] + data[1] * p1->vec[0] + data[2] * p2->vec[0] + data[3] * p3->vec[0]; + r_vec[1] = /* Y */ + data[0] * p0->vec[1] + data[1] * p1->vec[1] + data[2] * p2->vec[1] + data[3] * p3->vec[1]; + r_vec[2] = /* Z */ + data[0] * p0->vec[2] + data[1] * p1->vec[2] + data[2] * p2->vec[2] + data[3] * p3->vec[2]; + r_vec[3] = /* Tilt, should not be needed since we have quat still used */ + data[0] * p0->vec[3] + data[1] * p1->vec[3] + data[2] * p2->vec[3] + data[3] * p3->vec[3]; - if (quat) { + if (r_quat) { float totfac, q1[4], q2[4]; totfac = data[0] + data[3]; @@ -326,22 +330,22 @@ int where_on_path(Object *ob, totfac = data[0] + data[1] + data[2] + data[3]; if (totfac > FLT_EPSILON) { - interp_qt_qtqt(quat, q1, q2, (data[1] + data[2]) / totfac); + interp_qt_qtqt(r_quat, q1, q2, (data[1] + data[2]) / totfac); } else { - copy_qt_qt(quat, q2); + copy_qt_qt(r_quat, q2); } } - if (radius) { - *radius = data[0] * p0->radius + data[1] * p1->radius + data[2] * p2->radius + - data[3] * p3->radius; + if (r_radius) { + *r_radius = data[0] * p0->radius + data[1] * p1->radius + data[2] * p2->radius + + data[3] * p3->radius; } - if (weight) { - *weight = data[0] * p0->weight + data[1] * p1->weight + data[2] * p2->weight + - data[3] * p3->weight; + if (r_weight) { + *r_weight = data[0] * p0->weight + data[1] * p1->weight + data[2] * p2->weight + + data[3] * p3->weight; } - return 1; + return true; } diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 36921bd2662..007062abb5b 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -35,18 +35,12 @@ #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_string.h" -#include "BLI_task.h" #include "BLI_utildefines.h" #include "BLT_translation.h" -#include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" -#include "DNA_gpencil_types.h" -#include "DNA_lattice_types.h" #include "DNA_listBase.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -55,11 +49,8 @@ #include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_curve.h" -#include "BKE_deform.h" -#include "BKE_displist.h" #include "BKE_idprop.h" #include "BKE_idtype.h" -#include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" @@ -71,13 +62,13 @@ #include "BIK_api.h" -#include "atomic_ops.h" - #include "CLG_log.h" static CLG_LogRef LOG = {"bke.armature"}; -/*************************** Prototypes ***************************/ +/* -------------------------------------------------------------------- */ +/** \name Prototypes + * \{ */ static void copy_bonechildren(Bone *bone_dst, const Bone *bone_src, @@ -87,7 +78,11 @@ static void copy_bonechildren(Bone *bone_dst, static void copy_bonechildren_custom_handles(Bone *bone_dst, bArmature *arm_dst); -/*********************** Armature Datablock ***********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Armature Data-block + * \{ */ /** * Only copy internal data of Armature ID from source @@ -187,7 +182,11 @@ IDTypeInfo IDType_ID_AR = { .foreach_id = armature_foreach_id, }; -/* **************** Generic Functions, data level *************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generic Data-Level Functions + * \{ */ bArmature *BKE_armature_add(Main *bmain, const char *name) { @@ -284,6 +283,12 @@ bArmature *BKE_armature_copy(Main *bmain, const bArmature *arm) return arm_copy; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Armature Transform Copy + * \{ */ + static void copy_bone_transform(Bone *bone_dst, const Bone *bone_src) { bone_dst->roll = bone_src->roll; @@ -313,6 +318,14 @@ void BKE_armature_copy_bone_transforms(bArmature *armature_dst, const bArmature } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Armature Transform by 4x4 Matrix + * + * \see #ED_armature_edit_transform for the edit-mode version of this function. + * \{ */ + /** Helper for #ED_armature_transform */ static void armature_transform_recurse(ListBase *bonebase, const float mat[4][4], @@ -408,6 +421,14 @@ void BKE_armature_transform(bArmature *arm, const float mat[4][4], const bool do armature_transform_recurse(&arm->bonebase, mat, do_props, mat3, scale, NULL, NULL); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Armature Bone Find by Name + * + * Using fast #GHash look-ups when available. + * \{ */ + static Bone *get_named_bone_bonechildren(ListBase *lb, const char *name) { Bone *curBone, *rbone; @@ -480,6 +501,12 @@ void BKE_armature_bone_hash_free(bArmature *arm) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Armature Bone Flags + * \{ */ + bool BKE_armature_bone_flag_test_recursive(const Bone *bone, int flag) { if (bone->flag & flag) { @@ -493,6 +520,12 @@ bool BKE_armature_bone_flag_test_recursive(const Bone *bone, int flag) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Armature Layer Refresh Used + * \{ */ + static void armature_refresh_layer_used_recursive(bArmature *arm, ListBase *bones) { LISTBASE_FOREACH (Bone *, bone, bones) { @@ -518,6 +551,12 @@ void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmatu } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Armature Layer Refresh Used + * \{ */ + /* Finds the best possible extension to the name on a particular axis. (For renaming, check for * unique names afterwards) strip_number: removes number extensions (TODO: not used) * axis: the axis to name on @@ -654,7 +693,11 @@ int bone_autoside_name( } } -/* ************* B-Bone support ******************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Armature B-Bone Support + * \{ */ /* Compute a set of bezier parameter values that produce approximately equally spaced points. */ static void equalize_cubic_bezier(const float control[4][3], @@ -1209,8 +1252,6 @@ int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param, return param->segments; } -/* ************ Armature Deform ******************* */ - static void allocate_bbone_cache(bPoseChannel *pchan, int segments) { bPoseChannel_Runtime *runtime = &pchan->runtime; @@ -1331,498 +1372,11 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan, *r_blend_next = blend; } -/* Add the effect of one bone or B-Bone segment to the accumulated result. */ -static void pchan_deform_accumulate(const DualQuat *deform_dq, - const float deform_mat[4][4], - const float co_in[3], - float weight, - float co_accum[3], - DualQuat *dq_accum, - float mat_accum[3][3]) -{ - if (weight == 0.0f) { - return; - } - - if (dq_accum) { - BLI_assert(!co_accum); - - add_weighted_dq_dq(dq_accum, deform_dq, weight); - } - else { - float tmp[3]; - mul_v3_m4v3(tmp, deform_mat, co_in); - - sub_v3_v3(tmp, co_in); - madd_v3_v3fl(co_accum, tmp, weight); - - if (mat_accum) { - float tmpmat[3][3]; - copy_m3_m4(tmpmat, deform_mat); - - madd_m3_m3m3fl(mat_accum, mat_accum, tmpmat, weight); - } - } -} - -static void b_bone_deform(const bPoseChannel *pchan, - const float co[3], - float weight, - float vec[3], - DualQuat *dq, - float defmat[3][3]) -{ - const DualQuat *quats = pchan->runtime.bbone_dual_quats; - const Mat4 *mats = pchan->runtime.bbone_deform_mats; - const float(*mat)[4] = mats[0].mat; - float blend, y; - int index; - - /* Transform co to bone space and get its y component. */ - y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1]; - - /* Calculate the indices of the 2 affecting b_bone segments. */ - BKE_pchan_bbone_deform_segment_index(pchan, y / pchan->bone->length, &index, &blend); - - pchan_deform_accumulate( - &quats[index], mats[index + 1].mat, co, weight * (1.0f - blend), vec, dq, defmat); - pchan_deform_accumulate( - &quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat); -} - -/* using vec with dist to bone b1 - b2 */ -float distfactor_to_bone( - const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist) -{ - float dist_sq; - float bdelta[3]; - float pdelta[3]; - float hsqr, a, l, rad; - - sub_v3_v3v3(bdelta, b2, b1); - l = normalize_v3(bdelta); - - sub_v3_v3v3(pdelta, vec, b1); - - a = dot_v3v3(bdelta, pdelta); - hsqr = len_squared_v3(pdelta); - - if (a < 0.0f) { - /* If we're past the end of the bone, do a spherical field attenuation thing */ - dist_sq = len_squared_v3v3(b1, vec); - rad = rad1; - } - else if (a > l) { - /* If we're past the end of the bone, do a spherical field attenuation thing */ - dist_sq = len_squared_v3v3(b2, vec); - rad = rad2; - } - else { - dist_sq = (hsqr - (a * a)); - - if (l != 0.0f) { - rad = a / l; - rad = rad * rad2 + (1.0f - rad) * rad1; - } - else { - rad = rad1; - } - } - - a = rad * rad; - if (dist_sq < a) { - return 1.0f; - } - else { - l = rad + rdist; - l *= l; - if (rdist == 0.0f || dist_sq >= l) { - return 0.0f; - } - else { - a = sqrtf(dist_sq) - rad; - return 1.0f - (a * a) / (rdist * rdist); - } - } -} - -static float dist_bone_deform( - bPoseChannel *pchan, float vec[3], DualQuat *dq, float mat[3][3], const float co[3]) -{ - Bone *bone = pchan->bone; - float fac, contrib = 0.0; +/** \} */ - if (bone == NULL) { - return 0.0f; - } - - fac = distfactor_to_bone( - co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); - - if (fac > 0.0f) { - fac *= bone->weight; - contrib = fac; - if (contrib > 0.0f) { - if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) { - b_bone_deform(pchan, co, fac, vec, dq, mat); - } - else { - pchan_deform_accumulate( - &pchan->runtime.deform_dual_quat, pchan->chan_mat, co, fac, vec, dq, mat); - } - } - } - - return contrib; -} - -static void pchan_bone_deform(bPoseChannel *pchan, - float weight, - float vec[3], - DualQuat *dq, - float mat[3][3], - const float co[3], - float *contrib) -{ - Bone *bone = pchan->bone; - - if (!weight) { - return; - } - - if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) { - b_bone_deform(pchan, co, weight, vec, dq, mat); - } - else { - pchan_deform_accumulate( - &pchan->runtime.deform_dual_quat, pchan->chan_mat, co, weight, vec, dq, mat); - } - - (*contrib) += weight; -} - -typedef struct ArmatureUserdata { - Object *armOb; - Object *target; - const Mesh *mesh; - float (*vertexCos)[3]; - float (*defMats)[3][3]; - float (*prevCos)[3]; - - bool use_envelope; - bool use_quaternion; - bool invert_vgroup; - bool use_dverts; - - int armature_def_nr; - - int target_totvert; - MDeformVert *dverts; - - int defbase_tot; - bPoseChannel **defnrToPC; - - float premat[4][4]; - float postmat[4][4]; -} ArmatureUserdata; - -static void armature_vert_task(void *__restrict userdata, - const int i, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - const ArmatureUserdata *data = userdata; - float(*const vertexCos)[3] = data->vertexCos; - float(*const defMats)[3][3] = data->defMats; - float(*const prevCos)[3] = data->prevCos; - const bool use_envelope = data->use_envelope; - const bool use_quaternion = data->use_quaternion; - const bool use_dverts = data->use_dverts; - const int armature_def_nr = data->armature_def_nr; - - MDeformVert *dvert; - DualQuat sumdq, *dq = NULL; - bPoseChannel *pchan; - float *co, dco[3]; - float sumvec[3], summat[3][3]; - float *vec = NULL, (*smat)[3] = NULL; - float contrib = 0.0f; - float armature_weight = 1.0f; /* default to 1 if no overall def group */ - float prevco_weight = 1.0f; /* weight for optional cached vertexcos */ - - if (use_quaternion) { - memset(&sumdq, 0, sizeof(DualQuat)); - dq = &sumdq; - } - else { - sumvec[0] = sumvec[1] = sumvec[2] = 0.0f; - vec = sumvec; - - if (defMats) { - zero_m3(summat); - smat = summat; - } - } - - if (use_dverts || armature_def_nr != -1) { - if (data->mesh) { - BLI_assert(i < data->mesh->totvert); - if (data->mesh->dvert != NULL) { - dvert = data->mesh->dvert + i; - } - else { - dvert = NULL; - } - } - else if (data->dverts && i < data->target_totvert) { - dvert = data->dverts + i; - } - else { - dvert = NULL; - } - } - else { - dvert = NULL; - } - - if (armature_def_nr != -1 && dvert) { - armature_weight = BKE_defvert_find_weight(dvert, armature_def_nr); - - if (data->invert_vgroup) { - armature_weight = 1.0f - armature_weight; - } - - /* hackish: the blending factor can be used for blending with prevCos too */ - if (prevCos) { - prevco_weight = armature_weight; - armature_weight = 1.0f; - } - } - - /* check if there's any point in calculating for this vert */ - if (armature_weight == 0.0f) { - return; - } - - /* get the coord we work on */ - co = prevCos ? prevCos[i] : vertexCos[i]; - - /* Apply the object's matrix */ - mul_m4_v3(data->premat, co); - - if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */ - MDeformWeight *dw = dvert->dw; - int deformed = 0; - unsigned int j; - for (j = dvert->totweight; j != 0; j--, dw++) { - const uint index = dw->def_nr; - if (index < data->defbase_tot && (pchan = data->defnrToPC[index])) { - float weight = dw->weight; - Bone *bone = pchan->bone; - - deformed = 1; - - if (bone && bone->flag & BONE_MULT_VG_ENV) { - weight *= distfactor_to_bone( - co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); - } - - pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib); - } - } - /* if there are vertexgroups but not groups with bones - * (like for softbody groups) */ - if (deformed == 0 && use_envelope) { - for (pchan = data->armOb->pose->chanbase.first; pchan; pchan = pchan->next) { - if (!(pchan->bone->flag & BONE_NO_DEFORM)) { - contrib += dist_bone_deform(pchan, vec, dq, smat, co); - } - } - } - } - else if (use_envelope) { - for (pchan = data->armOb->pose->chanbase.first; pchan; pchan = pchan->next) { - if (!(pchan->bone->flag & BONE_NO_DEFORM)) { - contrib += dist_bone_deform(pchan, vec, dq, smat, co); - } - } - } - - /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */ - if (contrib > 0.0001f) { - if (use_quaternion) { - normalize_dq(dq, contrib); - - if (armature_weight != 1.0f) { - copy_v3_v3(dco, co); - mul_v3m3_dq(dco, (defMats) ? summat : NULL, dq); - sub_v3_v3(dco, co); - mul_v3_fl(dco, armature_weight); - add_v3_v3(co, dco); - } - else { - mul_v3m3_dq(co, (defMats) ? summat : NULL, dq); - } - - smat = summat; - } - else { - mul_v3_fl(vec, armature_weight / contrib); - add_v3_v3v3(co, vec, co); - } - - if (defMats) { - float pre[3][3], post[3][3], tmpmat[3][3]; - - copy_m3_m4(pre, data->premat); - copy_m3_m4(post, data->postmat); - copy_m3_m3(tmpmat, defMats[i]); - - if (!use_quaternion) { /* quaternion already is scale corrected */ - mul_m3_fl(smat, armature_weight / contrib); - } - - mul_m3_series(defMats[i], post, smat, pre, tmpmat); - } - } - - /* always, check above code */ - mul_m4_v3(data->postmat, co); - - /* interpolate with previous modifier position using weight group */ - if (prevCos) { - float mw = 1.0f - prevco_weight; - vertexCos[i][0] = prevco_weight * vertexCos[i][0] + mw * co[0]; - vertexCos[i][1] = prevco_weight * vertexCos[i][1] + mw * co[1]; - vertexCos[i][2] = prevco_weight * vertexCos[i][2] + mw * co[2]; - } -} - -void armature_deform_verts(Object *armOb, - Object *target, - const Mesh *mesh, - float (*vertexCos)[3], - float (*defMats)[3][3], - int numVerts, - int deformflag, - float (*prevCos)[3], - const char *defgrp_name, - bGPDstroke *gps) -{ - bArmature *arm = armOb->data; - bPoseChannel **defnrToPC = NULL; - MDeformVert *dverts = NULL; - bDeformGroup *dg; - const bool use_envelope = (deformflag & ARM_DEF_ENVELOPE) != 0; - const bool use_quaternion = (deformflag & ARM_DEF_QUATERNION) != 0; - const bool invert_vgroup = (deformflag & ARM_DEF_INVERT_VGROUP) != 0; - int defbase_tot = 0; /* safety for vertexgroup index overflow */ - int i, target_totvert = 0; /* safety for vertexgroup overflow */ - bool use_dverts = false; - int armature_def_nr; - - /* in editmode, or not an armature */ - if (arm->edbo || (armOb->pose == NULL)) { - return; - } - - if ((armOb->pose->flag & POSE_RECALC) != 0) { - CLOG_ERROR(&LOG, - "Trying to evaluate influence of armature '%s' which needs Pose recalc!", - armOb->id.name); - BLI_assert(0); - } - - /* get the def_nr for the overall armature vertex group if present */ - armature_def_nr = BKE_object_defgroup_name_index(target, defgrp_name); - - if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { - defbase_tot = BLI_listbase_count(&target->defbase); - - if (target->type == OB_MESH) { - Mesh *me = target->data; - dverts = me->dvert; - if (dverts) { - target_totvert = me->totvert; - } - } - else if (target->type == OB_LATTICE) { - Lattice *lt = target->data; - dverts = lt->dvert; - if (dverts) { - target_totvert = lt->pntsu * lt->pntsv * lt->pntsw; - } - } - else if (target->type == OB_GPENCIL) { - dverts = gps->dvert; - if (dverts) { - target_totvert = gps->totpoints; - } - } - } - - /* get a vertex-deform-index to posechannel array */ - if (deformflag & ARM_DEF_VGROUP) { - if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { - /* if we have a Mesh, only use dverts if it has them */ - if (mesh) { - use_dverts = (mesh->dvert != NULL); - } - else if (dverts) { - use_dverts = true; - } - - if (use_dverts) { - defnrToPC = MEM_callocN(sizeof(*defnrToPC) * defbase_tot, "defnrToBone"); - /* TODO(sergey): Some considerations here: - * - * - Check whether keeping this consistent across frames gives speedup. - */ - for (i = 0, dg = target->defbase.first; dg; i++, dg = dg->next) { - defnrToPC[i] = BKE_pose_channel_find_name(armOb->pose, dg->name); - /* exclude non-deforming bones */ - if (defnrToPC[i]) { - if (defnrToPC[i]->bone->flag & BONE_NO_DEFORM) { - defnrToPC[i] = NULL; - } - } - } - } - } - } - - ArmatureUserdata data = {.armOb = armOb, - .target = target, - .mesh = mesh, - .vertexCos = vertexCos, - .defMats = defMats, - .prevCos = prevCos, - .use_envelope = use_envelope, - .use_quaternion = use_quaternion, - .invert_vgroup = invert_vgroup, - .use_dverts = use_dverts, - .armature_def_nr = armature_def_nr, - .target_totvert = target_totvert, - .dverts = dverts, - .defbase_tot = defbase_tot, - .defnrToPC = defnrToPC}; - - float obinv[4][4]; - invert_m4_m4(obinv, target->obmat); - - mul_m4_m4m4(data.postmat, obinv, armOb->obmat); - invert_m4_m4(data.premat, data.postmat); - - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 32; - BLI_task_parallel_range(0, numVerts, &data, armature_vert_task, &settings); - - if (defnrToPC) { - MEM_freeN(defnrToPC); - } -} - -/* ************ END Armature Deform ******************* */ +/* -------------------------------------------------------------------- */ +/** \name Bone Space to Space Conversion API + * \{ */ void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[4][4], @@ -1832,8 +1386,6 @@ void get_objectspace_bone_matrix(struct Bone *bone, copy_m4_m4(M_accumulatedMatrix, bone->arm_mat); } -/* **************** Space to Space API ****************** */ - /* Convert World-Space Matrix to Pose-Space Matrix */ void BKE_armature_mat_world_to_pose(Object *ob, float inmat[4][4], float outmat[4][4]) { @@ -1868,6 +1420,12 @@ void BKE_armature_loc_world_to_pose(Object *ob, const float inloc[3], float outl copy_v3_v3(outloc, nLocMat[3]); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Bone Matrix Calculation API + * \{ */ + /* Simple helper, computes the offset bone matrix. * offs_bone = yoffs(b-1) + root(b) + bonemat(b). */ void BKE_bone_offset_matrix_get(const Bone *bone, float offs_bone[4][4]) @@ -2156,6 +1714,14 @@ void BKE_armature_loc_pose_to_bone(bPoseChannel *pchan, const float inloc[3], fl copy_v3_v3(outloc, nLocMat[3]); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Bone Matrix Read/Write API + * + * High level functions for transforming bones and reading the transform values. + * \{ */ + void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph, Object *ob, bPoseChannel *pchan, @@ -2255,8 +1821,13 @@ void BKE_armature_mat_pose_to_delta(float delta_mat[4][4], mul_m4_m4m4(delta_mat, imat, pose_mat); } -/* **************** Rotation Mode Conversions ****************************** */ -/* Used for Objects and Pose Channels, since both can have multiple rotation representations */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Rotation Mode Conversions + * + * Used for Objects and Pose Channels, since both can have multiple rotation representations. + * \{ */ /* Called from RNA when rotation mode changes * - the result should be that the rotations given in the provided pointers have had conversions @@ -2308,9 +1879,15 @@ void BKE_rotMode_change_values( } } -/* **************** The new & simple (but OK!) armature evaluation ********* */ +/** \} */ -/* ****************** And how it works! **************************************** +/* -------------------------------------------------------------------- */ +/** \name Bone Vector, Roll Conversion + * + * Used for Objects and Pose Channels, since both can have multiple rotation representations. + * + * How it Works + * ============ * * This is the bone transformation trick; they're hierarchical so each bone(b) * is in the coord system of bone(b-1): @@ -2326,7 +1903,7 @@ void BKE_rotMode_change_values( * * pose_mat(b)= arm_mat(b) * chan_mat(b) * - * *************************************************************************** */ + * \{ */ /* Computes vector and roll based on a rotation. * "mat" must contain only a rotation, and no scaling. */ @@ -2494,6 +2071,12 @@ void vec_roll_to_mat3(const float vec[3], const float roll, float mat[3][3]) vec_roll_to_mat3_normalized(nor, roll, mat); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Armature Bone Matrix Calculation (Recursive) + * \{ */ + /** * Recursive part, calculates rest-position of entire tree of children. * \note Used when exiting edit-mode too. @@ -2548,6 +2131,12 @@ void BKE_armature_where_is(bArmature *arm) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Pose Rebuild + * \{ */ + /* if bone layer is protected, copy the data from from->pose * when used with linked libraries this copies from the linked pose into the local pose */ static void pose_proxy_sync(Object *ob, Object *from, int layer_protected) @@ -2828,7 +2417,11 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_ } } -/* ********************** THE POSE SOLVER ******************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Pose Solver + * \{ */ /* loc/rot/size to given mat4 */ void BKE_pchan_to_mat4(const bPoseChannel *pchan, float chan_mat[4][4]) @@ -3024,7 +2617,12 @@ void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob) } } -/************** Bounding box ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Calculate Bounding Box (Armature & Pose) + * \{ */ + static int minmax_armature(Object *ob, float r_min[3], float r_max[3]) { bPoseChannel *pchan; @@ -3106,7 +2704,11 @@ bool BKE_pose_minmax(Object *ob, float r_min[3], float r_max[3], bool use_hidden return changed; } -/************** Graph evaluation ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Graph Evaluation + * \{ */ bPoseChannel *BKE_armature_ik_solver_find_root(bPoseChannel *pchan, bKinematicConstraint *data) { @@ -3145,3 +2747,5 @@ bPoseChannel *BKE_armature_splineik_solver_find_root(bPoseChannel *pchan, } return rootchan; } + +/** \} */ diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c new file mode 100644 index 00000000000..e757e30e524 --- /dev/null +++ b/source/blender/blenkernel/intern/armature_deform.c @@ -0,0 +1,688 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup bke + * + * Deform coordinates by a armature object (used by modifier). + */ + +#include <ctype.h> +#include <float.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_task.h" +#include "BLI_utildefines.h" + +#include "DNA_armature_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_lattice_types.h" +#include "DNA_listBase.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_deform.h" +#include "BKE_editmesh.h" +#include "BKE_lattice.h" + +#include "DEG_depsgraph_build.h" + +#include "CLG_log.h" + +static CLG_LogRef LOG = {"bke.armature_deform"}; + +/* -------------------------------------------------------------------- */ +/** \name Armature Deform Internal Utilities + * \{ */ + +/* Add the effect of one bone or B-Bone segment to the accumulated result. */ +static void pchan_deform_accumulate(const DualQuat *deform_dq, + const float deform_mat[4][4], + const float co_in[3], + float weight, + float co_accum[3], + DualQuat *dq_accum, + float mat_accum[3][3]) +{ + if (weight == 0.0f) { + return; + } + + if (dq_accum) { + BLI_assert(!co_accum); + + add_weighted_dq_dq(dq_accum, deform_dq, weight); + } + else { + float tmp[3]; + mul_v3_m4v3(tmp, deform_mat, co_in); + + sub_v3_v3(tmp, co_in); + madd_v3_v3fl(co_accum, tmp, weight); + + if (mat_accum) { + float tmpmat[3][3]; + copy_m3_m4(tmpmat, deform_mat); + + madd_m3_m3m3fl(mat_accum, mat_accum, tmpmat, weight); + } + } +} + +static void b_bone_deform(const bPoseChannel *pchan, + const float co[3], + float weight, + float vec[3], + DualQuat *dq, + float defmat[3][3]) +{ + const DualQuat *quats = pchan->runtime.bbone_dual_quats; + const Mat4 *mats = pchan->runtime.bbone_deform_mats; + const float(*mat)[4] = mats[0].mat; + float blend, y; + int index; + + /* Transform co to bone space and get its y component. */ + y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1]; + + /* Calculate the indices of the 2 affecting b_bone segments. */ + BKE_pchan_bbone_deform_segment_index(pchan, y / pchan->bone->length, &index, &blend); + + pchan_deform_accumulate( + &quats[index], mats[index + 1].mat, co, weight * (1.0f - blend), vec, dq, defmat); + pchan_deform_accumulate( + &quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat); +} + +/* using vec with dist to bone b1 - b2 */ +float distfactor_to_bone( + const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist) +{ + float dist_sq; + float bdelta[3]; + float pdelta[3]; + float hsqr, a, l, rad; + + sub_v3_v3v3(bdelta, b2, b1); + l = normalize_v3(bdelta); + + sub_v3_v3v3(pdelta, vec, b1); + + a = dot_v3v3(bdelta, pdelta); + hsqr = len_squared_v3(pdelta); + + if (a < 0.0f) { + /* If we're past the end of the bone, do a spherical field attenuation thing */ + dist_sq = len_squared_v3v3(b1, vec); + rad = rad1; + } + else if (a > l) { + /* If we're past the end of the bone, do a spherical field attenuation thing */ + dist_sq = len_squared_v3v3(b2, vec); + rad = rad2; + } + else { + dist_sq = (hsqr - (a * a)); + + if (l != 0.0f) { + rad = a / l; + rad = rad * rad2 + (1.0f - rad) * rad1; + } + else { + rad = rad1; + } + } + + a = rad * rad; + if (dist_sq < a) { + return 1.0f; + } + else { + l = rad + rdist; + l *= l; + if (rdist == 0.0f || dist_sq >= l) { + return 0.0f; + } + else { + a = sqrtf(dist_sq) - rad; + return 1.0f - (a * a) / (rdist * rdist); + } + } +} + +static float dist_bone_deform( + bPoseChannel *pchan, float vec[3], DualQuat *dq, float mat[3][3], const float co[3]) +{ + Bone *bone = pchan->bone; + float fac, contrib = 0.0; + + if (bone == NULL) { + return 0.0f; + } + + fac = distfactor_to_bone( + co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); + + if (fac > 0.0f) { + fac *= bone->weight; + contrib = fac; + if (contrib > 0.0f) { + if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) { + b_bone_deform(pchan, co, fac, vec, dq, mat); + } + else { + pchan_deform_accumulate( + &pchan->runtime.deform_dual_quat, pchan->chan_mat, co, fac, vec, dq, mat); + } + } + } + + return contrib; +} + +static void pchan_bone_deform(bPoseChannel *pchan, + float weight, + float vec[3], + DualQuat *dq, + float mat[3][3], + const float co[3], + float *contrib) +{ + Bone *bone = pchan->bone; + + if (!weight) { + return; + } + + if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) { + b_bone_deform(pchan, co, weight, vec, dq, mat); + } + else { + pchan_deform_accumulate( + &pchan->runtime.deform_dual_quat, pchan->chan_mat, co, weight, vec, dq, mat); + } + + (*contrib) += weight; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Armature Deform #BKE_armature_deform_coords API + * + * #BKE_armature_deform_coords and related functions. + * \{ */ + +typedef struct ArmatureUserdata { + const Object *ob_arm; + const Object *ob_target; + const Mesh *me_target; + float (*vert_coords)[3]; + float (*vert_deform_mats)[3][3]; + float (*vert_coords_prev)[3]; + + bool use_envelope; + bool use_quaternion; + bool invert_vgroup; + bool use_dverts; + + int armature_def_nr; + + const MDeformVert *dverts; + int dverts_len; + + bPoseChannel **pchan_from_defbase; + int defbase_len; + + float premat[4][4]; + float postmat[4][4]; + + /** Specific data types. */ + struct { + int cd_dvert_offset; + } bmesh; +} ArmatureUserdata; + +static void armature_vert_task_with_dvert(const ArmatureUserdata *data, + const int i, + const MDeformVert *dvert) +{ + float(*const vert_coords)[3] = data->vert_coords; + float(*const vert_deform_mats)[3][3] = data->vert_deform_mats; + float(*const vert_coords_prev)[3] = data->vert_coords_prev; + const bool use_envelope = data->use_envelope; + const bool use_quaternion = data->use_quaternion; + const bool use_dverts = data->use_dverts; + const int armature_def_nr = data->armature_def_nr; + + DualQuat sumdq, *dq = NULL; + bPoseChannel *pchan; + float *co, dco[3]; + float sumvec[3], summat[3][3]; + float *vec = NULL, (*smat)[3] = NULL; + float contrib = 0.0f; + float armature_weight = 1.0f; /* default to 1 if no overall def group */ + float prevco_weight = 1.0f; /* weight for optional cached vertexcos */ + + if (use_quaternion) { + memset(&sumdq, 0, sizeof(DualQuat)); + dq = &sumdq; + } + else { + zero_v3(sumvec); + vec = sumvec; + + if (vert_deform_mats) { + zero_m3(summat); + smat = summat; + } + } + + if (armature_def_nr != -1 && dvert) { + armature_weight = BKE_defvert_find_weight(dvert, armature_def_nr); + + if (data->invert_vgroup) { + armature_weight = 1.0f - armature_weight; + } + + /* hackish: the blending factor can be used for blending with vert_coords_prev too */ + if (vert_coords_prev) { + prevco_weight = armature_weight; + armature_weight = 1.0f; + } + } + + /* check if there's any point in calculating for this vert */ + if (armature_weight == 0.0f) { + return; + } + + /* get the coord we work on */ + co = vert_coords_prev ? vert_coords_prev[i] : vert_coords[i]; + + /* Apply the object's matrix */ + mul_m4_v3(data->premat, co); + + if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */ + const MDeformWeight *dw = dvert->dw; + int deformed = 0; + unsigned int j; + for (j = dvert->totweight; j != 0; j--, dw++) { + const uint index = dw->def_nr; + if (index < data->defbase_len && (pchan = data->pchan_from_defbase[index])) { + float weight = dw->weight; + Bone *bone = pchan->bone; + + deformed = 1; + + if (bone && bone->flag & BONE_MULT_VG_ENV) { + weight *= distfactor_to_bone( + co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); + } + + pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib); + } + } + /* if there are vertexgroups but not groups with bones + * (like for softbody groups) */ + if (deformed == 0 && use_envelope) { + for (pchan = data->ob_arm->pose->chanbase.first; pchan; pchan = pchan->next) { + if (!(pchan->bone->flag & BONE_NO_DEFORM)) { + contrib += dist_bone_deform(pchan, vec, dq, smat, co); + } + } + } + } + else if (use_envelope) { + for (pchan = data->ob_arm->pose->chanbase.first; pchan; pchan = pchan->next) { + if (!(pchan->bone->flag & BONE_NO_DEFORM)) { + contrib += dist_bone_deform(pchan, vec, dq, smat, co); + } + } + } + + /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */ + if (contrib > 0.0001f) { + if (use_quaternion) { + normalize_dq(dq, contrib); + + if (armature_weight != 1.0f) { + copy_v3_v3(dco, co); + mul_v3m3_dq(dco, (vert_deform_mats) ? summat : NULL, dq); + sub_v3_v3(dco, co); + mul_v3_fl(dco, armature_weight); + add_v3_v3(co, dco); + } + else { + mul_v3m3_dq(co, (vert_deform_mats) ? summat : NULL, dq); + } + + smat = summat; + } + else { + mul_v3_fl(vec, armature_weight / contrib); + add_v3_v3v3(co, vec, co); + } + + if (vert_deform_mats) { + float pre[3][3], post[3][3], tmpmat[3][3]; + + copy_m3_m4(pre, data->premat); + copy_m3_m4(post, data->postmat); + copy_m3_m3(tmpmat, vert_deform_mats[i]); + + if (!use_quaternion) { /* quaternion already is scale corrected */ + mul_m3_fl(smat, armature_weight / contrib); + } + + mul_m3_series(vert_deform_mats[i], post, smat, pre, tmpmat); + } + } + + /* always, check above code */ + mul_m4_v3(data->postmat, co); + + /* interpolate with previous modifier position using weight group */ + if (vert_coords_prev) { + float mw = 1.0f - prevco_weight; + vert_coords[i][0] = prevco_weight * vert_coords[i][0] + mw * co[0]; + vert_coords[i][1] = prevco_weight * vert_coords[i][1] + mw * co[1]; + vert_coords[i][2] = prevco_weight * vert_coords[i][2] + mw * co[2]; + } +} + +static void armature_vert_task(void *__restrict userdata, + const int i, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + const ArmatureUserdata *data = userdata; + const MDeformVert *dvert; + if (data->use_dverts || data->armature_def_nr != -1) { + if (data->me_target) { + BLI_assert(i < data->me_target->totvert); + if (data->me_target->dvert != NULL) { + dvert = data->me_target->dvert + i; + } + else { + dvert = NULL; + } + } + else if (data->dverts && i < data->dverts_len) { + dvert = data->dverts + i; + } + else { + dvert = NULL; + } + } + else { + dvert = NULL; + } + + armature_vert_task_with_dvert(data, i, dvert); +} + +static void armature_vert_task_editmesh(void *__restrict userdata, MempoolIterData *iter) +{ + const ArmatureUserdata *data = userdata; + BMVert *v = (BMVert *)iter; + MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(v, data->bmesh.cd_dvert_offset); + armature_vert_task_with_dvert(data, BM_elem_index_get(v), dvert); +} + +static void armature_vert_task_editmesh_no_dvert(void *__restrict userdata, MempoolIterData *iter) +{ + const ArmatureUserdata *data = userdata; + BMVert *v = (BMVert *)iter; + armature_vert_task_with_dvert(data, BM_elem_index_get(v), NULL); +} + +static void armature_deform_coords_impl(const Object *ob_arm, + const Object *ob_target, + float (*vert_coords)[3], + float (*vert_deform_mats)[3][3], + const int vert_coords_len, + const int deformflag, + float (*vert_coords_prev)[3], + const char *defgrp_name, + const Mesh *me_target, + BMEditMesh *em_target, + bGPDstroke *gps_target) +{ + bArmature *arm = ob_arm->data; + bPoseChannel **pchan_from_defbase = NULL; + const MDeformVert *dverts = NULL; + bDeformGroup *dg; + const bool use_envelope = (deformflag & ARM_DEF_ENVELOPE) != 0; + const bool use_quaternion = (deformflag & ARM_DEF_QUATERNION) != 0; + const bool invert_vgroup = (deformflag & ARM_DEF_INVERT_VGROUP) != 0; + int defbase_len = 0; /* safety for vertexgroup index overflow */ + int i, dverts_len = 0; /* safety for vertexgroup overflow */ + bool use_dverts = false; + int armature_def_nr; + int cd_dvert_offset = -1; + + /* in editmode, or not an armature */ + if (arm->edbo || (ob_arm->pose == NULL)) { + return; + } + + if ((ob_arm->pose->flag & POSE_RECALC) != 0) { + CLOG_ERROR(&LOG, + "Trying to evaluate influence of armature '%s' which needs Pose recalc!", + ob_arm->id.name); + BLI_assert(0); + } + + /* get the def_nr for the overall armature vertex group if present */ + armature_def_nr = BKE_object_defgroup_name_index(ob_target, defgrp_name); + + if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { + defbase_len = BLI_listbase_count(&ob_target->defbase); + + if (ob_target->type == OB_MESH) { + if (em_target == NULL) { + Mesh *me = ob_target->data; + dverts = me->dvert; + if (dverts) { + dverts_len = me->totvert; + } + } + } + else if (ob_target->type == OB_LATTICE) { + Lattice *lt = ob_target->data; + dverts = lt->dvert; + if (dverts) { + dverts_len = lt->pntsu * lt->pntsv * lt->pntsw; + } + } + else if (ob_target->type == OB_GPENCIL) { + dverts = gps_target->dvert; + if (dverts) { + dverts_len = gps_target->totpoints; + } + } + } + + /* get a vertex-deform-index to posechannel array */ + if (deformflag & ARM_DEF_VGROUP) { + if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { + /* if we have a Mesh, only use dverts if it has them */ + if (em_target) { + cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT); + use_dverts = (cd_dvert_offset != -1); + } + else if (me_target) { + use_dverts = (me_target->dvert != NULL); + } + else if (dverts) { + use_dverts = true; + } + + if (use_dverts) { + pchan_from_defbase = MEM_callocN(sizeof(*pchan_from_defbase) * defbase_len, "defnrToBone"); + /* TODO(sergey): Some considerations here: + * + * - Check whether keeping this consistent across frames gives speedup. + */ + for (i = 0, dg = ob_target->defbase.first; dg; i++, dg = dg->next) { + pchan_from_defbase[i] = BKE_pose_channel_find_name(ob_arm->pose, dg->name); + /* exclude non-deforming bones */ + if (pchan_from_defbase[i]) { + if (pchan_from_defbase[i]->bone->flag & BONE_NO_DEFORM) { + pchan_from_defbase[i] = NULL; + } + } + } + } + } + } + + ArmatureUserdata data = { + .ob_arm = ob_arm, + .ob_target = ob_target, + .me_target = me_target, + .vert_coords = vert_coords, + .vert_deform_mats = vert_deform_mats, + .vert_coords_prev = vert_coords_prev, + .use_envelope = use_envelope, + .use_quaternion = use_quaternion, + .invert_vgroup = invert_vgroup, + .use_dverts = use_dverts, + .armature_def_nr = armature_def_nr, + .dverts = dverts, + .dverts_len = dverts_len, + .pchan_from_defbase = pchan_from_defbase, + .defbase_len = defbase_len, + .bmesh = + { + .cd_dvert_offset = cd_dvert_offset, + }, + }; + + float obinv[4][4]; + invert_m4_m4(obinv, ob_target->obmat); + + mul_m4_m4m4(data.postmat, obinv, ob_arm->obmat); + invert_m4_m4(data.premat, data.postmat); + + if (em_target != NULL) { + /* While this could cause an extra loop over mesh data, in most cases this will + * have already been properly set. */ + BM_mesh_elem_index_ensure(em_target->bm, BM_VERT); + + if (use_dverts) { + BLI_task_parallel_mempool(em_target->bm->vpool, &data, armature_vert_task_editmesh, true); + } + else { + BLI_task_parallel_mempool( + em_target->bm->vpool, &data, armature_vert_task_editmesh_no_dvert, true); + } + } + else { + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 32; + BLI_task_parallel_range(0, vert_coords_len, &data, armature_vert_task, &settings); + } + + if (pchan_from_defbase) { + MEM_freeN(pchan_from_defbase); + } +} + +void BKE_armature_deform_coords_with_gpencil_stroke(const Object *ob_arm, + const Object *ob_target, + float (*vert_coords)[3], + float (*vert_deform_mats)[3][3], + int vert_coords_len, + int deformflag, + float (*vert_coords_prev)[3], + const char *defgrp_name, + bGPDstroke *gps_target) +{ + armature_deform_coords_impl(ob_arm, + ob_target, + vert_coords, + vert_deform_mats, + vert_coords_len, + deformflag, + vert_coords_prev, + defgrp_name, + NULL, + NULL, + gps_target); +} + +void BKE_armature_deform_coords_with_mesh(const Object *ob_arm, + const Object *ob_target, + float (*vert_coords)[3], + float (*vert_deform_mats)[3][3], + int vert_coords_len, + int deformflag, + float (*vert_coords_prev)[3], + const char *defgrp_name, + const Mesh *me_target) +{ + armature_deform_coords_impl(ob_arm, + ob_target, + vert_coords, + vert_deform_mats, + vert_coords_len, + deformflag, + vert_coords_prev, + defgrp_name, + me_target, + NULL, + NULL); +} + +void BKE_armature_deform_coords_with_editmesh(const Object *ob_arm, + const Object *ob_target, + float (*vert_coords)[3], + float (*vert_deform_mats)[3][3], + int vert_coords_len, + int deformflag, + float (*vert_coords_prev)[3], + const char *defgrp_name, + BMEditMesh *em_target) +{ + armature_deform_coords_impl(ob_arm, + ob_target, + vert_coords, + vert_deform_mats, + vert_coords_len, + deformflag, + vert_coords_prev, + defgrp_name, + NULL, + em_target, + NULL); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 0b9780ac81c..ce6143116a1 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -146,6 +146,7 @@ void cloth_init(ClothModifierData *clmd) clmd->sim_parms->uniform_pressure_force = 0.0f; clmd->sim_parms->target_volume = 0.0f; clmd->sim_parms->pressure_factor = 1.0f; + clmd->sim_parms->fluid_density = 0.0f; clmd->sim_parms->vgroup_pressure = 0; // also from softbodies diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 290b181f172..a9d3c7c1b65 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -716,6 +716,31 @@ static void collection_tag_update_parent_recursive(Main *bmain, } } +static Collection *collection_parent_editable_find_recursive(Collection *collection) +{ + if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection)) { + return collection; + } + + if (collection->flag & COLLECTION_IS_MASTER) { + return NULL; + } + + LISTBASE_FOREACH (CollectionParent *, collection_parent, &collection->parents) { + if (!ID_IS_LINKED(collection_parent->collection) && + !ID_IS_OVERRIDE_LIBRARY(collection_parent->collection)) { + return collection_parent->collection; + } + Collection *editable_collection = collection_parent_editable_find_recursive( + collection_parent->collection); + if (editable_collection != NULL) { + return editable_collection; + } + } + + return NULL; +} + static bool collection_object_add( Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us) { @@ -786,6 +811,15 @@ bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob) return false; } + collection = collection_parent_editable_find_recursive(collection); + + /* Only case where this pointer can be NULL is when scene itself is linked, this case should + * never be reached. */ + BLI_assert(collection != NULL); + if (collection == NULL) { + return false; + } + if (!collection_object_add(bmain, collection, ob, 0, true)) { return false; } @@ -808,7 +842,8 @@ void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, O bool is_instantiated = false; FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) { - if (!ID_IS_LINKED(collection) && BKE_collection_has_object(collection, ob_src)) { + if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) && + BKE_collection_has_object(collection, ob_src)) { collection_object_add(bmain, collection, ob_dst, 0, true); is_instantiated = true; } diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index e67cf8573f3..0b65f53708f 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -29,7 +29,6 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" -#include "BLI_linklist.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -43,7 +42,6 @@ /* for dereferencing pointers */ #include "DNA_key_types.h" #include "DNA_object_types.h" -#include "DNA_scene_types.h" #include "DNA_vfont_types.h" #include "BKE_curve.h" @@ -54,7 +52,6 @@ #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" -#include "BKE_material.h" #include "BKE_object.h" #include "DEG_depsgraph.h" diff --git a/source/blender/blenkernel/intern/curve_deform.c b/source/blender/blenkernel/intern/curve_deform.c new file mode 100644 index 00000000000..d4f197521a1 --- /dev/null +++ b/source/blender/blenkernel/intern/curve_deform.c @@ -0,0 +1,504 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup bke + * + * Deform coordinates by a curve object (used by modifier). + */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "DNA_curve_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_anim_path.h" +#include "BKE_curve.h" +#include "BKE_editmesh.h" +#include "BKE_lattice.h" +#include "BKE_modifier.h" + +#include "BKE_deform.h" + +/* -------------------------------------------------------------------- */ +/** \name Curve Deform Internal Utilities + * \{ */ + +/** + * Calculations is in local space of deformed object + * so we store matrices to transform points to/from local-space. + */ +typedef struct { + float dmin[3], dmax[3]; + float curvespace[4][4], objectspace[4][4], objectspace3[3][3]; + int no_rot_axis; +} CurveDeform; + +static void init_curve_deform(const Object *ob_curve, const Object *ob_target, CurveDeform *cd) +{ + float imat[4][4]; + invert_m4_m4(imat, ob_target->obmat); + mul_m4_m4m4(cd->objectspace, imat, ob_curve->obmat); + invert_m4_m4(cd->curvespace, cd->objectspace); + copy_m3_m4(cd->objectspace3, cd->objectspace); + cd->no_rot_axis = 0; +} + +/** + * This makes sure we can extend for non-cyclic. + * + * \return Success. + */ +static bool where_on_path_deform(const Object *ob_curve, + float ctime, + float r_vec[4], + float r_dir[3], + float r_quat[4], + float *r_radius) +{ + BevList *bl; + float ctime1; + int cycl = 0; + + /* test for cyclic */ + bl = ob_curve->runtime.curve_cache->bev.first; + if (!bl->nr) { + return false; + } + if (bl->poly > -1) { + cycl = 1; + } + + if (cycl == 0) { + ctime1 = CLAMPIS(ctime, 0.0f, 1.0f); + } + else { + ctime1 = ctime; + } + + /* vec needs 4 items */ + if (where_on_path(ob_curve, ctime1, r_vec, r_dir, r_quat, r_radius, NULL)) { + + if (cycl == 0) { + Path *path = ob_curve->runtime.curve_cache->path; + float dvec[3]; + + if (ctime < 0.0f) { + sub_v3_v3v3(dvec, path->data[1].vec, path->data[0].vec); + mul_v3_fl(dvec, ctime * (float)path->len); + add_v3_v3(r_vec, dvec); + if (r_quat) { + copy_qt_qt(r_quat, path->data[0].quat); + } + if (r_radius) { + *r_radius = path->data[0].radius; + } + } + else if (ctime > 1.0f) { + sub_v3_v3v3(dvec, path->data[path->len - 1].vec, path->data[path->len - 2].vec); + mul_v3_fl(dvec, (ctime - 1.0f) * (float)path->len); + add_v3_v3(r_vec, dvec); + if (r_quat) { + copy_qt_qt(r_quat, path->data[path->len - 1].quat); + } + if (r_radius) { + *r_radius = path->data[path->len - 1].radius; + } + /* weight - not used but could be added */ + } + } + return true; + } + return false; +} + +/** + * For each point, rotate & translate to curve use path, since it has constant distances. + * + * \param co: local coord, result local too. + * \param r_quat: returns quaternion for rotation, + * using #CurveDeform.no_rot_axis axis is using another define. + */ +static bool calc_curve_deform( + const Object *ob_curve, float co[3], const short axis, const CurveDeform *cd, float r_quat[4]) +{ + Curve *cu = ob_curve->data; + float fac, loc[4], dir[3], new_quat[4], radius; + short index; + const bool is_neg_axis = (axis > 2); + + if (ob_curve->runtime.curve_cache == NULL) { + /* Happens with a cyclic dependencies. */ + return false; + } + + if (ob_curve->runtime.curve_cache->path == NULL) { + return false; /* happens on append, cyclic dependencies and empty curves */ + } + + /* options */ + if (is_neg_axis) { + index = axis - 3; + if (cu->flag & CU_STRETCH) { + fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]); + } + else { + fac = -(co[index] - cd->dmax[index]) / (ob_curve->runtime.curve_cache->path->totdist); + } + } + else { + index = axis; + if (cu->flag & CU_STRETCH) { + fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]); + } + else { + if (LIKELY(ob_curve->runtime.curve_cache->path->totdist > FLT_EPSILON)) { + fac = +(co[index] - cd->dmin[index]) / (ob_curve->runtime.curve_cache->path->totdist); + } + else { + fac = 0.0f; + } + } + } + + if (where_on_path_deform(ob_curve, fac, loc, dir, new_quat, &radius)) { /* returns OK */ + float quat[4], cent[3]; + + if (cd->no_rot_axis) { /* set by caller */ + + /* This is not exactly the same as 2.4x, since the axis is having rotation removed rather + * than changing the axis before calculating the tilt but serves much the same purpose. */ + float dir_flat[3] = {0, 0, 0}, q[4]; + copy_v3_v3(dir_flat, dir); + dir_flat[cd->no_rot_axis - 1] = 0.0f; + + normalize_v3(dir); + normalize_v3(dir_flat); + + rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */ + + mul_qt_qtqt(new_quat, q, new_quat); + } + + /* Logic for 'cent' orientation * + * + * The way 'co' is copied to 'cent' may seem to have no meaning, but it does. + * + * Use a curve modifier to stretch a cube out, color each side RGB, + * positive side light, negative dark. + * view with X up (default), from the angle that you can see 3 faces RGB colors (light), + * anti-clockwise + * Notice X,Y,Z Up all have light colors and each ordered CCW. + * + * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell + * + * note: moved functions into quat_apply_track/vec_apply_track + * */ + copy_qt_qt(quat, new_quat); + copy_v3_v3(cent, co); + + /* zero the axis which is not used, + * the big block of text above now applies to these 3 lines */ + quat_apply_track( + quat, + axis, + (axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */ + vec_apply_track(cent, axis); + cent[index] = 0.0f; + + /* scale if enabled */ + if (cu->flag & CU_PATH_RADIUS) { + mul_v3_fl(cent, radius); + } + + /* local rotation */ + normalize_qt(quat); + mul_qt_v3(quat, cent); + + /* translation */ + add_v3_v3v3(co, cent, loc); + + if (r_quat) { + copy_qt_qt(r_quat, quat); + } + + return true; + } + return false; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Curve Deform #BKE_curve_deform_coords API + * + * #BKE_curve_deform and related functions. + * \{ */ + +static void curve_deform_coords_impl(const Object *ob_curve, + const Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const MDeformVert *dvert, + const int defgrp_index, + const short flag, + const short defaxis, + BMEditMesh *em_target) +{ + Curve *cu; + int a; + CurveDeform cd; + const bool is_neg_axis = (defaxis > 2); + const bool invert_vgroup = (flag & MOD_CURVE_INVERT_VGROUP) != 0; + bool use_dverts = false; + int cd_dvert_offset; + + if (ob_curve->type != OB_CURVE) { + return; + } + + cu = ob_curve->data; + + init_curve_deform(ob_curve, ob_target, &cd); + + if (cu->flag & CU_DEFORM_BOUNDS_OFF) { + /* Dummy bounds. */ + if (is_neg_axis == false) { + cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f; + cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f; + } + else { + /* Negative, these bounds give a good rest position. */ + cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f; + cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f; + } + } + else { + /* Set mesh min/max bounds. */ + INIT_MINMAX(cd.dmin, cd.dmax); + } + + if (em_target != NULL) { + cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT); + if (cd_dvert_offset != -1) { + use_dverts = true; + } + } + else { + if (dvert != NULL) { + use_dverts = true; + } + } + + if (use_dverts) { + if (cu->flag & CU_DEFORM_BOUNDS_OFF) { + +#define DEFORM_OP(dvert) \ + { \ + const float weight = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dvert, defgrp_index) : \ + BKE_defvert_find_weight(dvert, defgrp_index); \ + if (weight > 0.0f) { \ + float vec[3]; \ + mul_m4_v3(cd.curvespace, vert_coords[a]); \ + copy_v3_v3(vec, vert_coords[a]); \ + calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL); \ + interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight); \ + mul_m4_v3(cd.objectspace, vert_coords[a]); \ + } \ + } \ + ((void)0) + + if (em_target != NULL) { + BMIter iter; + BMVert *v; + BM_ITER_MESH_INDEX (v, &iter, em_target->bm, BM_VERTS_OF_MESH, a) { + dvert = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset); + DEFORM_OP(dvert); + } + } + else { + for (a = 0; a < vert_coords_len; a++) { + DEFORM_OP(&dvert[a]); + } + } + +#undef DEFORM_OP + } + else { + +#define DEFORM_OP_MINMAX(dvert) \ + { \ + const float weight = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dvert, defgrp_index) : \ + BKE_defvert_find_weight(dvert, defgrp_index); \ + if (weight > 0.0f) { \ + mul_m4_v3(cd.curvespace, vert_coords[a]); \ + minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]); \ + } \ + } \ + ((void)0) + + /* already in 'cd.curvespace', prev for loop */ +#define DEFORM_OP_CLAMPED(dvert) \ + { \ + const float weight = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dvert, defgrp_index) : \ + BKE_defvert_find_weight(dvert, defgrp_index); \ + if (weight > 0.0f) { \ + float vec[3]; \ + copy_v3_v3(vec, vert_coords[a]); \ + calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL); \ + interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight); \ + mul_m4_v3(cd.objectspace, vert_coords[a]); \ + } \ + } \ + ((void)0) + + if (em_target != NULL) { + BMIter iter; + BMVert *v; + BM_ITER_MESH_INDEX (v, &iter, em_target->bm, BM_VERTS_OF_MESH, a) { + dvert = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset); + DEFORM_OP_MINMAX(dvert); + } + + BM_ITER_MESH_INDEX (v, &iter, em_target->bm, BM_VERTS_OF_MESH, a) { + dvert = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset); + DEFORM_OP_CLAMPED(dvert); + } + } + else { + + for (a = 0; a < vert_coords_len; a++) { + DEFORM_OP_MINMAX(&dvert[a]); + } + + for (a = 0; a < vert_coords_len; a++) { + DEFORM_OP_CLAMPED(&dvert[a]); + } + } + } + +#undef DEFORM_OP_MINMAX +#undef DEFORM_OP_CLAMPED + } + else { + if (cu->flag & CU_DEFORM_BOUNDS_OFF) { + for (a = 0; a < vert_coords_len; a++) { + mul_m4_v3(cd.curvespace, vert_coords[a]); + calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL); + mul_m4_v3(cd.objectspace, vert_coords[a]); + } + } + else { + for (a = 0; a < vert_coords_len; a++) { + mul_m4_v3(cd.curvespace, vert_coords[a]); + minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]); + } + + for (a = 0; a < vert_coords_len; a++) { + /* already in 'cd.curvespace', prev for loop */ + calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL); + mul_m4_v3(cd.objectspace, vert_coords[a]); + } + } + } +} + +void BKE_curve_deform_coords(const Object *ob_curve, + const Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const MDeformVert *dvert, + const int defgrp_index, + const short flag, + const short defaxis) +{ + curve_deform_coords_impl( + ob_curve, ob_target, vert_coords, vert_coords_len, dvert, defgrp_index, flag, defaxis, NULL); +} + +void BKE_curve_deform_coords_with_editmesh(const Object *ob_curve, + const Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const int defgrp_index, + const short flag, + const short defaxis, + BMEditMesh *em_target) +{ + curve_deform_coords_impl(ob_curve, + ob_target, + vert_coords, + vert_coords_len, + NULL, + defgrp_index, + flag, + defaxis, + em_target); +} + +/** + * \param orco: Input vec and orco = local coord in curve space + * orco is original not-animated or deformed reference point. + * + * The result written in vec and r_mat. + */ +void BKE_curve_deform_co(const Object *ob_curve, + const Object *ob_target, + const float orco[3], + float vec[3], + const int no_rot_axis, + float r_mat[3][3]) +{ + CurveDeform cd; + float quat[4]; + + if (ob_curve->type != OB_CURVE) { + unit_m3(r_mat); + return; + } + + init_curve_deform(ob_curve, ob_target, &cd); + cd.no_rot_axis = no_rot_axis; /* option to only rotate for XY, for example */ + + copy_v3_v3(cd.dmin, orco); + copy_v3_v3(cd.dmax, orco); + + mul_m4_v3(cd.curvespace, vec); + + if (calc_curve_deform(ob_curve, vec, ob_target->trackflag, &cd, quat)) { + float qmat[3][3]; + + quat_to_mat3(qmat, quat); + mul_m3_m3m3(r_mat, qmat, cd.objectspace3); + } + else { + unit_m3(r_mat); + } + + mul_m4_v3(cd.objectspace, vec); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 9a3965a86f6..b97935d57f2 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -486,14 +486,14 @@ void BKE_defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int } } -bDeformGroup *BKE_object_defgroup_find_name(Object *ob, const char *name) +bDeformGroup *BKE_object_defgroup_find_name(const Object *ob, const char *name) { return (name && name[0] != '\0') ? BLI_findstring(&ob->defbase, name, offsetof(bDeformGroup, name)) : NULL; } -int BKE_object_defgroup_name_index(Object *ob, const char *name) +int BKE_object_defgroup_name_index(const Object *ob, const char *name) { return (name && name[0] != '\0') ? BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)) : @@ -503,7 +503,7 @@ int BKE_object_defgroup_name_index(Object *ob, const char *name) /** * \note caller must free. */ -int *BKE_object_defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_default) +int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const bool use_default) { int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase); @@ -545,7 +545,7 @@ int *BKE_object_defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_ /** * \note caller must free. */ -int *BKE_object_defgroup_flip_map_single(Object *ob, +int *BKE_object_defgroup_flip_map_single(const Object *ob, int *flip_map_len, const bool use_default, int defgroup) @@ -580,7 +580,7 @@ int *BKE_object_defgroup_flip_map_single(Object *ob, } } -int BKE_object_defgroup_flip_index(Object *ob, int index, const bool use_default) +int BKE_object_defgroup_flip_index(const Object *ob, int index, const bool use_default) { bDeformGroup *dg = BLI_findlink(&ob->defbase, index); int flip_index = -1; diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index b889b91e366..2f8500bd1df 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -286,11 +286,11 @@ void BKE_gpencil_lattice_init(Object *ob) return; } if (mmd->cache_data) { - end_latt_deform((struct LatticeDeformData *)mmd->cache_data); + BKE_lattice_deform_data_destroy(mmd->cache_data); } /* init deform data */ - mmd->cache_data = (struct LatticeDeformData *)init_latt_deform(latob, ob); + mmd->cache_data = BKE_lattice_deform_data_create(latob, ob); } } } @@ -303,7 +303,7 @@ void BKE_gpencil_lattice_clear(Object *ob) if (md->type == eGpencilModifierType_Lattice) { LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; if ((mmd) && (mmd->cache_data)) { - end_latt_deform((struct LatticeDeformData *)mmd->cache_data); + BKE_lattice_deform_data_destroy(mmd->cache_data); mmd->cache_data = NULL; } } @@ -859,7 +859,7 @@ void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *o } ob->runtime.gpd_eval = gpencil_copy_for_eval(ob->runtime.gpd_orig); gpencil_assign_object_eval(ob); - BKE_gpencil_update_orig_pointers(ob_orig, (Object *)ob); + BKE_gpencil_update_orig_pointers(ob_orig, ob); } /* Calculate gpencil modifiers */ diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index e7a2421a625..8820434cbcf 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -31,7 +31,6 @@ #include "BLI_bitmap.h" #include "BLI_listbase.h" #include "BLI_math.h" -#include "BLI_task.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -40,16 +39,13 @@ #include "DNA_defaults.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" -#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "BKE_anim_path.h" #include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_idtype.h" -#include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" @@ -299,7 +295,7 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) copy_m4_m4(mat, ltOb->obmat); unit_m4(ltOb->obmat); - lattice_deform_verts(ltOb, NULL, NULL, vert_coords, uNew * vNew * wNew, 0, NULL, 1.0f); + BKE_lattice_deform_coords(ltOb, NULL, vert_coords, uNew * vNew * wNew, 0, NULL, 1.0f); copy_m4_m4(ltOb->obmat, mat); lt->typeu = typeu; @@ -349,651 +345,13 @@ Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt) return lt_copy; } -typedef struct LatticeDeformData { - Object *object; - float *latticedata; - float latmat[4][4]; -} LatticeDeformData; - -LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob) -{ - /* we make an array with all differences */ - Lattice *lt = oblatt->data; - BPoint *bp; - DispList *dl = oblatt->runtime.curve_cache ? - BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) : - NULL; - const float *co = dl ? dl->verts : NULL; - float *fp, imat[4][4]; - float fu, fv, fw; - int u, v, w; - float *latticedata; - float latmat[4][4]; - LatticeDeformData *lattice_deform_data; - - if (lt->editlatt) { - lt = lt->editlatt->latt; - } - bp = lt->def; - - fp = latticedata = MEM_mallocN(sizeof(float) * 3 * lt->pntsu * lt->pntsv * lt->pntsw, - "latticedata"); - - /* for example with a particle system: (ob == NULL) */ - if (ob == NULL) { - /* in deformspace, calc matrix */ - invert_m4_m4(latmat, oblatt->obmat); - - /* back: put in deform array */ - invert_m4_m4(imat, latmat); - } - else { - /* in deformspace, calc matrix */ - invert_m4_m4(imat, oblatt->obmat); - mul_m4_m4m4(latmat, imat, ob->obmat); - - /* back: put in deform array */ - invert_m4_m4(imat, latmat); - } - - for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) { - for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) { - for (u = 0, fu = lt->fu; u < lt->pntsu; u++, bp++, co += 3, fp += 3, fu += lt->du) { - if (dl) { - fp[0] = co[0] - fu; - fp[1] = co[1] - fv; - fp[2] = co[2] - fw; - } - else { - fp[0] = bp->vec[0] - fu; - fp[1] = bp->vec[1] - fv; - fp[2] = bp->vec[2] - fw; - } - - mul_mat3_m4_v3(imat, fp); - } - } - } - - lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data"); - lattice_deform_data->latticedata = latticedata; - lattice_deform_data->object = oblatt; - copy_m4_m4(lattice_deform_data->latmat, latmat); - - return lattice_deform_data; -} - -void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float weight) -{ - Object *ob = lattice_deform_data->object; - Lattice *lt = ob->data; - float u, v, w, tu[4], tv[4], tw[4]; - float vec[3]; - int idx_w, idx_v, idx_u; - int ui, vi, wi, uu, vv, ww; - - /* vgroup influence */ - int defgrp_index = -1; - float co_prev[3], weight_blend = 0.0f; - MDeformVert *dvert = BKE_lattice_deform_verts_get(ob); - float *__restrict latticedata = lattice_deform_data->latticedata; - - if (lt->editlatt) { - lt = lt->editlatt->latt; - } - if (latticedata == NULL) { - return; - } - - if (lt->vgroup[0] && dvert) { - defgrp_index = BKE_object_defgroup_name_index(ob, lt->vgroup); - copy_v3_v3(co_prev, co); - } - - /* co is in local coords, treat with latmat */ - mul_v3_m4v3(vec, lattice_deform_data->latmat, co); - - /* u v w coords */ - - if (lt->pntsu > 1) { - u = (vec[0] - lt->fu) / lt->du; - ui = (int)floor(u); - u -= ui; - key_curve_position_weights(u, tu, lt->typeu); - } - else { - tu[0] = tu[2] = tu[3] = 0.0; - tu[1] = 1.0; - ui = 0; - } - - if (lt->pntsv > 1) { - v = (vec[1] - lt->fv) / lt->dv; - vi = (int)floor(v); - v -= vi; - key_curve_position_weights(v, tv, lt->typev); - } - else { - tv[0] = tv[2] = tv[3] = 0.0; - tv[1] = 1.0; - vi = 0; - } - - if (lt->pntsw > 1) { - w = (vec[2] - lt->fw) / lt->dw; - wi = (int)floor(w); - w -= wi; - key_curve_position_weights(w, tw, lt->typew); - } - else { - tw[0] = tw[2] = tw[3] = 0.0; - tw[1] = 1.0; - wi = 0; - } - - for (ww = wi - 1; ww <= wi + 2; ww++) { - w = tw[ww - wi + 1]; - - if (w != 0.0f) { - if (ww > 0) { - if (ww < lt->pntsw) { - idx_w = ww * lt->pntsu * lt->pntsv; - } - else { - idx_w = (lt->pntsw - 1) * lt->pntsu * lt->pntsv; - } - } - else { - idx_w = 0; - } - - for (vv = vi - 1; vv <= vi + 2; vv++) { - v = w * tv[vv - vi + 1]; - - if (v != 0.0f) { - if (vv > 0) { - if (vv < lt->pntsv) { - idx_v = idx_w + vv * lt->pntsu; - } - else { - idx_v = idx_w + (lt->pntsv - 1) * lt->pntsu; - } - } - else { - idx_v = idx_w; - } - - for (uu = ui - 1; uu <= ui + 2; uu++) { - u = weight * v * tu[uu - ui + 1]; - - if (u != 0.0f) { - if (uu > 0) { - if (uu < lt->pntsu) { - idx_u = idx_v + uu; - } - else { - idx_u = idx_v + (lt->pntsu - 1); - } - } - else { - idx_u = idx_v; - } - - madd_v3_v3fl(co, &latticedata[idx_u * 3], u); - - if (defgrp_index != -1) { - weight_blend += (u * BKE_defvert_find_weight(dvert + idx_u, defgrp_index)); - } - } - } - } - } - } - } - - if (defgrp_index != -1) { - interp_v3_v3v3(co, co_prev, co, weight_blend); - } -} - -void end_latt_deform(LatticeDeformData *lattice_deform_data) -{ - if (lattice_deform_data->latticedata) { - MEM_freeN(lattice_deform_data->latticedata); - } - - MEM_freeN(lattice_deform_data); -} - -/* calculations is in local space of deformed object - * so we store in latmat transform from path coord inside object - */ -typedef struct { - float dmin[3], dmax[3]; - float curvespace[4][4], objectspace[4][4], objectspace3[3][3]; - int no_rot_axis; -} CurveDeform; - -static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd) -{ - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_m4m4(cd->objectspace, ob->imat, par->obmat); - invert_m4_m4(cd->curvespace, cd->objectspace); - copy_m3_m4(cd->objectspace3, cd->objectspace); - cd->no_rot_axis = 0; -} - -/* this makes sure we can extend for non-cyclic. - * - * returns OK: 1/0 - */ -static bool where_on_path_deform( - Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius) -{ - BevList *bl; - float ctime1; - int cycl = 0; - - /* test for cyclic */ - bl = ob->runtime.curve_cache->bev.first; - if (!bl->nr) { - return false; - } - if (bl->poly > -1) { - cycl = 1; - } - - if (cycl == 0) { - ctime1 = CLAMPIS(ctime, 0.0f, 1.0f); - } - else { - ctime1 = ctime; - } - - /* vec needs 4 items */ - if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) { - - if (cycl == 0) { - Path *path = ob->runtime.curve_cache->path; - float dvec[3]; - - if (ctime < 0.0f) { - sub_v3_v3v3(dvec, path->data[1].vec, path->data[0].vec); - mul_v3_fl(dvec, ctime * (float)path->len); - add_v3_v3(vec, dvec); - if (quat) { - copy_qt_qt(quat, path->data[0].quat); - } - if (radius) { - *radius = path->data[0].radius; - } - } - else if (ctime > 1.0f) { - sub_v3_v3v3(dvec, path->data[path->len - 1].vec, path->data[path->len - 2].vec); - mul_v3_fl(dvec, (ctime - 1.0f) * (float)path->len); - add_v3_v3(vec, dvec); - if (quat) { - copy_qt_qt(quat, path->data[path->len - 1].quat); - } - if (radius) { - *radius = path->data[path->len - 1].radius; - } - /* weight - not used but could be added */ - } - } - return true; - } - return false; -} - -/* for each point, rotate & translate to curve */ -/* use path, since it has constant distances */ -/* co: local coord, result local too */ -/* returns quaternion for rotation, using cd->no_rot_axis */ -/* axis is using another define!!! */ -static bool calc_curve_deform( - Object *par, float co[3], const short axis, CurveDeform *cd, float r_quat[4]) -{ - Curve *cu = par->data; - float fac, loc[4], dir[3], new_quat[4], radius; - short index; - const bool is_neg_axis = (axis > 2); - - if (par->runtime.curve_cache == NULL) { - /* Happens with a cyclic dependencies. */ - return false; - } - - if (par->runtime.curve_cache->path == NULL) { - return false; /* happens on append, cyclic dependencies and empty curves */ - } - - /* options */ - if (is_neg_axis) { - index = axis - 3; - if (cu->flag & CU_STRETCH) { - fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]); - } - else { - fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist); - } - } - else { - index = axis; - if (cu->flag & CU_STRETCH) { - fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]); - } - else { - if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) { - fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist); - } - else { - fac = 0.0f; - } - } - } - - if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */ - float quat[4], cent[3]; - - if (cd->no_rot_axis) { /* set by caller */ - - /* This is not exactly the same as 2.4x, since the axis is having rotation removed rather - * than changing the axis before calculating the tilt but serves much the same purpose. */ - float dir_flat[3] = {0, 0, 0}, q[4]; - copy_v3_v3(dir_flat, dir); - dir_flat[cd->no_rot_axis - 1] = 0.0f; - - normalize_v3(dir); - normalize_v3(dir_flat); - - rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */ - - mul_qt_qtqt(new_quat, q, new_quat); - } - - /* Logic for 'cent' orientation * - * - * The way 'co' is copied to 'cent' may seem to have no meaning, but it does. - * - * Use a curve modifier to stretch a cube out, color each side RGB, - * positive side light, negative dark. - * view with X up (default), from the angle that you can see 3 faces RGB colors (light), - * anti-clockwise - * Notice X,Y,Z Up all have light colors and each ordered CCW. - * - * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell - * - * note: moved functions into quat_apply_track/vec_apply_track - * */ - copy_qt_qt(quat, new_quat); - copy_v3_v3(cent, co); - - /* zero the axis which is not used, - * the big block of text above now applies to these 3 lines */ - quat_apply_track( - quat, - axis, - (axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */ - vec_apply_track(cent, axis); - cent[index] = 0.0f; - - /* scale if enabled */ - if (cu->flag & CU_PATH_RADIUS) { - mul_v3_fl(cent, radius); - } - - /* local rotation */ - normalize_qt(quat); - mul_qt_v3(quat, cent); - - /* translation */ - add_v3_v3v3(co, cent, loc); - - if (r_quat) { - copy_qt_qt(r_quat, quat); - } - - return true; - } - return false; -} - -void curve_deform_verts(Object *cuOb, - Object *target, - float (*vert_coords)[3], - int numVerts, - MDeformVert *dvert, - const int defgrp_index, - short flag, - short defaxis) -{ - Curve *cu; - int a; - CurveDeform cd; - const bool is_neg_axis = (defaxis > 2); - const bool invert_vgroup = (flag & MOD_CURVE_INVERT_VGROUP) != 0; - - if (cuOb->type != OB_CURVE) { - return; - } - - cu = cuOb->data; - - init_curve_deform(cuOb, target, &cd); - - /* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */ - if (is_neg_axis == false) { - cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f; - cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f; - } - else { - /* negative, these bounds give a good rest position */ - cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f; - cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f; - } - - if (dvert) { - MDeformVert *dvert_iter; - float vec[3]; - - if (cu->flag & CU_DEFORM_BOUNDS_OFF) { - for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) { - const float weight = invert_vgroup ? - 1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) : - BKE_defvert_find_weight(dvert_iter, defgrp_index); - - if (weight > 0.0f) { - mul_m4_v3(cd.curvespace, vert_coords[a]); - copy_v3_v3(vec, vert_coords[a]); - calc_curve_deform(cuOb, vec, defaxis, &cd, NULL); - interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight); - mul_m4_v3(cd.objectspace, vert_coords[a]); - } - } - } - else { - /* set mesh min/max bounds */ - INIT_MINMAX(cd.dmin, cd.dmax); - - for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) { - const float weight = invert_vgroup ? - 1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) : - BKE_defvert_find_weight(dvert_iter, defgrp_index); - if (weight > 0.0f) { - mul_m4_v3(cd.curvespace, vert_coords[a]); - minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]); - } - } - - for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) { - const float weight = invert_vgroup ? - 1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) : - BKE_defvert_find_weight(dvert_iter, defgrp_index); - - if (weight > 0.0f) { - /* already in 'cd.curvespace', prev for loop */ - copy_v3_v3(vec, vert_coords[a]); - calc_curve_deform(cuOb, vec, defaxis, &cd, NULL); - interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight); - mul_m4_v3(cd.objectspace, vert_coords[a]); - } - } - } - } - else { - if (cu->flag & CU_DEFORM_BOUNDS_OFF) { - for (a = 0; a < numVerts; a++) { - mul_m4_v3(cd.curvespace, vert_coords[a]); - calc_curve_deform(cuOb, vert_coords[a], defaxis, &cd, NULL); - mul_m4_v3(cd.objectspace, vert_coords[a]); - } - } - else { - /* set mesh min max bounds */ - INIT_MINMAX(cd.dmin, cd.dmax); - - for (a = 0; a < numVerts; a++) { - mul_m4_v3(cd.curvespace, vert_coords[a]); - minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]); - } - - for (a = 0; a < numVerts; a++) { - /* already in 'cd.curvespace', prev for loop */ - calc_curve_deform(cuOb, vert_coords[a], defaxis, &cd, NULL); - mul_m4_v3(cd.objectspace, vert_coords[a]); - } - } - } -} - -/* input vec and orco = local coord in armature space */ -/* orco is original not-animated or deformed reference point */ -/* result written in vec and mat */ -void curve_deform_vector( - Object *cuOb, Object *target, float orco[3], float vec[3], float mat[3][3], int no_rot_axis) -{ - CurveDeform cd; - float quat[4]; - - if (cuOb->type != OB_CURVE) { - unit_m3(mat); - return; - } - - init_curve_deform(cuOb, target, &cd); - cd.no_rot_axis = no_rot_axis; /* option to only rotate for XY, for example */ - - copy_v3_v3(cd.dmin, orco); - copy_v3_v3(cd.dmax, orco); - - mul_m4_v3(cd.curvespace, vec); - - if (calc_curve_deform(cuOb, vec, target->trackflag, &cd, quat)) { - float qmat[3][3]; - - quat_to_mat3(qmat, quat); - mul_m3_m3m3(mat, qmat, cd.objectspace3); - } - else { - unit_m3(mat); - } - - mul_m4_v3(cd.objectspace, vec); -} - -typedef struct LatticeDeformUserdata { - LatticeDeformData *lattice_deform_data; - float (*vert_coords)[3]; - MDeformVert *dvert; - int defgrp_index; - float fac; - bool invert_vgroup; -} LatticeDeformUserdata; - -static void lattice_deform_vert_task(void *__restrict userdata, - const int index, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - const LatticeDeformUserdata *data = userdata; - - if (data->dvert != NULL) { - const float weight = data->invert_vgroup ? - 1.0f - - BKE_defvert_find_weight(data->dvert + index, data->defgrp_index) : - BKE_defvert_find_weight(data->dvert + index, data->defgrp_index); - if (weight > 0.0f) { - calc_latt_deform(data->lattice_deform_data, data->vert_coords[index], weight * data->fac); - } - } - else { - calc_latt_deform(data->lattice_deform_data, data->vert_coords[index], data->fac); - } -} - -void lattice_deform_verts(Object *laOb, - Object *target, - Mesh *mesh, - float (*vert_coords)[3], - int numVerts, - short flag, - const char *vgroup, - float fac) -{ - LatticeDeformData *lattice_deform_data; - MDeformVert *dvert = NULL; - int defgrp_index = -1; - - if (laOb->type != OB_LATTICE) { - return; - } - - lattice_deform_data = init_latt_deform(laOb, target); - - /* Check whether to use vertex groups (only possible if target is a Mesh or Lattice). - * We want either a Mesh/Lattice with no derived data, or derived data with deformverts. - */ - if (vgroup && vgroup[0] && target && ELEM(target->type, OB_MESH, OB_LATTICE)) { - defgrp_index = BKE_object_defgroup_name_index(target, vgroup); - - if (defgrp_index != -1) { - /* if there's derived data without deformverts, don't use vgroups */ - if (mesh) { - dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); - } - else if (target->type == OB_LATTICE) { - dvert = ((Lattice *)target->data)->dvert; - } - else { - dvert = ((Mesh *)target->data)->dvert; - } - } - } - - LatticeDeformUserdata data = { - .lattice_deform_data = lattice_deform_data, - .vert_coords = vert_coords, - .dvert = dvert, - .defgrp_index = defgrp_index, - .fac = fac, - .invert_vgroup = (flag & MOD_LATTICE_INVERT_VGROUP) != 0, - }; - - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 32; - BLI_task_parallel_range(0, numVerts, &data, lattice_deform_vert_task, &settings); - - end_latt_deform(lattice_deform_data); -} - bool object_deform_mball(Object *ob, ListBase *dispbase) { if (ob->parent && ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) { DispList *dl; for (dl = dispbase->first; dl; dl = dl->next) { - lattice_deform_verts(ob->parent, ob, NULL, (float(*)[3])dl->verts, dl->nr, 0, NULL, 1.0f); + BKE_lattice_deform_coords(ob->parent, ob, (float(*)[3])dl->verts, dl->nr, 0, NULL, 1.0f); } return true; @@ -1194,7 +552,7 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec } } -struct MDeformVert *BKE_lattice_deform_verts_get(struct Object *oblatt) +struct MDeformVert *BKE_lattice_deform_verts_get(const struct Object *oblatt) { Lattice *lt = (Lattice *)oblatt->data; BLI_assert(oblatt->type == OB_LATTICE); diff --git a/source/blender/blenkernel/intern/lattice_deform.c b/source/blender/blenkernel/intern/lattice_deform.c new file mode 100644 index 00000000000..2b3349d4d9a --- /dev/null +++ b/source/blender/blenkernel/intern/lattice_deform.c @@ -0,0 +1,470 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup bke + * + * Deform coordinates by a lattice object (used by modifier). + */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_task.h" +#include "BLI_utildefines.h" + +#include "DNA_curve_types.h" +#include "DNA_lattice_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_curve.h" +#include "BKE_displist.h" +#include "BKE_editmesh.h" +#include "BKE_key.h" +#include "BKE_lattice.h" +#include "BKE_modifier.h" + +#include "BKE_deform.h" + +/* -------------------------------------------------------------------- */ +/** \name Lattice Deform API + * \{ */ + +typedef struct LatticeDeformData { + const Object *object; + float *latticedata; + float latmat[4][4]; +} LatticeDeformData; + +LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Object *ob) +{ + /* we make an array with all differences */ + Lattice *lt = oblatt->data; + BPoint *bp; + DispList *dl = oblatt->runtime.curve_cache ? + BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) : + NULL; + const float *co = dl ? dl->verts : NULL; + float *fp, imat[4][4]; + float fu, fv, fw; + int u, v, w; + float *latticedata; + float latmat[4][4]; + LatticeDeformData *lattice_deform_data; + + if (lt->editlatt) { + lt = lt->editlatt->latt; + } + bp = lt->def; + + fp = latticedata = MEM_mallocN(sizeof(float) * 3 * lt->pntsu * lt->pntsv * lt->pntsw, + "latticedata"); + + /* for example with a particle system: (ob == NULL) */ + if (ob == NULL) { + /* in deformspace, calc matrix */ + invert_m4_m4(latmat, oblatt->obmat); + + /* back: put in deform array */ + invert_m4_m4(imat, latmat); + } + else { + /* in deformspace, calc matrix */ + invert_m4_m4(imat, oblatt->obmat); + mul_m4_m4m4(latmat, imat, ob->obmat); + + /* back: put in deform array */ + invert_m4_m4(imat, latmat); + } + + for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) { + for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) { + for (u = 0, fu = lt->fu; u < lt->pntsu; u++, bp++, co += 3, fp += 3, fu += lt->du) { + if (dl) { + fp[0] = co[0] - fu; + fp[1] = co[1] - fv; + fp[2] = co[2] - fw; + } + else { + fp[0] = bp->vec[0] - fu; + fp[1] = bp->vec[1] - fv; + fp[2] = bp->vec[2] - fw; + } + + mul_mat3_m4_v3(imat, fp); + } + } + } + + lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data"); + lattice_deform_data->latticedata = latticedata; + lattice_deform_data->object = oblatt; + copy_m4_m4(lattice_deform_data->latmat, latmat); + + return lattice_deform_data; +} + +void BKE_lattice_deform_data_eval_co(LatticeDeformData *lattice_deform_data, + float co[3], + float weight) +{ + const Object *ob = lattice_deform_data->object; + Lattice *lt = ob->data; + float u, v, w, tu[4], tv[4], tw[4]; + float vec[3]; + int idx_w, idx_v, idx_u; + int ui, vi, wi, uu, vv, ww; + + /* vgroup influence */ + int defgrp_index = -1; + float co_prev[3], weight_blend = 0.0f; + const MDeformVert *dvert = BKE_lattice_deform_verts_get(ob); + float *__restrict latticedata = lattice_deform_data->latticedata; + + if (lt->editlatt) { + lt = lt->editlatt->latt; + } + if (latticedata == NULL) { + return; + } + + if (lt->vgroup[0] && dvert) { + defgrp_index = BKE_object_defgroup_name_index(ob, lt->vgroup); + copy_v3_v3(co_prev, co); + } + + /* co is in local coords, treat with latmat */ + mul_v3_m4v3(vec, lattice_deform_data->latmat, co); + + /* u v w coords */ + + if (lt->pntsu > 1) { + u = (vec[0] - lt->fu) / lt->du; + ui = (int)floor(u); + u -= ui; + key_curve_position_weights(u, tu, lt->typeu); + } + else { + tu[0] = tu[2] = tu[3] = 0.0; + tu[1] = 1.0; + ui = 0; + } + + if (lt->pntsv > 1) { + v = (vec[1] - lt->fv) / lt->dv; + vi = (int)floor(v); + v -= vi; + key_curve_position_weights(v, tv, lt->typev); + } + else { + tv[0] = tv[2] = tv[3] = 0.0; + tv[1] = 1.0; + vi = 0; + } + + if (lt->pntsw > 1) { + w = (vec[2] - lt->fw) / lt->dw; + wi = (int)floor(w); + w -= wi; + key_curve_position_weights(w, tw, lt->typew); + } + else { + tw[0] = tw[2] = tw[3] = 0.0; + tw[1] = 1.0; + wi = 0; + } + + for (ww = wi - 1; ww <= wi + 2; ww++) { + w = tw[ww - wi + 1]; + + if (w != 0.0f) { + if (ww > 0) { + if (ww < lt->pntsw) { + idx_w = ww * lt->pntsu * lt->pntsv; + } + else { + idx_w = (lt->pntsw - 1) * lt->pntsu * lt->pntsv; + } + } + else { + idx_w = 0; + } + + for (vv = vi - 1; vv <= vi + 2; vv++) { + v = w * tv[vv - vi + 1]; + + if (v != 0.0f) { + if (vv > 0) { + if (vv < lt->pntsv) { + idx_v = idx_w + vv * lt->pntsu; + } + else { + idx_v = idx_w + (lt->pntsv - 1) * lt->pntsu; + } + } + else { + idx_v = idx_w; + } + + for (uu = ui - 1; uu <= ui + 2; uu++) { + u = weight * v * tu[uu - ui + 1]; + + if (u != 0.0f) { + if (uu > 0) { + if (uu < lt->pntsu) { + idx_u = idx_v + uu; + } + else { + idx_u = idx_v + (lt->pntsu - 1); + } + } + else { + idx_u = idx_v; + } + + madd_v3_v3fl(co, &latticedata[idx_u * 3], u); + + if (defgrp_index != -1) { + weight_blend += (u * BKE_defvert_find_weight(dvert + idx_u, defgrp_index)); + } + } + } + } + } + } + } + + if (defgrp_index != -1) { + interp_v3_v3v3(co, co_prev, co, weight_blend); + } +} + +void BKE_lattice_deform_data_destroy(LatticeDeformData *lattice_deform_data) +{ + if (lattice_deform_data->latticedata) { + MEM_freeN(lattice_deform_data->latticedata); + } + + MEM_freeN(lattice_deform_data); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Lattice Deform #BKE_lattice_deform_coords API + * + * #BKE_lattice_deform_coords and related functions. + * \{ */ + +typedef struct LatticeDeformUserdata { + LatticeDeformData *lattice_deform_data; + float (*vert_coords)[3]; + const MDeformVert *dvert; + int defgrp_index; + float fac; + bool invert_vgroup; + + /** Specific data types. */ + struct { + int cd_dvert_offset; + } bmesh; +} LatticeDeformUserdata; + +static void lattice_deform_vert_with_dvert(const LatticeDeformUserdata *data, + const int index, + const MDeformVert *dvert) +{ + if (dvert != NULL) { + const float weight = data->invert_vgroup ? + 1.0f - BKE_defvert_find_weight(dvert, data->defgrp_index) : + BKE_defvert_find_weight(dvert, data->defgrp_index); + if (weight > 0.0f) { + BKE_lattice_deform_data_eval_co( + data->lattice_deform_data, data->vert_coords[index], weight * data->fac); + } + } + else { + BKE_lattice_deform_data_eval_co( + data->lattice_deform_data, data->vert_coords[index], data->fac); + } +} + +static void lattice_deform_vert_task(void *__restrict userdata, + const int index, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + const LatticeDeformUserdata *data = userdata; + lattice_deform_vert_with_dvert(data, index, data->dvert ? &data->dvert[index] : NULL); +} + +static void lattice_vert_task_editmesh(void *__restrict userdata, MempoolIterData *iter) +{ + const LatticeDeformUserdata *data = userdata; + BMVert *v = (BMVert *)iter; + MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(v, data->bmesh.cd_dvert_offset); + lattice_deform_vert_with_dvert(data, BM_elem_index_get(v), dvert); +} + +static void lattice_vert_task_editmesh_no_dvert(void *__restrict userdata, MempoolIterData *iter) +{ + const LatticeDeformUserdata *data = userdata; + BMVert *v = (BMVert *)iter; + lattice_deform_vert_with_dvert(data, BM_elem_index_get(v), NULL); +} + +static void lattice_deform_coords_impl(const Object *ob_lattice, + const Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const short flag, + const char *defgrp_name, + const float fac, + const Mesh *me_target, + BMEditMesh *em_target) +{ + LatticeDeformData *lattice_deform_data; + const MDeformVert *dvert = NULL; + int defgrp_index = -1; + int cd_dvert_offset = -1; + + if (ob_lattice->type != OB_LATTICE) { + return; + } + + lattice_deform_data = BKE_lattice_deform_data_create(ob_lattice, ob_target); + + /* Check whether to use vertex groups (only possible if ob_target is a Mesh or Lattice). + * We want either a Mesh/Lattice with no derived data, or derived data with deformverts. + */ + if (defgrp_name && defgrp_name[0] && ob_target && ELEM(ob_target->type, OB_MESH, OB_LATTICE)) { + defgrp_index = BKE_object_defgroup_name_index(ob_target, defgrp_name); + + if (defgrp_index != -1) { + /* if there's derived data without deformverts, don't use vgroups */ + if (em_target) { + cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT); + } + else if (me_target) { + dvert = CustomData_get_layer(&me_target->vdata, CD_MDEFORMVERT); + } + else if (ob_target->type == OB_LATTICE) { + dvert = ((Lattice *)ob_target->data)->dvert; + } + else { + dvert = ((Mesh *)ob_target->data)->dvert; + } + } + } + + LatticeDeformUserdata data = { + .lattice_deform_data = lattice_deform_data, + .vert_coords = vert_coords, + .dvert = dvert, + .defgrp_index = defgrp_index, + .fac = fac, + .invert_vgroup = (flag & MOD_LATTICE_INVERT_VGROUP) != 0, + .bmesh = + { + .cd_dvert_offset = cd_dvert_offset, + }, + }; + + if (em_target != NULL) { + /* While this could cause an extra loop over mesh data, in most cases this will + * have already been properly set. */ + BM_mesh_elem_index_ensure(em_target->bm, BM_VERT); + + if (cd_dvert_offset != -1) { + BLI_task_parallel_mempool(em_target->bm->vpool, &data, lattice_vert_task_editmesh, true); + } + else { + BLI_task_parallel_mempool( + em_target->bm->vpool, &data, lattice_vert_task_editmesh_no_dvert, true); + } + } + else { + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 32; + BLI_task_parallel_range(0, vert_coords_len, &data, lattice_deform_vert_task, &settings); + } + + BKE_lattice_deform_data_destroy(lattice_deform_data); +} + +void BKE_lattice_deform_coords(const Object *ob_lattice, + const Object *ob_target, + float (*vert_coords)[3], + int vert_coords_len, + short flag, + const char *defgrp_name, + float fac) +{ + lattice_deform_coords_impl( + ob_lattice, ob_target, vert_coords, vert_coords_len, flag, defgrp_name, fac, NULL, NULL); +} + +void BKE_lattice_deform_coords_with_mesh(const Object *ob_lattice, + const Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const short flag, + const char *defgrp_name, + const float fac, + const Mesh *me_target) +{ + lattice_deform_coords_impl(ob_lattice, + ob_target, + vert_coords, + vert_coords_len, + flag, + defgrp_name, + fac, + me_target, + NULL); +} + +void BKE_lattice_deform_coords_with_editmesh(const struct Object *ob_lattice, + const struct Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const short flag, + const char *defgrp_name, + const float influence, + struct BMEditMesh *em_target) +{ + lattice_deform_coords_impl(ob_lattice, + ob_target, + vert_coords, + vert_coords_len, + flag, + defgrp_name, + influence, + NULL, + em_target); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 3ad429c5f5a..ca23ec90c97 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -1694,7 +1694,7 @@ static void library_make_local_copying_check(ID *id, continue; } - /* Shapekeys are considered 'private' to their owner ID here, and never tagged + /* Shape-keys are considered 'private' to their owner ID here, and never tagged * (since they cannot be linked), so we have to switch effective parent to their owner. */ if (GS(par_id->name) == ID_KE) { diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index d16428ccd60..d6f037f64a4 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -197,7 +197,6 @@ static ID *lib_override_library_create_from(Main *bmain, ID *reference_id) id_us_min(local_id); BKE_lib_override_library_init(local_id, reference_id); - local_id->override_library->flag |= OVERRIDE_LIBRARY_AUTO; return local_id; } @@ -736,13 +735,15 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local) * Generating diff values and applying overrides are much cheaper. * * \return true if new overriding op was created, or some local data was reset. */ -bool BKE_lib_override_library_operations_create(Main *bmain, ID *local, const bool force_auto) +bool BKE_lib_override_library_operations_create(Main *bmain, + ID *local, + const bool UNUSED(force_auto)) { BLI_assert(local->override_library != NULL); const bool is_template = (local->override_library->reference == NULL); bool ret = false; - if (!is_template && (force_auto || local->override_library->flag & OVERRIDE_LIBRARY_AUTO)) { + if (!is_template) { /* Do not attempt to generate overriding rules from an empty place-holder generated by link * code when it cannot find to actual library/ID. Much better to keep the local datablock as * is in the file in that case, until broken lib is fixed. */ @@ -804,7 +805,7 @@ void BKE_lib_override_library_main_operations_create(Main *bmain, const bool for FOREACH_MAIN_ID_BEGIN (bmain, id) { if ((ID_IS_OVERRIDE_LIBRARY(id) && force_auto) || - (ID_IS_OVERRIDE_LIBRARY_AUTO(id) && (id->tag & LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH))) { + (id->tag & LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH)) { BKE_lib_override_library_operations_create(bmain, id, force_auto); id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH; } diff --git a/source/blender/blenkernel/intern/mesh_wrapper.c b/source/blender/blenkernel/intern/mesh_wrapper.c index 98b77256ad7..6a8bc698b11 100644 --- a/source/blender/blenkernel/intern/mesh_wrapper.c +++ b/source/blender/blenkernel/intern/mesh_wrapper.c @@ -53,7 +53,7 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em, const CustomData_MeshMasks *cd_mask_extra, - float (*vertexCos)[3], + const float (*vert_coords)[3], const Mesh *me_settings) { Mesh *me = BKE_id_new_nomain(ID_ME, NULL); @@ -83,7 +83,7 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em, #endif EditMeshData *edit_data = me->runtime.edit_data; - edit_data->vertexCos = vertexCos; + edit_data->vertexCos = vert_coords; return me; } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index d4b7d05c228..7c77746ea1c 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -878,10 +878,7 @@ void BKE_modifier_free_temporary_data(ModifierData *md) if (md->type == eModifierType_Armature) { ArmatureModifierData *amd = (ArmatureModifierData *)md; - if (amd->prevCos) { - MEM_freeN(amd->prevCos); - amd->prevCos = NULL; - } + MEM_SAFE_FREE(amd->vert_coords_prev); } } diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 474142e8555..4c6354f12a1 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -1053,7 +1053,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem } if (psys->lattice_deform_data) { - end_latt_deform(psys->lattice_deform_data); + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index eb485e1522f..c201cb83c44 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -410,7 +410,7 @@ struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData } } if (lattice) { - lattice_deform_data = init_latt_deform(lattice, NULL); + lattice_deform_data = BKE_lattice_deform_data_create(lattice, NULL); } } @@ -3150,7 +3150,8 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re /* lattices have to be calculated separately to avoid mixups between effector calculations */ if (psys->lattice_deform_data) { for (k = 0, ca = cache[p]; k <= segments; k++, ca++) { - calc_latt_deform(psys->lattice_deform_data, ca->co, psys->lattice_strength); + BKE_lattice_deform_data_eval_co( + psys->lattice_deform_data, ca->co, psys->lattice_strength); } } } @@ -3185,7 +3186,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re psys->totcached = totpart; if (psys->lattice_deform_data) { - end_latt_deform(psys->lattice_deform_data); + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } @@ -4413,7 +4414,8 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, } if (psys->lattice_deform_data && edit == 0) { - calc_latt_deform(psys->lattice_deform_data, state->co, psys->lattice_strength); + BKE_lattice_deform_data_eval_co( + psys->lattice_deform_data, state->co, psys->lattice_strength); } } } @@ -4696,7 +4698,8 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta do_child_modifiers(&modifier_ctx, mat, state, t); if (psys->lattice_deform_data) { - calc_latt_deform(psys->lattice_deform_data, state->co, psys->lattice_strength); + BKE_lattice_deform_data_eval_co( + psys->lattice_deform_data, state->co, psys->lattice_strength); } } else { @@ -4760,7 +4763,8 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta } if (sim->psys->lattice_deform_data) { - calc_latt_deform(sim->psys->lattice_deform_data, state->co, psys->lattice_strength); + BKE_lattice_deform_data_eval_co( + sim->psys->lattice_deform_data, state->co, psys->lattice_strength); } } @@ -4970,12 +4974,13 @@ void psys_apply_hair_lattice(Depsgraph *depsgraph, Scene *scene, Object *ob, Par hkey = pa->hair; for (h = 0; h < pa->totkey; h++, hkey++) { mul_m4_v3(hairmat, hkey->co); - calc_latt_deform(psys->lattice_deform_data, hkey->co, psys->lattice_strength); + BKE_lattice_deform_data_eval_co( + psys->lattice_deform_data, hkey->co, psys->lattice_strength); mul_m4_v3(imat, hkey->co); } } - end_latt_deform(psys->lattice_deform_data); + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); psys->lattice_deform_data = NULL; /* protect the applied shape */ diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 31d51a74e7f..606291a9ae0 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -536,7 +536,7 @@ void psys_thread_context_free(ParticleThreadContext *ctx) } if (ctx->sim.psys->lattice_deform_data) { - end_latt_deform(ctx->sim.psys->lattice_deform_data); + BKE_lattice_deform_data_destroy(ctx->sim.psys->lattice_deform_data); ctx->sim.psys->lattice_deform_data = NULL; } @@ -4126,7 +4126,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_ } if (psys->lattice_deform_data) { - end_latt_deform(psys->lattice_deform_data); + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } @@ -4616,7 +4616,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_ /* cleanup */ if (psys->lattice_deform_data) { - end_latt_deform(psys->lattice_deform_data); + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 9cd17310f07..836fe59d7bd 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -138,6 +138,7 @@ static int ptcache_data_size[] = { static int ptcache_extra_datasize[] = { 0, sizeof(ParticleSpring), + sizeof(float) * 3, }; /* forward declarations */ @@ -176,6 +177,23 @@ static int ptcache_basic_header_write(PTCacheFile *pf) return 1; } +static void ptcache_add_extra_data(PTCacheMem *pm, + unsigned int type, + unsigned int count, + void *data) +{ + PTCacheExtra *extra = MEM_callocN(sizeof(PTCacheExtra), "Point cache: extra data descriptor"); + + extra->type = type; + extra->totdata = count; + + size_t size = extra->totdata * ptcache_extra_datasize[extra->type]; + + extra->data = MEM_mallocN(size, "Point cache: extra data"); + memcpy(extra->data, data, size); + + BLI_addtail(&pm->extradata, extra); +} /* Softbody functions */ static int ptcache_softbody_write(int index, void *soft_v, void **data, int UNUSED(cfra)) { @@ -467,21 +485,12 @@ static int ptcache_particle_totwrite(void *psys_v, int cfra) static void ptcache_particle_extra_write(void *psys_v, PTCacheMem *pm, int UNUSED(cfra)) { ParticleSystem *psys = psys_v; - PTCacheExtra *extra = NULL; if (psys->part->phystype == PART_PHYS_FLUID && psys->part->fluid && psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS && psys->tot_fluidsprings && psys->fluid_springs) { - extra = MEM_callocN(sizeof(PTCacheExtra), "Point cache: fluid extra data"); - - extra->type = BPHYS_EXTRA_FLUID_SPRINGS; - extra->totdata = psys->tot_fluidsprings; - - extra->data = MEM_callocN(extra->totdata * ptcache_extra_datasize[extra->type], - "Point cache: extra data"); - memcpy(extra->data, psys->fluid_springs, extra->totdata * ptcache_extra_datasize[extra->type]); - - BLI_addtail(&pm->extradata, extra); + ptcache_add_extra_data( + pm, BPHYS_EXTRA_FLUID_SPRINGS, psys->tot_fluidsprings, psys->fluid_springs); } } @@ -575,6 +584,33 @@ static void ptcache_cloth_interpolate( /* should vert->xconst be interpolated somehow too? - jahka */ } +static void ptcache_cloth_extra_write(void *cloth_v, PTCacheMem *pm, int UNUSED(cfra)) +{ + ClothModifierData *clmd = cloth_v; + Cloth *cloth = clmd->clothObject; + + if (!is_zero_v3(cloth->average_acceleration)) { + ptcache_add_extra_data(pm, BPHYS_EXTRA_CLOTH_ACCELERATION, 1, cloth->average_acceleration); + } +} +static void ptcache_cloth_extra_read(void *cloth_v, PTCacheMem *pm, float UNUSED(cfra)) +{ + ClothModifierData *clmd = cloth_v; + Cloth *cloth = clmd->clothObject; + PTCacheExtra *extra = pm->extradata.first; + + zero_v3(cloth->average_acceleration); + + for (; extra; extra = extra->next) { + switch (extra->type) { + case BPHYS_EXTRA_CLOTH_ACCELERATION: { + copy_v3_v3(cloth->average_acceleration, extra->data); + break; + } + } + } +} + static int ptcache_cloth_totpoint(void *cloth_v, int UNUSED(cfra)) { ClothModifierData *clmd = cloth_v; @@ -1681,8 +1717,8 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl pid->write_stream = NULL; pid->read_stream = NULL; - pid->write_extra_data = NULL; - pid->read_extra_data = NULL; + pid->write_extra_data = ptcache_cloth_extra_write; + pid->read_extra_data = ptcache_cloth_extra_read; pid->interpolate_extra_data = NULL; pid->write_header = ptcache_basic_header_write; diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh index b929d1220da..07155439170 100644 --- a/source/blender/blenlib/BLI_array.hh +++ b/source/blender/blenlib/BLI_array.hh @@ -55,7 +55,7 @@ template< * The number of values that can be stored in the array, without doing a heap allocation. * * When T is large, the small buffer optimization is disabled by default to avoid large - * unexpected allocations on the stack. It can still be enabled explicitely though. + * unexpected allocations on the stack. It can still be enabled explicitly though. */ uint InlineBufferCapacity = (sizeof(T) < 100) ? 4 : 0, /** diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh index 57d5f7f9d8a..5490c953756 100644 --- a/source/blender/blenlib/BLI_hash.hh +++ b/source/blender/blenlib/BLI_hash.hh @@ -65,7 +65,7 @@ * * - When you want to provide a different hash function for a type that already has a default hash * function: Implement a struct like the one below and pass it as template parameter to the hash - * table explicitely. + * table explicitly. * * struct MyCustomHash { * uint32_t operator()(const TheType &value) const { @@ -97,6 +97,16 @@ template<typename T> struct DefaultHash { } }; +/** + * Use the same hash function for const and non const variants of a type. + */ +template<typename T> struct DefaultHash<const T> { + uint32_t operator()(const T &value) const + { + return DefaultHash<T>{}(value); + } +}; + #define TRIVIAL_DEFAULT_INT_HASH(TYPE) \ template<> struct DefaultHash<TYPE> { \ uint32_t operator()(TYPE value) const \ diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh index f968f9f15ce..2a0dc939cb9 100644 --- a/source/blender/blenlib/BLI_linear_allocator.hh +++ b/source/blender/blenlib/BLI_linear_allocator.hh @@ -171,7 +171,7 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya MutableSpan<T *> pointers = void_pointers.cast<T *>(); for (uint i : IndexRange(n)) { - new (pointers[i]) T(std::forward<Args>(args)...); + new ((void *)pointers[i]) T(std::forward<Args>(args)...); } return pointers; diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh index 4fc9f98d835..a4c3ee76ca1 100644 --- a/source/blender/blenlib/BLI_map.hh +++ b/source/blender/blenlib/BLI_map.hh @@ -94,7 +94,7 @@ template< * that (unlike vector) initializing a map has a O(n) cost in the number of slots. * * When Key or Value are large, the small buffer optimization is disabled by default to avoid - * large unexpected allocations on the stack. It can still be enabled explicitely though. + * large unexpected allocations on the stack. It can still be enabled explicitly though. */ uint32_t InlineBufferCapacity = (sizeof(Key) + sizeof(Value) < 100) ? 4 : 0, /** @@ -470,7 +470,7 @@ class Map { const ModifyValueF &modify_value) -> decltype(create_value(nullptr)) { return this->add_or_modify__impl( - std::forward<Key>(key), create_value, modify_value, m_hash(key)); + std::forward<ForwardKey>(key), create_value, modify_value, m_hash(key)); } /** @@ -1175,7 +1175,7 @@ class Map { bool add_overwrite__impl(ForwardKey &&key, ForwardValue &&value, uint32_t hash) { auto create_func = [&](Value *ptr) { - new (ptr) Value(std::forward<ForwardValue>(value)); + new ((void *)ptr) Value(std::forward<ForwardValue>(value)); return true; }; auto modify_func = [&](Value *ptr) { diff --git a/source/blender/blenlib/BLI_map_slots.hh b/source/blender/blenlib/BLI_map_slots.hh index 9ea2c4cad89..f12eefcaf0b 100644 --- a/source/blender/blenlib/BLI_map_slots.hh +++ b/source/blender/blenlib/BLI_map_slots.hh @@ -84,13 +84,13 @@ template<typename Key, typename Value> class SimpleMapSlot { { m_state = other.m_state; if (other.m_state == Occupied) { - new (this->key()) Key(*other.key()); - new (this->value()) Value(*other.value()); + new ((void *)this->key()) Key(*other.key()); + new ((void *)this->value()) Value(*other.value()); } } /** - * The move construtor has to copy the state. If the other slot was occupied, the key and value + * The move constructor has to copy the state. If the other slot was occupied, the key and value * from the other have to moved as well. The other slot stays in the state it was in before. Its * optionally stored key and value remain in a moved-from state. */ @@ -98,8 +98,8 @@ template<typename Key, typename Value> class SimpleMapSlot { { m_state = other.m_state; if (other.m_state == Occupied) { - new (this->key()) Key(std::move(*other.key())); - new (this->value()) Value(std::move(*other.value())); + new ((void *)this->key()) Key(std::move(*other.key())); + new ((void *)this->value()) Value(std::move(*other.value())); } } @@ -170,8 +170,8 @@ template<typename Key, typename Value> class SimpleMapSlot { BLI_assert(!this->is_occupied()); BLI_assert(other.is_occupied()); m_state = Occupied; - new (this->key()) Key(std::move(*other.key())); - new (this->value()) Value(std::move(*other.value())); + new ((void *)this->key()) Key(std::move(*other.key())); + new ((void *)this->value()) Value(std::move(*other.value())); other.key()->~Key(); other.value()->~Value(); } @@ -198,7 +198,7 @@ template<typename Key, typename Value> class SimpleMapSlot { { BLI_assert(!this->is_occupied()); this->occupy_without_value(std::forward<ForwardKey>(key), hash); - new (this->value()) Value(std::forward<ForwardValue>(value)); + new ((void *)this->value()) Value(std::forward<ForwardValue>(value)); } /** @@ -209,7 +209,7 @@ template<typename Key, typename Value> class SimpleMapSlot { { BLI_assert(!this->is_occupied()); m_state = Occupied; - new (this->key()) Key(std::forward<ForwardKey>(key)); + new ((void *)this->key()) Key(std::forward<ForwardKey>(key)); } /** @@ -251,14 +251,14 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot IntrusiveMapSlot(const IntrusiveMapSlot &other) : m_key(other.m_key) { if (KeyInfo::is_not_empty_or_removed(m_key)) { - new (this->value()) Value(*other.value()); + new ((void *)this->value()) Value(*other.value()); } } IntrusiveMapSlot(IntrusiveMapSlot &&other) noexcept : m_key(other.m_key) { if (KeyInfo::is_not_empty_or_removed(m_key)) { - new (this->value()) Value(std::move(*other.value())); + new ((void *)this->value()) Value(std::move(*other.value())); } } @@ -303,7 +303,7 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot BLI_assert(!this->is_occupied()); BLI_assert(other.is_occupied()); m_key = std::move(other.m_key); - new (this->value()) Value(std::move(*other.value())); + new ((void *)this->value()) Value(std::move(*other.value())); other.m_key.~Key(); other.value()->~Value(); } @@ -321,7 +321,7 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot BLI_assert(!this->is_occupied()); BLI_assert(KeyInfo::is_not_empty_or_removed(key)); this->occupy_without_value(std::forward<ForwardKey>(key), hash); - new (this->value()) Value(std::forward<ForwardValue>(value)); + new ((void *)this->value()) Value(std::forward<ForwardValue>(value)); } template<typename ForwardKey> void occupy_without_value(ForwardKey &&key, uint32_t UNUSED(hash)) diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index de9fc956bfb..81792e2101c 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -22,6 +22,7 @@ */ #include <memory> +#include <new> #include "BLI_utildefines.h" @@ -39,13 +40,13 @@ namespace blender { template<typename T> void default_construct_n(T *ptr, uint n) { /* This is not strictly necessary, because the loop below will be optimized away anyway. It is - * nice to make behavior this explicitely, though. */ + * nice to make behavior this explicitly, though. */ if (std::is_trivially_constructible<T>::value) { return; } for (uint i = 0; i < n; i++) { - new (ptr + i) T; + new ((void *)(ptr + i)) T; } } @@ -61,7 +62,7 @@ template<typename T> void default_construct_n(T *ptr, uint n) template<typename T> void destruct_n(T *ptr, uint n) { /* This is not strictly necessary, because the loop below will be optimized away anyway. It is - * nice to make behavior this explicitely, though. */ + * nice to make behavior this explicitly, though. */ if (std::is_trivially_destructible<T>::value) { return; } @@ -101,7 +102,7 @@ template<typename T> void initialized_copy_n(const T *src, uint n, T *dst) template<typename T> void uninitialized_copy_n(const T *src, uint n, T *dst) { for (uint i = 0; i < n; i++) { - new (dst + i) T(src[i]); + new ((void *)(dst + i)) T(src[i]); } } @@ -135,7 +136,7 @@ template<typename T> void initialized_move_n(T *src, uint n, T *dst) template<typename T> void uninitialized_move_n(T *src, uint n, T *dst) { for (uint i = 0; i < n; i++) { - new (dst + i) T(std::move(src[i])); + new ((void *)(dst + i)) T(std::move(src[i])); } } @@ -162,7 +163,7 @@ template<typename T> void initialized_relocate_n(T *src, uint n, T *dst) * * Before: * src: initialized - * dst: uinitialized + * dst: uninitialized * After: * src: uninitialized * dst: initialized @@ -199,7 +200,7 @@ template<typename T> void initialized_fill_n(T *dst, uint n, const T &value) template<typename T> void uninitialized_fill_n(T *dst, uint n, const T &value) { for (uint i = 0; i < n; i++) { - new (dst + i) T(value); + new ((void *)(dst + i)) T(value); } } diff --git a/source/blender/blenlib/BLI_optional.hh b/source/blender/blenlib/BLI_optional.hh index b5f98d6fa97..2e6b66d0eac 100644 --- a/source/blender/blenlib/BLI_optional.hh +++ b/source/blender/blenlib/BLI_optional.hh @@ -121,7 +121,7 @@ template<typename T> class Optional { this->value() = value; } else { - new (this->value_ptr()) T(value); + new ((void *)this->value_ptr()) T(value); m_set = true; } } @@ -132,7 +132,7 @@ template<typename T> class Optional { this->value() = std::move(value); } else { - new (this->value_ptr()) T(std::move(value)); + new ((void *)this->value_ptr()) T(std::move(value)); m_set = true; } } @@ -140,14 +140,14 @@ template<typename T> class Optional { void set_new(const T &value) { BLI_assert(!m_set); - new (this->value_ptr()) T(value); + new ((void *)this->value_ptr()) T(value); m_set = true; } void set_new(T &&value) { BLI_assert(!m_set); - new (this->value_ptr()) T(std::move(value)); + new ((void *)this->value_ptr()) T(std::move(value)); m_set = true; } diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh index af0c3424f5a..d23aa96e434 100644 --- a/source/blender/blenlib/BLI_set.hh +++ b/source/blender/blenlib/BLI_set.hh @@ -91,7 +91,7 @@ template< * that (unlike vector) initializing a set has a O(n) cost in the number of slots. * * When Key is large, the small buffer optimization is disabled by default to avoid large - * unexpected allocations on the stack. It can still be enabled explicitely though. + * unexpected allocations on the stack. It can still be enabled explicitly though. */ uint32_t InlineBufferCapacity = (sizeof(Key) < 100) ? 4 : 0, /** @@ -433,7 +433,7 @@ class Set { /** * Creates a new slot array and reinserts all keys inside of that. This method can be used to get - * rid of dummy slots. Also this is useful for benchmarking the grow function. + * rid of removed slots. Also this is useful for benchmarking the grow function. */ void rehash() { diff --git a/source/blender/blenlib/BLI_set_slots.hh b/source/blender/blenlib/BLI_set_slots.hh index 15f56f2450e..581e70ce628 100644 --- a/source/blender/blenlib/BLI_set_slots.hh +++ b/source/blender/blenlib/BLI_set_slots.hh @@ -80,7 +80,7 @@ template<typename Key> class SimpleSetSlot { { m_state = other.m_state; if (other.m_state == Occupied) { - new (this->key()) Key(*other.key()); + new ((void *)this->key()) Key(*other.key()); } } @@ -93,7 +93,7 @@ template<typename Key> class SimpleSetSlot { { m_state = other.m_state; if (other.m_state == Occupied) { - new (this->key()) Key(std::move(*other.key())); + new ((void *)this->key()) Key(std::move(*other.key())); } } @@ -148,7 +148,7 @@ template<typename Key> class SimpleSetSlot { BLI_assert(!this->is_occupied()); BLI_assert(other.is_occupied()); m_state = Occupied; - new (this->key()) Key(std::move(*other.key())); + new ((void *)this->key()) Key(std::move(*other.key())); other.key()->~Key(); } @@ -173,7 +173,7 @@ template<typename Key> class SimpleSetSlot { { BLI_assert(!this->is_occupied()); m_state = Occupied; - new (this->key()) Key(std::forward<ForwardKey>(key)); + new ((void *)this->key()) Key(std::forward<ForwardKey>(key)); } /** @@ -221,7 +221,7 @@ template<typename Key> class HashedSetSlot { m_state = other.m_state; if (other.m_state == Occupied) { m_hash = other.m_hash; - new (this->key()) Key(*other.key()); + new ((void *)this->key()) Key(*other.key()); } } @@ -230,7 +230,7 @@ template<typename Key> class HashedSetSlot { m_state = other.m_state; if (other.m_state == Occupied) { m_hash = other.m_hash; - new (this->key()) Key(std::move(*other.key())); + new ((void *)this->key()) Key(std::move(*other.key())); } } @@ -266,7 +266,7 @@ template<typename Key> class HashedSetSlot { BLI_assert(other.is_occupied()); m_state = Occupied; m_hash = hash; - new (this->key()) Key(std::move(*other.key())); + new ((void *)this->key()) Key(std::move(*other.key())); other.key()->~Key(); } @@ -287,7 +287,7 @@ template<typename Key> class HashedSetSlot { BLI_assert(!this->is_occupied()); m_state = Occupied; m_hash = hash; - new (this->key()) Key(std::forward<ForwardKey>(key)); + new ((void *)this->key()) Key(std::forward<ForwardKey>(key)); } void remove() diff --git a/source/blender/blenlib/BLI_stack.hh b/source/blender/blenlib/BLI_stack.hh index 030d9c84c8e..2170b8b23bc 100644 --- a/source/blender/blenlib/BLI_stack.hh +++ b/source/blender/blenlib/BLI_stack.hh @@ -75,7 +75,7 @@ template< * not initialized when it is not needed. * * When T is large, the small buffer optimization is disabled by default to avoid large - * unexpected allocations on the stack. It can still be enabled explicitely though. + * unexpected allocations on the stack. It can still be enabled explicitly though. */ uint InlineBufferCapacity = (sizeof(T) < 100) ? 4 : 0, /** diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh index 073137fe175..bb8479efe95 100644 --- a/source/blender/blenlib/BLI_string_ref.hh +++ b/source/blender/blenlib/BLI_string_ref.hh @@ -292,8 +292,8 @@ inline std::ostream &operator<<(std::ostream &stream, StringRefNull ref) } /** - * Adding two StringRefs will allocate an std::string. This is not efficient, but convenient in - * most cases. + * Adding two #StringRefs will allocate an std::string. + * This is not efficient, but convenient in most cases. */ inline std::string operator+(StringRef a, StringRef b) { @@ -347,7 +347,7 @@ inline bool StringRefBase::endswith(StringRef suffix) const } /** - * Return a new StringRef containing only a substring of the original string. + * Return a new #StringRef containing only a sub-string of the original string. */ inline StringRef StringRefBase::substr(uint start, uint size) const { diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh index b2b2da0a4b0..f61a3d4282b 100644 --- a/source/blender/blenlib/BLI_vector.hh +++ b/source/blender/blenlib/BLI_vector.hh @@ -68,7 +68,7 @@ template< * not initialized when it is not needed. * * When T is large, the small buffer optimization is disabled by default to avoid large - * unexpected allocations on the stack. It can still be enabled explicitely though. + * unexpected allocations on the stack. It can still be enabled explicitly though. */ uint InlineBufferCapacity = (sizeof(T) < 100) ? 4 : 0, /** @@ -79,7 +79,7 @@ template< class Vector { private: /** - * Use pointers instead of storing the size explicitely. This reduces the number of instructions + * Use pointers instead of storing the size explicitly. This reduces the number of instructions * in `append`. * * The pointers might point to the memory in the inline buffer. @@ -95,7 +95,7 @@ class Vector { AlignedBuffer<(uint)sizeof(T) * InlineBufferCapacity, (uint)alignof(T)> m_inline_buffer; /** - * Store the size of the vector explicitely in debug builds. Otherwise you'd always have to call + * Store the size of the vector explicitly in debug builds. Otherwise you'd always have to call * the `size` function or do the math to compute it from the pointers manually. This is rather * annoying. Knowing the size of a vector is often quite essential when debugging some code. */ diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh index dcd4927aed2..03f25a68cd8 100644 --- a/source/blender/blenlib/BLI_vector_set.hh +++ b/source/blender/blenlib/BLI_vector_set.hh @@ -27,7 +27,7 @@ * * All core operations (add, remove and contains) can be done in O(1) amortized expected time. * - * Using a VectorSet instead of a normal Set can be benefitial in any of the following + * Using a VectorSet instead of a normal Set can be beneficial in any of the following * circumstances: * - The insertion order is important. * - Iteration over all keys has to be fast. diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a88b804d5b2..2bf4921f8df 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5604,7 +5604,7 @@ static void direct_link_modifiers(BlendDataReader *reader, ListBase *lb, Object else if (md->type == eModifierType_Armature) { ArmatureModifierData *amd = (ArmatureModifierData *)md; - amd->prevCos = NULL; + amd->vert_coords_prev = NULL; } else if (md->type == eModifierType_Cloth) { ClothModifierData *clmd = (ClothModifierData *)md; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 84c17a7ceb7..c6257738cf7 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1379,6 +1379,7 @@ static const char *ptcache_data_struct[] = { static const char *ptcache_extra_struct[] = { "", "ParticleSpring", + "vec3f", }; static void write_pointcaches(BlendWriter *writer, ListBase *ptcaches) { diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index ee543dcf25d..df6c139e916 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -251,8 +251,7 @@ void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *upd if (graph->is_active && id_node->is_user_modified) { deg_editors_id_update(update_ctx, id_orig); } - /* ID may need to get its auto-override operations refreshed. */ - if (ID_IS_OVERRIDE_LIBRARY_AUTO(id_orig)) { + if (ID_IS_OVERRIDE_LIBRARY(id_orig)) { id_orig->tag |= LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH; } /* Inform draw engines that something was changed. */ diff --git a/source/blender/draw/intern/draw_cache_impl_lattice.c b/source/blender/draw/intern/draw_cache_impl_lattice.c index bb313b31deb..66a67d6b8fe 100644 --- a/source/blender/draw/intern/draw_cache_impl_lattice.c +++ b/source/blender/draw/intern/draw_cache_impl_lattice.c @@ -127,7 +127,7 @@ typedef struct LatticeRenderData { int actbp; - struct MDeformVert *dvert; + const struct MDeformVert *dvert; } LatticeRenderData; enum { diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index e7dff422105..2ba766f4729 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1467,6 +1467,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, /* Only iterate over objects for internal engines or when overlays are enabled */ if (do_populate_loop) { + DST.dupli_origin = NULL; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; @@ -1864,6 +1865,7 @@ void DRW_render_object_iter( const int object_type_exclude_viewport = draw_ctx->v3d ? draw_ctx->v3d->object_type_exclude_viewport : 0; + DST.dupli_origin = NULL; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { if ((object_type_exclude_viewport & (1 << ob->type)) == 0) { DST.dupli_parent = data_.dupli_parent; @@ -2121,6 +2123,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, const int object_type_exclude_select = (v3d->object_type_exclude_viewport | v3d->object_type_exclude_select); bool filter_exclude = false; + DST.dupli_origin = NULL; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { if (!BKE_object_is_visible_in_viewport(v3d, ob)) { continue; @@ -2271,6 +2274,7 @@ static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph, drw_engines_world_update(DST.draw_ctx.scene); const int object_type_exclude_viewport = v3d->object_type_exclude_viewport; + DST.dupli_origin = NULL; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (DST.draw_ctx.depsgraph, ob) { if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c index 365c5b5d264..635fc6279ea 100644 --- a/source/blender/editors/mesh/editmesh_select_similar.c +++ b/source/blender/editors/mesh/editmesh_select_similar.c @@ -23,6 +23,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_bitmap.h" #include "BLI_kdtree.h" #include "BLI_listbase.h" #include "BLI_math.h" @@ -1007,7 +1008,9 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(ob); BMesh *bm = em->bm; int cd_dvert_offset = -1; - int dvert_selected = 0; + BLI_bitmap *defbase_selected = NULL; + int defbase_len = 0; + invert_m4_m4(ob->imat, ob->obmat); if (bm->totvertsel == 0) { @@ -1019,6 +1022,11 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) if (cd_dvert_offset == -1) { continue; } + defbase_len = BLI_listbase_count(&ob->defbase); + if (defbase_len == 0) { + continue; + } + defbase_selected = BLI_BITMAP_NEW(defbase_len, __func__); } BMVert *vert; /* Mesh vertex. */ @@ -1048,7 +1056,9 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) for (int i = 0; i < dvert->totweight; i++, dw++) { if (dw->weight > 0.0f) { - dvert_selected |= (1 << dw->def_nr); + if (LIKELY(dw->def_nr < defbase_len)) { + BLI_BITMAP_ENABLE(defbase_selected, dw->def_nr); + } } } break; @@ -1060,13 +1070,15 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) if (type == SIMVERT_VGROUP) { /* We store the names of the vertex groups, so we can select * vertex groups with the same name in different objects. */ - const int dvert_tot = BLI_listbase_count(&ob->defbase); - for (int i = 0; i < dvert_tot; i++) { - if (dvert_selected & (1 << i)) { - bDeformGroup *dg = BLI_findlink(&ob->defbase, i); + + int i = 0; + LISTBASE_FOREACH (bDeformGroup *, dg, &ob->defbase) { + if (BLI_BITMAP_TEST(defbase_selected, i)) { BLI_gset_add(gset, dg->name); } + i += 1; } + MEM_freeN(defbase_selected); } } @@ -1082,32 +1094,42 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) BLI_kdtree_3d_balance(tree_3d); } - /* Run .the BM operators. */ + /* Run the matching operations. */ for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *ob = objects[ob_index]; BMEditMesh *em = BKE_editmesh_from_object(ob); BMesh *bm = em->bm; bool changed = false; int cd_dvert_offset = -1; - int dvert_selected = 0; + BLI_bitmap *defbase_selected = NULL; + int defbase_len = 0; if (type == SIMVERT_VGROUP) { cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); if (cd_dvert_offset == -1) { continue; } + defbase_len = BLI_listbase_count(&ob->defbase); + if (defbase_len == 0) { + continue; + } /* We map back the names of the vertex groups to their corresponding indices * for this object. This is fast, and keep the logic for each vertex very simple. */ + + defbase_selected = BLI_BITMAP_NEW(defbase_len, __func__); + bool found_any = false; GSetIterator gs_iter; GSET_ITER (gs_iter, gset) { const char *name = BLI_gsetIterator_getKey(&gs_iter); int vgroup_id = BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)); if (vgroup_id != -1) { - dvert_selected |= (1 << vgroup_id); + BLI_BITMAP_ENABLE(defbase_selected, vgroup_id); + found_any = true; } } - if (dvert_selected == 0) { + if (found_any == false) { + MEM_freeN(defbase_selected); continue; } } @@ -1167,9 +1189,11 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) for (int i = 0; i < dvert->totweight; i++, dw++) { if (dw->weight > 0.0f) { - if (dvert_selected & (1 << dw->def_nr)) { - select = true; - break; + if (LIKELY(dw->def_nr < defbase_len)) { + if (BLI_BITMAP_TEST(defbase_selected, dw->def_nr)) { + select = true; + break; + } } } } @@ -1184,6 +1208,10 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) } } + if (type == SIMVERT_VGROUP) { + MEM_freeN(defbase_selected); + } + if (changed) { EDBM_selectmode_flush(em); EDBM_update_generic(ob->data, false, false); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 1e04355c9a7..a2d33ffe413 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -678,7 +678,7 @@ static bool edit_constraint_poll_generic(bContext *C, StructRNA *rna_type) return 0; } - if (ID_IS_OVERRIDE_LIBRARY(ob)) { + if (ID_IS_OVERRIDE_LIBRARY(ob) && ptr.data != NULL) { CTX_wm_operator_poll_msg_set(C, "Cannot edit constraints coming from library override"); return (((bConstraint *)ptr.data)->flag & CONSTRAINT_OVERRIDE_LIBRARY_LOCAL) != 0; } diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index eed3f2ea90c..fd2fcb11635 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2400,10 +2400,6 @@ static int make_override_library_exec(bContext *C, wmOperator *op) /* TODO: is setting active needed? */ BKE_view_layer_base_select_and_set_active(view_layer, base); } - else { - /* Disable auto-override tags for non-active objects, will help with performaces... */ - new_ob->id.override_library->flag &= ~OVERRIDE_LIBRARY_AUTO; - } /* We still want to store all objects' current override status (i.e. change of parent). */ BKE_lib_override_library_operations_create(bmain, &new_ob->id, true); } diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index 3203282c30c..7776af11a77 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -106,6 +106,27 @@ #define CLOTH_MAX_CONSTRAINTS_PER_VERTEX 1024 #define CLOTH_SIMULATION_TIME_STEP 0.01f +static void cloth_brush_constraint_key_get(int r_key[2], const int v1, const int v2) +{ + if (v1 < v2) { + r_key[0] = v1; + r_key[1] = v2; + } + else { + r_key[0] = v2; + r_key[1] = v1; + } +} + +static bool cloth_brush_sim_has_length_constraint(SculptClothSimulation *cloth_sim, + const int v1, + const int v2) +{ + int constraint[2]; + cloth_brush_constraint_key_get(constraint, v1, v2); + return BLI_gset_haskey(cloth_sim->created_length_constraints, constraint); +} + static void cloth_brush_add_length_constraint(SculptSession *ss, SculptClothSimulation *cloth_sim, const int v1, @@ -126,6 +147,11 @@ static void cloth_brush_add_length_constraint(SculptSession *ss, sizeof(SculptClothLengthConstraint), "length constraints"); } + + /* Add the constraint to the GSet to avoid creating it again. */ + int constraint[2]; + cloth_brush_constraint_key_get(constraint, v1, v2); + BLI_gset_add(cloth_sim->created_length_constraints, constraint); } static void do_cloth_brush_build_constraints_task_cb_ex( @@ -159,7 +185,8 @@ static void do_cloth_brush_build_constraints_task_cb_ex( for (int c_i = 0; c_i < tot_indices; c_i++) { for (int c_j = 0; c_j < tot_indices; c_j++) { - if (c_i != c_j) { + if (c_i != c_j && !cloth_brush_sim_has_length_constraint( + data->cloth_sim, build_indices[c_i], build_indices[c_j])) { cloth_brush_add_length_constraint( ss, data->cloth_sim, build_indices[c_i], build_indices[c_j]); } @@ -445,6 +472,9 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd, TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, false, totnode); + cloth_sim->created_length_constraints = BLI_gset_new( + BLI_ghashutil_inthash_v2_p, BLI_ghashutil_inthash_v2_cmp, "created length constraints"); + SculptThreadedTaskData build_constraints_data = { .sd = sd, .ob = ob, @@ -456,6 +486,8 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd, }; BLI_task_parallel_range( 0, totnode, &build_constraints_data, do_cloth_brush_build_constraints_task_cb_ex, &settings); + + BLI_gset_free(cloth_sim->created_length_constraints, NULL); } static void cloth_brush_satisfy_constraints(SculptSession *ss, diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c index 03ed8870d67..6d08fd00cab 100644 --- a/source/blender/editors/space_graph/graph_utils.c +++ b/source/blender/editors/space_graph/graph_utils.c @@ -52,7 +52,7 @@ /* Set Up Drivers Editor */ /* Set up UI configuration for Drivers Editor */ -/* NOTE: Currently called from windowmanager +/* NOTE: Currently called from window-manager * (new drivers editor window) and RNA (mode switching) */ void ED_drivers_editor_init(bContext *C, ScrArea *area) { diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index fa378954a30..e50b25de412 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -3667,7 +3667,7 @@ static int text_find_set_selected_exec(bContext *C, wmOperator *op) void TEXT_OT_find_set_selected(wmOperatorType *ot) { /* identifiers */ - ot->name = "Find Set Selected"; + ot->name = "Find & Set Selection"; ot->idname = "TEXT_OT_find_set_selected"; ot->description = "Find specified text and set as selected"; @@ -3698,7 +3698,7 @@ static int text_replace_set_selected_exec(bContext *C, wmOperator *UNUSED(op)) void TEXT_OT_replace_set_selected(wmOperatorType *ot) { /* identifiers */ - ot->name = "Replace Set Selected"; + ot->name = "Replace & Set Selection"; ot->idname = "TEXT_OT_replace_set_selected"; ot->description = "Replace text with specified text and set as selected"; diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c index 2bfce9f8418..22261b9bbd8 100644 --- a/source/blender/editors/transform/transform_convert_gpencil.c +++ b/source/blender/editors/transform/transform_convert_gpencil.c @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" #include "BLI_ghash.h" +#include "BLI_listbase.h" #include "BLI_math.h" #include "BKE_colortools.h" @@ -76,7 +77,6 @@ void createTransGPencil(bContext *C, TransInfo *t) bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0; Object *obact = CTX_data_active_object(C); - bGPDlayer *gpl; TransData *td = NULL; float mtx[3][3], smtx[3][3]; @@ -110,15 +110,12 @@ void createTransGPencil(bContext *C, TransInfo *t) /* First Pass: Count the number of data-points required for the strokes, * (and additional info about the configuration - e.g. 2D/3D?). */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* only editable and visible layers are considered */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + /* Only editable and visible layers are considered. */ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf; bGPDstroke *gps; - bGPDframe *init_gpf = gpl->actframe; - if (is_multiedit) { - init_gpf = gpl->frames.first; - } + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; for (gpf = init_gpf; gpf; gpf = gpf->next) { if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { @@ -127,7 +124,7 @@ void createTransGPencil(bContext *C, TransInfo *t) if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; } - /* check if the color is editable */ + /* Check if the color is editable. */ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) { continue; } @@ -135,23 +132,22 @@ void createTransGPencil(bContext *C, TransInfo *t) if (is_prop_edit) { /* Proportional Editing... */ if (is_prop_edit_connected) { - /* connected only - so only if selected */ + /* Connected only - so only if selected. */ if (gps->flag & GP_STROKE_SELECT) { tc->data_len += gps->totpoints; } } else { - /* everything goes - connection status doesn't matter */ + /* Everything goes - connection status doesn't matter. */ tc->data_len += gps->totpoints; } } else { - /* only selected stroke points are considered */ + /* Only selected stroke points are considered. */ if (gps->flag & GP_STROKE_SELECT) { bGPDspoint *pt; int i; - // TODO: 2D vs 3D? for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { tc->data_len++; @@ -161,7 +157,7 @@ void createTransGPencil(bContext *C, TransInfo *t) } } } - /* if not multiedit out of loop */ + /* If not multiedit out of loop. */ if (!is_multiedit) { break; } @@ -169,7 +165,7 @@ void createTransGPencil(bContext *C, TransInfo *t) } } - /* Stop trying if nothing selected */ + /* Stop trying if nothing selected. */ if (tc->data_len == 0) { return; } @@ -181,21 +177,17 @@ void createTransGPencil(bContext *C, TransInfo *t) unit_m3(smtx); unit_m3(mtx); - /* Second Pass: Build transdata array */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* Second Pass: Build transdata array. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* only editable and visible layers are considered */ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene; bGPDframe *gpf = gpl->actframe; - bGPDstroke *gps; float diff_mat[4][4]; float inverse_diff_mat[4][4]; - bGPDframe *init_gpf = gpl->actframe; - if (is_multiedit) { - init_gpf = gpl->frames.first; - } - /* init multiframe falloff options */ + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + /* Init multiframe falloff options. */ int f_init = 0; int f_end = 0; @@ -203,9 +195,9 @@ void createTransGPencil(bContext *C, TransInfo *t) BKE_gpencil_frame_range_selected(gpl, &f_init, &f_end); } - /* calculate difference matrix */ + /* Calculate difference matrix. */ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); - /* undo matrix */ + /* Undo matrix. */ invert_m4_m4(inverse_diff_mat, diff_mat); /* Make a new frame to work on if the layer's frame @@ -214,7 +206,6 @@ void createTransGPencil(bContext *C, TransInfo *t) * - This is useful when animating as it saves that "uh-oh" moment when you realize you've * spent too much time editing the wrong frame... */ - // XXX: should this be allowed when framelock is enabled? if ((gpf->framenum != cfra) && (!is_multiedit)) { gpf = BKE_gpencil_frame_addcopy(gpl, cfra); /* in some weird situations (framelock enabled) return NULL */ @@ -239,7 +230,7 @@ void createTransGPencil(bContext *C, TransInfo *t) gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff); } - for (gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { TransData *head = td; TransData *tail = td; bool stroke_ok; @@ -286,20 +277,20 @@ void createTransGPencil(bContext *C, TransInfo *t) /* include point? */ if (is_prop_edit) { - /* Always all points in strokes that get included */ + /* Always all points in strokes that get included. */ point_ok = true; } else { - /* Only selected points in selected strokes */ + /* Only selected points in selected strokes. */ point_ok = (pt->flag & GP_SPOINT_SELECT) != 0; } /* do point... */ if (point_ok) { copy_v3_v3(td->iloc, &pt->x); - /* only copy center in local origins. + /* Only copy center in local origins. * This allows get interesting effects also when move - * using proportional editing */ + * using proportional editing. */ if ((gps->flag & GP_STROKE_SELECT) && (ts->transform_pivot_point == V3D_AROUND_LOCAL_ORIGINS)) { copy_v3_v3(td->center, center); @@ -316,8 +307,8 @@ void createTransGPencil(bContext *C, TransInfo *t) td->flag |= TD_SELECTED; } - /* for other transform modes (e.g. shrink-fatten), need to additional data - * but never for mirror + /* For other transform modes (e.g. shrink-fatten), need to additional data + * but never for mirror. */ if (t->mode != TFM_MIRROR) { if (t->mode != TFM_GPENCIL_OPACITY) { @@ -363,7 +354,6 @@ void createTransGPencil(bContext *C, TransInfo *t) /* March over these points, and calculate the proportional editing distances */ if (is_prop_edit && (head != tail)) { - /* XXX: for now, we are similar enough that this works... */ calc_distanceCurveVerts(head, tail - 1); } } diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c index 5feaa70ba19..3fa722d14cf 100644 --- a/source/blender/editors/transform/transform_convert_particle.c +++ b/source/blender/editors/transform/transform_convert_particle.c @@ -250,7 +250,7 @@ static void flushTransParticles(TransInfo *t) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Recalc Trasform Particles Data +/** \name Recalc Transform Particles Data * * \{ */ diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index c6d7b92fb42..4f942221f79 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -634,12 +634,15 @@ static void initSnappingMode(TransInfo *t) t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( t->scene, 0, t->region, t->view); - ED_transform_snap_object_context_set_editmesh_callbacks( - t->tsnap.object_context, - (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, - bm_edge_is_snap_target, - bm_face_is_snap_target, - POINTER_FROM_UINT((BM_ELEM_SELECT | BM_ELEM_HIDDEN))); + if (t->data_type == TC_MESH_VERTS) { + /* Ignore elements being transformed. */ + ED_transform_snap_object_context_set_editmesh_callbacks( + t->tsnap.object_context, + (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, + bm_edge_is_snap_target, + bm_face_is_snap_target, + POINTER_FROM_UINT((BM_ELEM_SELECT | BM_ELEM_HIDDEN))); + } } } } diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh index d580ce54f1d..1dc72e16e77 100644 --- a/source/blender/functions/FN_cpp_type.hh +++ b/source/blender/functions/FN_cpp_type.hh @@ -70,6 +70,7 @@ #include "BLI_math_base.h" #include "BLI_string_ref.hh" +namespace blender { namespace FN { using blender::IndexMask; @@ -211,7 +212,7 @@ class CPPType { } /** - * Returns true, when the given pointer fullfills the alignment requirement of this type. + * Returns true, when the given pointer fulfills the alignment requirement of this type. */ bool pointer_has_valid_alignment(const void *ptr) const { @@ -719,13 +720,14 @@ static std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &d } } // namespace FN +} // namespace blender #define MAKE_CPP_TYPE(IDENTIFIER, TYPE_NAME) \ static TYPE_NAME default_value_##IDENTIFIER; \ - static std::unique_ptr<const FN::CPPType> CPPTYPE_##IDENTIFIER##_owner = \ - FN::create_cpp_type<TYPE_NAME>(STRINGIFY(IDENTIFIER), default_value_##IDENTIFIER); \ - const FN::CPPType &CPPType_##IDENTIFIER = *CPPTYPE_##IDENTIFIER##_owner; \ - template<> const FN::CPPType &FN::CPPType::get<TYPE_NAME>() \ + static std::unique_ptr<const blender::FN::CPPType> CPPTYPE_##IDENTIFIER##_owner = \ + blender::FN::create_cpp_type<TYPE_NAME>(STRINGIFY(IDENTIFIER), default_value_##IDENTIFIER); \ + const blender::FN::CPPType &CPPType_##IDENTIFIER = *CPPTYPE_##IDENTIFIER##_owner; \ + template<> const blender::FN::CPPType &blender::FN::CPPType::get<TYPE_NAME>() \ { \ return CPPType_##IDENTIFIER; \ } diff --git a/source/blender/functions/FN_cpp_types.hh b/source/blender/functions/FN_cpp_types.hh index eceb43beb9d..6ee8788cd52 100644 --- a/source/blender/functions/FN_cpp_types.hh +++ b/source/blender/functions/FN_cpp_types.hh @@ -26,6 +26,7 @@ #include "FN_cpp_type.hh" +namespace blender { namespace FN { extern const CPPType &CPPType_bool; @@ -44,5 +45,6 @@ extern const CPPType &CPPType_Color4b; extern const CPPType &CPPType_string; } // namespace FN +} // namespace blender #endif /* __FN_CPP_TYPES_HH__ */ diff --git a/source/blender/functions/intern/cpp_types.cc b/source/blender/functions/intern/cpp_types.cc index 6e548d65192..6339250caa5 100644 --- a/source/blender/functions/intern/cpp_types.cc +++ b/source/blender/functions/intern/cpp_types.cc @@ -21,6 +21,7 @@ #include "BLI_float3.hh" #include "BLI_float4x4.hh" +namespace blender { namespace FN { MAKE_CPP_TYPE(bool, bool) @@ -39,3 +40,4 @@ MAKE_CPP_TYPE(Color4b, blender::Color4b) MAKE_CPP_TYPE(string, std::string) } // namespace FN +} // namespace blender diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c index 2d5e01ced94..776e5521179 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c @@ -36,10 +36,10 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BKE_armature.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" -#include "BKE_lattice.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" @@ -69,39 +69,34 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target) static void gpencil_deform_verts(ArmatureGpencilModifierData *mmd, Object *target, bGPDstroke *gps) { bGPDspoint *pt = gps->points; - float *all_vert_coords = MEM_callocN(sizeof(float) * 3 * gps->totpoints, __func__); + float(*vert_coords)[3] = MEM_mallocN(sizeof(float[3]) * gps->totpoints, __func__); int i; BKE_gpencil_dvert_ensure(gps); /* prepare array of points */ for (i = 0; i < gps->totpoints; i++, pt++) { - float *pt_coords = &all_vert_coords[3 * i]; - float co[3]; - copy_v3_v3(co, &pt->x); - copy_v3_v3(pt_coords, co); + copy_v3_v3(vert_coords[i], &pt->x); } /* deform verts */ - armature_deform_verts(mmd->object, - target, - NULL, - (float(*)[3])all_vert_coords, - NULL, - gps->totpoints, - mmd->deformflag, - (float(*)[3])mmd->prevCos, - mmd->vgname, - gps); + BKE_armature_deform_coords_with_gpencil_stroke(mmd->object, + target, + vert_coords, + NULL, + gps->totpoints, + mmd->deformflag, + mmd->vert_coords_prev, + mmd->vgname, + gps); /* Apply deformed coordinates */ pt = gps->points; for (i = 0; i < gps->totpoints; i++, pt++) { - float *pt_coords = &all_vert_coords[3 * i]; - copy_v3_v3(&pt->x, pt_coords); + copy_v3_v3(&pt->x, vert_coords[i]); } - MEM_SAFE_FREE(all_vert_coords); + MEM_freeN(vert_coords); } /* deform stroke */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c index 5d5d673ca55..92b35f390f8 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -105,7 +105,8 @@ static void deformStroke(GpencilModifierData *md, if (weight < 0.0f) { continue; } - calc_latt_deform((struct LatticeDeformData *)mmd->cache_data, &pt->x, mmd->strength * weight); + BKE_lattice_deform_data_eval_co( + (struct LatticeDeformData *)mmd->cache_data, &pt->x, mmd->strength * weight); } /* Calc geometry data. */ BKE_gpencil_stroke_geometry_update(gps); @@ -147,7 +148,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData /* free lingering data */ ldata = (struct LatticeDeformData *)mmd->cache_data; if (ldata) { - end_latt_deform(ldata); + BKE_lattice_deform_data_destroy(ldata); mmd->cache_data = NULL; } @@ -162,7 +163,7 @@ static void freeData(GpencilModifierData *md) struct LatticeDeformData *ldata = (struct LatticeDeformData *)mmd->cache_data; /* free deform data */ if (ldata) { - end_latt_deform(ldata); + BKE_lattice_deform_data_destroy(ldata); } } diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 1c346217e9f..b03b0fc0b1e 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -912,6 +912,11 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y); + if (textarget == GL_TEXTURE_1D_ARRAY) { + /* Special for tile mapping. */ + GPU_texture_mipmap_mode(*tex, false, false); + } + return *tex; #endif return NULL; diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 469abefca68..ab55fcfb1e0 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -304,7 +304,14 @@ void gpu_extensions_init(void) } } - GG.glew_arb_base_instance_is_supported = GLEW_ARB_base_instance; + /* Limit support for GLEW_ARB_base_instance to OpenGL 4.0 and higher. NVIDIA Quadro FX 4800 + * (TeraScale) report that they support GLEW_ARB_base_instance, but the driver does not support + * GLEW_ARB_draw_indirect as it has an OpenGL3 context what also matches the minimum needed + * requirements. + * + * We use it as a target for glMapBuffer(Range) what is part of the OpenGL 4 API. So better + * disable it when we don't have an OpenGL4 context (See T77657) */ + GG.glew_arb_base_instance_is_supported = GLEW_ARB_base_instance && GLEW_VERSION_4_0; GG.glew_arb_texture_cube_map_array_is_supported = GLEW_ARB_texture_cube_map_array; gpu_detect_mip_render_workaround(); diff --git a/source/blender/io/alembic/intern/abc_writer_points.cc b/source/blender/io/alembic/intern/abc_writer_points.cc index d45af2eed4c..ac663b62693 100644 --- a/source/blender/io/alembic/intern/abc_writer_points.cc +++ b/source/blender/io/alembic/intern/abc_writer_points.cc @@ -104,7 +104,7 @@ void AbcPointsWriter::do_write() } if (m_psys->lattice_deform_data) { - end_latt_deform(m_psys->lattice_deform_data); + BKE_lattice_deform_data_destroy(m_psys->lattice_deform_data); m_psys->lattice_deform_data = NULL; } diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index 841501bcf42..61337beff20 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -335,6 +335,7 @@ void USDGenericMeshWriter::assign_materials(const HierarchyContext &context, * which is why we always bind the first material to the entire mesh. See * https://github.com/PixarAnimationStudios/USD/issues/542 for more info. */ bool mesh_material_bound = false; + pxr::UsdShadeMaterialBindingAPI material_binding_api(usd_mesh.GetPrim()); for (short mat_num = 0; mat_num < context.object->totcol; mat_num++) { Material *material = BKE_object_material_get(context.object, mat_num + 1); if (material == nullptr) { @@ -342,7 +343,7 @@ void USDGenericMeshWriter::assign_materials(const HierarchyContext &context, } pxr::UsdShadeMaterial usd_material = ensure_usd_material(material); - usd_material.Bind(usd_mesh.GetPrim()); + material_binding_api.Bind(usd_material); /* USD seems to support neither per-material nor per-face-group double-sidedness, so we just * use the flag from the first non-empty material slot. */ @@ -378,9 +379,9 @@ void USDGenericMeshWriter::assign_materials(const HierarchyContext &context, pxr::UsdShadeMaterial usd_material = ensure_usd_material(material); pxr::TfToken material_name = usd_material.GetPath().GetNameToken(); - pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(usd_mesh); - pxr::UsdGeomSubset usd_face_subset = api.CreateMaterialBindSubset(material_name, face_indices); - usd_material.Bind(usd_face_subset.GetPrim()); + pxr::UsdGeomSubset usd_face_subset = material_binding_api.CreateMaterialBindSubset( + material_name, face_indices); + pxr::UsdShadeMaterialBindingAPI(usd_face_subset.GetPrim()).Bind(usd_material); } } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 265b16992d8..eb02352f49b 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -225,9 +225,6 @@ typedef struct IDOverrideLibrary { /** List of IDOverrideProperty structs. */ ListBase properties; - short flag; - char _pad[6]; - /* Read/write data. */ /* Temp ID storing extra override data (used for differential operations only currently). * Always NULL outside of read/write context. */ @@ -236,10 +233,6 @@ typedef struct IDOverrideLibrary { IDOverrideLibraryRuntime *runtime; } IDOverrideLibrary; -enum eOverrideLibrary_Flag { - OVERRIDE_LIBRARY_AUTO = 1 << 0, /* Allow automatic generation of overriding rules. */ -}; - /** * About Unique identifier. * @@ -540,10 +533,6 @@ typedef enum ID_Type { #define ID_IS_OVERRIDE_LIBRARY_TEMPLATE(_id) \ (((ID *)(_id))->override_library != NULL && ((ID *)(_id))->override_library->reference == NULL) -#define ID_IS_OVERRIDE_LIBRARY_AUTO(_id) \ - (!ID_IS_LINKED((_id)) && ID_IS_OVERRIDE_LIBRARY((_id)) && \ - (((ID *)(_id))->override_library->flag & OVERRIDE_LIBRARY_AUTO)) - /* Check whether datablock type is covered by copy-on-write. */ #define ID_TYPE_IS_COW(_id_type) (!ELEM(_id_type, ID_BR, ID_PAL, ID_IM)) diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h index 8f3a26cf9c0..9d9ee711339 100644 --- a/source/blender/makesdna/DNA_cloth_types.h +++ b/source/blender/makesdna/DNA_cloth_types.h @@ -109,8 +109,11 @@ typedef struct ClothSimSettings { pressure=( (current_volume/target_volume) - 1 + uniform_pressure_force) * pressure_factor */ float pressure_factor; + /* Density of the fluid inside or outside the object for use in the hydrostatic pressure + * gradient. */ + float fluid_density; short vgroup_pressure; - char _pad7[2]; + char _pad7[6]; /* XXX various hair stuff * should really be separate, this struct is a horrible mess already diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index 125423cd061..674999ab465 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -24,6 +24,8 @@ #include "DNA_defs.h" #include "DNA_listBase.h" +struct LatticeDeformData; + /* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE! * (ONLY ADD NEW ITEMS AT THE END) */ @@ -445,8 +447,8 @@ typedef struct LatticeGpencilModifierData { float strength; /** Custom index for passes. */ int layer_pass; - /** Runtime only (LatticeDeformData). */ - void *cache_data; + /** Runtime only. */ + struct LatticeDeformData *cache_data; } LatticeGpencilModifierData; typedef enum eLatticeGpencil_Flag { @@ -655,12 +657,12 @@ typedef enum eSmoothGpencil_Flag { typedef struct ArmatureGpencilModifierData { GpencilModifierData modifier; - /** Deformflag replaces armature->deformflag. */ + /** #eArmature_DeformFlag use instead of #bArmature.deformflag. */ short deformflag, multi; int _pad; struct Object *object; - /** Stored input of previous modifier, for vertexgroup blending. */ - float *prevCos; + /** Stored input of previous modifier, for vertex-group blending. */ + float (*vert_coords_prev)[3]; /** MAX_VGROUP_NAME. */ char vgname[64]; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index a2b96ac2772..1413db4baea 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -693,12 +693,12 @@ enum { typedef struct ArmatureModifierData { ModifierData modifier; - /** Deformflag replaces armature->deformflag. */ + /** #eArmature_DeformFlag use instead of #bArmature.deformflag. */ short deformflag, multi; char _pad2[4]; struct Object *object; - /** Stored input of previous modifier, for vertexgroup blending. */ - float *prevCos; + /** Stored input of previous modifier, for vertex-group blending. */ + float (*vert_coords_prev)[3]; /** MAX_VGROUP_NAME. */ char defgrp_name[64]; } ArmatureModifierData; diff --git a/source/blender/makesdna/DNA_pointcache_types.h b/source/blender/makesdna/DNA_pointcache_types.h index fcdc22ca56d..3c7fc9031de 100644 --- a/source/blender/makesdna/DNA_pointcache_types.h +++ b/source/blender/makesdna/DNA_pointcache_types.h @@ -50,6 +50,7 @@ extern "C" { #define BPHYS_TOT_DATA 8 #define BPHYS_EXTRA_FLUID_SPRINGS 1 +#define BPHYS_EXTRA_CLOTH_ACCELERATION 2 typedef struct PTCacheExtra { struct PTCacheExtra *next, *prev; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index e1e8d808c60..a07b8f81d96 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -265,7 +265,7 @@ typedef struct wmWindow { short modalcursor; /** Cursor grab mode. */ short grabcursor; - /** Internal: tag this for extra mousemove event, + /** Internal: tag this for extra mouse-move event, * makes cursors/buttons active on UI switching. */ char addmousemove; char tag_cursor_refresh; diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 56e3cc3cc9e..50658ef412b 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -1441,7 +1441,6 @@ static void rna_def_ID_override_library_property(BlenderRNA *brna) static void rna_def_ID_override_library(BlenderRNA *brna) { StructRNA *srna; - PropertyRNA *prop; srna = RNA_def_struct(brna, "IDOverrideLibrary", NULL); RNA_def_struct_ui_text( @@ -1450,14 +1449,6 @@ static void rna_def_ID_override_library(BlenderRNA *brna) RNA_def_pointer( srna, "reference", "ID", "Reference ID", "Linked ID used as reference by this override"); - prop = RNA_def_boolean( - srna, - "auto_generate", - true, - "Auto Generate Override", - "Automatically generate overriding operations by detecting changes in properties"); - RNA_def_property_boolean_sdna(prop, NULL, "flag", OVERRIDE_LIBRARY_AUTO); - RNA_def_collection(srna, "properties", "IDOverrideLibraryProperty", diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c index 70f219259ef..594b77ea1ad 100644 --- a/source/blender/makesrna/intern/rna_cloth.c +++ b/source/blender/makesrna/intern/rna_cloth.c @@ -975,8 +975,10 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_pressure_volume", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL); - RNA_def_property_ui_text( - prop, "Use Custom Volume", "Use the Volume parameter as the initial volume"); + RNA_def_property_ui_text(prop, + "Use Custom Volume", + "Use the Target Volume parameter as the initial volume, instead " + "of calculating it from the mesh itself"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_cloth_update"); @@ -984,10 +986,10 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "uniform_pressure_force"); RNA_def_property_range(prop, -10000.0f, 10000.0f); RNA_def_property_float_default(prop, 0.0f); - RNA_def_property_ui_text( - prop, - "Pressure", - "The uniform pressure that is constantly applied to the mesh. Can be negative"); + RNA_def_property_ui_text(prop, + "Pressure", + "The uniform pressure that is constantly applied to the mesh, in units " + "of Pressure Scale. Can be negative"); RNA_def_property_update(prop, 0, "rna_cloth_update"); prop = RNA_def_property(srna, "target_volume", PROP_FLOAT, PROP_NONE); @@ -997,14 +999,28 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Target Volume", "The mesh volume where the inner/outer pressure will be the same. If " - "set to zero the volume will not contribute to the total pressure"); + "set to zero the change in volume will not affect pressure"); RNA_def_property_update(prop, 0, "rna_cloth_update"); prop = RNA_def_property(srna, "pressure_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "pressure_factor"); RNA_def_property_range(prop, 0.0f, 10000.0f); RNA_def_property_float_default(prop, 1.0f); - RNA_def_property_ui_text(prop, "Pressure Scale", "Air pressure scaling factor"); + RNA_def_property_ui_text(prop, + "Pressure Scale", + "Ambient pressure (kPa) that balances out between the inside and " + "outside of the object when it has the target volume"); + RNA_def_property_update(prop, 0, "rna_cloth_update"); + + prop = RNA_def_property(srna, "fluid_density", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "fluid_density"); + RNA_def_property_ui_range(prop, -2.0f, 2.0f, 0.05f, 4); + RNA_def_property_ui_text( + prop, + "Fluid Density", + "Density (kg/l) of the fluid contained inside the object, used to create " + "a hydrostatic pressure gradient simulating the weight of the internal fluid, " + "or buoyancy from the surrounding fluid if negative"); RNA_def_property_update(prop, 0, "rna_cloth_update"); prop = RNA_def_property(srna, "vertex_group_pressure", PROP_STRING, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index a52811a9a9a..c707ad9b84e 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -76,6 +76,35 @@ static EnumPropertyItem rna_enum_gpencil_onion_modes_items[] = { {0, NULL, 0, NULL, NULL}, }; +static const EnumPropertyItem rna_enum_keyframe_type_items[] = { + {BEZT_KEYTYPE_KEYFRAME, + "KEYFRAME", + ICON_KEYTYPE_KEYFRAME_VEC, + "Keyframe", + "Normal keyframe - e.g. for key poses"}, + {BEZT_KEYTYPE_BREAKDOWN, + "BREAKDOWN", + ICON_KEYTYPE_BREAKDOWN_VEC, + "Breakdown", + "A breakdown pose - e.g. for transitions between key poses"}, + {BEZT_KEYTYPE_MOVEHOLD, + "MOVING_HOLD", + ICON_KEYTYPE_MOVING_HOLD_VEC, + "Moving Hold", + "A keyframe that is part of a moving hold"}, + {BEZT_KEYTYPE_EXTREME, + "EXTREME", + ICON_KEYTYPE_EXTREME_VEC, + "Extreme", + "An 'extreme' pose, or some other purpose as needed"}, + {BEZT_KEYTYPE_JITTER, + "JITTER", + ICON_KEYTYPE_JITTER_VEC, + "Jitter", + "A filler or baked keyframe for keying on ones, or some other purpose as needed"}, + {0, NULL, 0, NULL, NULL}, +}; + static const EnumPropertyItem rna_enum_onion_keyframe_type_items[] = { {-1, "ALL", ICON_ACTION, "All Types", "Include all Keyframe types"}, {BEZT_KEYTYPE_KEYFRAME, @@ -1324,6 +1353,13 @@ static void rna_def_gpencil_frame(BlenderRNA *brna) RNA_def_property_range(prop, -MAXFRAME, MAXFRAME); RNA_def_property_ui_text(prop, "Frame Number", "The frame on which this sketch appears"); + prop = RNA_def_property(srna, "keyframe_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "key_type"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_enum_items(prop, rna_enum_keyframe_type_items); + RNA_def_property_ui_text(prop, "Keyframe Type", "Type of keyframe"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + /* Flags */ prop = RNA_def_property(srna, "is_edited", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna( diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index c5781175d65..093fd8b3bd5 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -1174,6 +1174,22 @@ void RNA_def_main_libraries(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "tag", "rna_Main_libraries_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_function_ui_description(func, "Remove a camera from the current blendfile"); + parm = RNA_def_pointer(func, "library", "Library", "", "Library to remove"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_boolean( + func, "do_unlink", true, "", "Unlink all usages of this library before deleting it"); + RNA_def_boolean(func, + "do_id_user", + true, + "", + "Decrement user counter of all datablocks used by this object"); + RNA_def_boolean( + func, "do_ui_user", true, "", "Make sure interface does not reference this object"); } void RNA_def_main_screens(BlenderRNA *brna, PropertyRNA *cprop) diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index ad8d6ac8b8a..0cc0680804e 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -34,9 +34,9 @@ #include "DNA_screen_types.h" #include "BKE_action.h" +#include "BKE_armature.h" #include "BKE_context.h" #include "BKE_editmesh.h" -#include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_mesh.h" @@ -74,7 +74,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla ArmatureModifierData *tamd = (ArmatureModifierData *)target; BKE_modifier_copydata_generic(md, target, flag); - tamd->prevCos = NULL; + tamd->vert_coords_prev = NULL; } static void requiredDataMask(Object *UNUSED(ob), @@ -146,88 +146,64 @@ static void deformVerts(ModifierData *md, MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ - armature_deform_verts(amd->object, - ctx->object, - mesh, - vertexCos, - NULL, - numVerts, - amd->deformflag, - (float(*)[3])amd->prevCos, - amd->defgrp_name, - NULL); + BKE_armature_deform_coords_with_mesh(amd->object, + ctx->object, + vertexCos, + NULL, + numVerts, + amd->deformflag, + amd->vert_coords_prev, + amd->defgrp_name, + mesh); /* free cache */ - if (amd->prevCos) { - MEM_freeN(amd->prevCos); - amd->prevCos = NULL; - } + MEM_SAFE_FREE(amd->vert_coords_prev); } static void deformVertsEM(ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em, - Mesh *mesh, + Mesh *UNUSED(mesh), float (*vertexCos)[3], int numVerts) { ArmatureModifierData *amd = (ArmatureModifierData *)md; - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); - - /* TODO(Campbell): use edit-mode data only (remove this line). */ - if (mesh_src != NULL) { - BKE_mesh_wrapper_ensure_mdata(mesh_src); - } MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ - armature_deform_verts(amd->object, - ctx->object, - mesh_src, - vertexCos, - NULL, - numVerts, - amd->deformflag, - (float(*)[3])amd->prevCos, - amd->defgrp_name, - NULL); + BKE_armature_deform_coords_with_editmesh(amd->object, + ctx->object, + vertexCos, + NULL, + numVerts, + amd->deformflag, + amd->vert_coords_prev, + amd->defgrp_name, + em); /* free cache */ - if (amd->prevCos) { - MEM_freeN(amd->prevCos); - amd->prevCos = NULL; - } - - if (mesh_src != mesh) { - BKE_id_free(NULL, mesh_src); - } + MEM_SAFE_FREE(amd->vert_coords_prev); } static void deformMatricesEM(ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em, - Mesh *mesh, + Mesh *UNUSED(mesh), float (*vertexCos)[3], float (*defMats)[3][3], int numVerts) { ArmatureModifierData *amd = (ArmatureModifierData *)md; - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); - - armature_deform_verts(amd->object, - ctx->object, - mesh_src, - vertexCos, - defMats, - numVerts, - amd->deformflag, - NULL, - amd->defgrp_name, - NULL); - - if (mesh_src != mesh) { - BKE_id_free(NULL, mesh_src); - } + + BKE_armature_deform_coords_with_editmesh(amd->object, + ctx->object, + vertexCos, + defMats, + numVerts, + amd->deformflag, + NULL, + amd->defgrp_name, + em); } static void deformMatrices(ModifierData *md, @@ -240,16 +216,15 @@ static void deformMatrices(ModifierData *md, ArmatureModifierData *amd = (ArmatureModifierData *)md; Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - armature_deform_verts(amd->object, - ctx->object, - mesh_src, - vertexCos, - defMats, - numVerts, - amd->deformflag, - NULL, - amd->defgrp_name, - NULL); + BKE_armature_deform_coords_with_mesh(amd->object, + ctx->object, + vertexCos, + defMats, + numVerts, + amd->deformflag, + NULL, + amd->defgrp_name, + mesh_src); if (!ELEM(mesh_src, NULL, mesh)) { BKE_id_free(NULL, mesh_src); diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index a2348539779..a13bb07f678 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -33,8 +33,9 @@ #include "DNA_screen_types.h" #include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_deform.h" #include "BKE_editmesh.h" -#include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_mesh.h" @@ -129,16 +130,17 @@ static void deformVerts(ModifierData *md, int defgrp_index = -1; MOD_get_vgroup(ctx->object, mesh_src, cmd->name, &dvert, &defgrp_index); - /* silly that defaxis and curve_deform_verts are off by 1 + /* Silly that defaxis and BKE_curve_deform_coords are off by 1 * but leave for now to save having to call do_versions */ - curve_deform_verts(cmd->object, - ctx->object, - vertexCos, - numVerts, - dvert, - defgrp_index, - cmd->flag, - cmd->defaxis - 1); + + BKE_curve_deform_coords(cmd->object, + ctx->object, + vertexCos, + numVerts, + dvert, + defgrp_index, + cmd->flag, + cmd->defaxis - 1); if (!ELEM(mesh_src, NULL, mesh)) { BKE_id_free(NULL, mesh_src); @@ -147,22 +149,41 @@ static void deformVerts(ModifierData *md, static void deformVertsEM(ModifierData *md, const ModifierEvalContext *ctx, - struct BMEditMesh *em, - Mesh *mesh, + BMEditMesh *em, + Mesh *UNUSED(mesh), float (*vertexCos)[3], int numVerts) { - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); + CurveModifierData *cmd = (CurveModifierData *)md; + bool use_dverts = false; + int defgrp_index = -1; - /* TODO(Campbell): use edit-mode data only (remove this line). */ - if (mesh_src != NULL) { - BKE_mesh_wrapper_ensure_mdata(mesh_src); + if (ctx->object->type == OB_MESH && cmd->name[0] != '\0') { + defgrp_index = BKE_object_defgroup_name_index(ctx->object, cmd->name); + if (defgrp_index != -1) { + use_dverts = true; + } } - deformVerts(md, ctx, mesh_src, vertexCos, numVerts); - - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); + if (use_dverts) { + BKE_curve_deform_coords_with_editmesh(cmd->object, + ctx->object, + vertexCos, + numVerts, + defgrp_index, + cmd->flag, + cmd->defaxis - 1, + em); + } + else { + BKE_curve_deform_coords(cmd->object, + ctx->object, + vertexCos, + numVerts, + NULL, + defgrp_index, + cmd->flag, + cmd->defaxis - 1); } } diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 0c1eedd429a..f2e476f85aa 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -1115,7 +1115,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, explode->runtime.cd_dirty_vert |= CD_MASK_NORMAL; if (psmd->psys->lattice_deform_data) { - end_latt_deform(psmd->psys->lattice_deform_data); + BKE_lattice_deform_data_destroy(psmd->psys->lattice_deform_data); psmd->psys->lattice_deform_data = NULL; } diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c index 4d96638fc83..574ea969be4 100644 --- a/source/blender/modifiers/intern/MOD_lattice.c +++ b/source/blender/modifiers/intern/MOD_lattice.c @@ -113,14 +113,14 @@ static void deformVerts(ModifierData *md, MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ - lattice_deform_verts(lmd->object, - ctx->object, - mesh_src, - vertexCos, - numVerts, - lmd->flag, - lmd->name, - lmd->strength); + BKE_lattice_deform_coords_with_mesh(lmd->object, + ctx->object, + vertexCos, + numVerts, + lmd->flag, + lmd->name, + lmd->strength, + mesh_src); if (!ELEM(mesh_src, NULL, mesh)) { BKE_id_free(NULL, mesh_src); @@ -130,23 +130,16 @@ static void deformVerts(ModifierData *md, static void deformVertsEM(ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em, - struct Mesh *mesh, + struct Mesh *UNUSED(mesh), float (*vertexCos)[3], int numVerts) { - struct Mesh *mesh_src = MOD_deform_mesh_eval_get( - ctx->object, em, mesh, NULL, numVerts, false, false); - - /* TODO(Campbell): use edit-mode data only (remove this line). */ - if (mesh_src != NULL) { - BKE_mesh_wrapper_ensure_mdata(mesh_src); - } + LatticeModifierData *lmd = (LatticeModifierData *)md; - deformVerts(md, ctx, mesh_src, vertexCos, numVerts); + MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + BKE_lattice_deform_coords_with_editmesh( + lmd->object, ctx->object, vertexCos, numVerts, lmd->flag, lmd->name, lmd->strength, em); } static void panel_draw(const bContext *C, Panel *panel) diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index 0a9fb964281..62b28f22c17 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -542,7 +542,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } if (psys->lattice_deform_data) { - end_latt_deform(psys->lattice_deform_data); + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index 1aee545aa43..c6dff375109 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -169,12 +169,12 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd, } } -void MOD_previous_vcos_store(ModifierData *md, float (*vertexCos)[3]) +void MOD_previous_vcos_store(ModifierData *md, const float (*vert_coords)[3]) { while ((md = md->next) && md->type == eModifierType_Armature) { ArmatureModifierData *amd = (ArmatureModifierData *)md; - if (amd->multi && amd->prevCos == NULL) { - amd->prevCos = MEM_dupallocN(vertexCos); + if (amd->multi && amd->vert_coords_prev == NULL) { + amd->vert_coords_prev = MEM_dupallocN(vert_coords); } else { break; @@ -187,7 +187,7 @@ void MOD_previous_vcos_store(ModifierData *md, float (*vertexCos)[3]) Mesh *MOD_deform_mesh_eval_get(Object *ob, struct BMEditMesh *em, Mesh *mesh, - float (*vertexCos)[3], + const float (*vertexCos)[3], const int num_verts, const bool use_normals, const bool use_orco) diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h index 38e2083082d..a05e25d204c 100644 --- a/source/blender/modifiers/intern/MOD_util.h +++ b/source/blender/modifiers/intern/MOD_util.h @@ -40,12 +40,12 @@ void MOD_get_texture_coords(struct MappingInfoModifierData *dmd, float (*cos)[3], float (*r_texco)[3]); -void MOD_previous_vcos_store(struct ModifierData *md, float (*vertexCos)[3]); +void MOD_previous_vcos_store(struct ModifierData *md, const float (*vertexCos)[3]); struct Mesh *MOD_deform_mesh_eval_get(struct Object *ob, struct BMEditMesh *em, struct Mesh *mesh, - float (*vertexCos)[3], + const float (*vertexCos)[3], const int num_verts, const bool use_normals, const bool use_orco); diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp index 6a951519730..18fab5215a6 100644 --- a/source/blender/physics/intern/BPH_mass_spring.cpp +++ b/source/blender/physics/intern/BPH_mass_spring.cpp @@ -72,12 +72,50 @@ static int cloth_count_nondiag_blocks(Cloth *cloth) return nondiag; } +static bool cloth_get_pressure_weights(ClothModifierData *clmd, + const MVertTri *vt, + float *r_weights) +{ + /* We have custom vertex weights for pressure. */ + if (clmd->sim_parms->vgroup_pressure > 0) { + Cloth *cloth = clmd->clothObject; + ClothVertex *verts = cloth->verts; + + for (unsigned int j = 0; j < 3; j++) { + r_weights[j] = verts[vt->tri[j]].pressure_factor; + + /* Skip the entire triangle if it has a zero weight. */ + if (r_weights[j] == 0.0f) { + return false; + } + } + } + + return true; +} + +static void cloth_calc_pressure_gradient(ClothModifierData *clmd, + const float gradient_vector[3], + float *r_vertex_pressure) +{ + Cloth *cloth = clmd->clothObject; + Implicit_Data *data = cloth->implicit; + unsigned int mvert_num = cloth->mvert_num; + float pt[3]; + + for (unsigned int i = 0; i < mvert_num; i++) { + BPH_mass_spring_get_position(data, i, pt); + r_vertex_pressure[i] = dot_v3v3(pt, gradient_vector); + } +} + static float cloth_calc_volume(ClothModifierData *clmd) { /* Calculate the (closed) cloth volume. */ Cloth *cloth = clmd->clothObject; const MVertTri *tri = cloth->tri; Implicit_Data *data = cloth->implicit; + float weights[3] = {1.0f, 1.0f, 1.0f}; float vol = 0; /* Early exit for hair, as it never has volume. */ @@ -85,38 +123,45 @@ static float cloth_calc_volume(ClothModifierData *clmd) return 0.0f; } - if (clmd->sim_parms->vgroup_pressure > 0) { - for (unsigned int i = 0; i < cloth->primitive_num; i++) { - bool skip_face = false; - /* We have custom vertex weights for pressure. */ - const MVertTri *vt = &tri[i]; - for (unsigned int j = 0; j < 3; j++) { - /* If any weight is zero, don't take this face into account for volume calculation. */ - ClothVertex *verts = clmd->clothObject->verts; - - if (verts[vt->tri[j]].pressure_factor == 0.0f) { - skip_face = true; - } - } - if (skip_face) { - continue; - } + for (unsigned int i = 0; i < cloth->primitive_num; i++) { + const MVertTri *vt = &tri[i]; + if (cloth_get_pressure_weights(clmd, vt, weights)) { vol += BPH_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]); } } - else { - for (unsigned int i = 0; i < cloth->primitive_num; i++) { - const MVertTri *vt = &tri[i]; - vol += BPH_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]); - } - } + /* We need to divide by 6 to get the actual volume. */ vol = vol / 6.0f; return vol; } +static float cloth_calc_average_pressure(ClothModifierData *clmd, const float *vertex_pressure) +{ + Cloth *cloth = clmd->clothObject; + const MVertTri *tri = cloth->tri; + Implicit_Data *data = cloth->implicit; + float weights[3] = {1.0f, 1.0f, 1.0f}; + float total_force = 0; + float total_area = 0; + + for (unsigned int i = 0; i < cloth->primitive_num; i++) { + const MVertTri *vt = &tri[i]; + + if (cloth_get_pressure_weights(clmd, vt, weights)) { + float area = BPH_tri_area(data, vt->tri[0], vt->tri[1], vt->tri[2]); + + total_force += (vertex_pressure[vt->tri[0]] + vertex_pressure[vt->tri[1]] + + vertex_pressure[vt->tri[2]]) * + area / 3.0f; + total_area += area; + } + } + + return total_force / total_area; +} + int BPH_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd) { Cloth *cloth = clmd->clothObject; @@ -554,6 +599,7 @@ static void cloth_calc_force( if ((parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE) && (clmd->hairdata == NULL)) { /* The difference in pressure between the inside and outside of the mesh.*/ float pressure_difference = 0.0f; + float volume_factor = 1.0f; float init_vol; if (parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL) { @@ -568,59 +614,71 @@ static void cloth_calc_force( float f; float vol = cloth_calc_volume(clmd); + /* If the volume is the same don't apply any pressure. */ + volume_factor = init_vol / vol; + pressure_difference = volume_factor - 1; + /* Calculate an artificial maximum value for cloth pressure. */ f = fabs(clmd->sim_parms->uniform_pressure_force) + 200.0f; /* Clamp the cloth pressure to the calculated maximum value. */ - if (vol * f < init_vol) { - pressure_difference = f; - } - else { - /* If the volume is the same don't apply any pressure. */ - pressure_difference = (init_vol / vol) - 1; - } + CLAMP_MAX(pressure_difference, f); } - pressure_difference += clmd->sim_parms->uniform_pressure_force; + pressure_difference += clmd->sim_parms->uniform_pressure_force; pressure_difference *= clmd->sim_parms->pressure_factor; - for (i = 0; i < cloth->primitive_num; i++) { - const MVertTri *vt = &tri[i]; - if (fabs(pressure_difference) > 1E-6f) { - if (clmd->sim_parms->vgroup_pressure > 0) { - /* We have custom vertex weights for pressure. */ - ClothVertex *verts = clmd->clothObject->verts; - int v1, v2, v3; - v1 = vt->tri[0]; - v2 = vt->tri[1]; - v3 = vt->tri[2]; - - float weights[3]; - bool skip_face = false; - - weights[0] = verts[v1].pressure_factor; - weights[1] = verts[v2].pressure_factor; - weights[2] = verts[v3].pressure_factor; - for (unsigned int j = 0; j < 3; j++) { - if (weights[j] == 0.0f) { - /* Exclude faces which has a zero weight vert. */ - skip_face = true; - break; - } - } - if (skip_face) { - continue; - } + /* Compute the hydrostatic pressure gradient if enabled. */ + float fluid_density = clmd->sim_parms->fluid_density * 1000; /* kg/l -> kg/m3 */ + float *hydrostatic_pressure = NULL; - BPH_mass_spring_force_pressure(data, v1, v2, v3, pressure_difference, weights); - } - else { - float weights[3] = {1.0f, 1.0f, 1.0f}; - BPH_mass_spring_force_pressure( - data, vt->tri[0], vt->tri[1], vt->tri[2], pressure_difference, weights); + if (fabs(fluid_density) > 1e-6f) { + float hydrostatic_vector[3]; + copy_v3_v3(hydrostatic_vector, gravity); + + /* When the fluid is inside the object, factor in the acceleration of + * the object into the pressure field, as gravity is indistinguishable + * from acceleration from the inside. */ + if (fluid_density > 0) { + sub_v3_v3(hydrostatic_vector, cloth->average_acceleration); + + /* Preserve the total mass by scaling density to match the change in volume. */ + fluid_density *= volume_factor; + } + + mul_v3_fl(hydrostatic_vector, fluid_density); + + /* Compute an array of per-vertex hydrostatic pressure, and subtract the average. */ + hydrostatic_pressure = (float *)MEM_mallocN(sizeof(float) * mvert_num, + "hydrostatic pressure gradient"); + + cloth_calc_pressure_gradient(clmd, hydrostatic_vector, hydrostatic_pressure); + + pressure_difference -= cloth_calc_average_pressure(clmd, hydrostatic_pressure); + } + + /* Apply pressure. */ + if (hydrostatic_pressure || fabs(pressure_difference) > 1E-6f) { + float weights[3] = {1.0f, 1.0f, 1.0f}; + + for (i = 0; i < cloth->primitive_num; i++) { + const MVertTri *vt = &tri[i]; + + if (cloth_get_pressure_weights(clmd, vt, weights)) { + BPH_mass_spring_force_pressure(data, + vt->tri[0], + vt->tri[1], + vt->tri[2], + pressure_difference, + hydrostatic_pressure, + weights); } } } + + if (hydrostatic_pressure) { + MEM_freeN(hydrostatic_pressure); + } } /* handle external forces like wind */ @@ -1032,6 +1090,30 @@ static void cloth_calc_volume_force(ClothModifierData *clmd) } #endif +static void cloth_calc_average_acceleration(ClothModifierData *clmd, float dt) +{ + Cloth *cloth = clmd->clothObject; + Implicit_Data *data = cloth->implicit; + int i, mvert_num = cloth->mvert_num; + float total[3] = {0.0f, 0.0f, 0.0f}; + + for (i = 0; i < mvert_num; i++) { + float v[3], nv[3]; + + BPH_mass_spring_get_velocity(data, i, v); + BPH_mass_spring_get_new_velocity(data, i, nv); + + sub_v3_v3(nv, v); + add_v3_v3(total, nv); + } + + mul_v3_fl(total, 1.0f / dt / mvert_num); + + /* Smooth the data using a running average to prevent instability. + * This is effectively an abstraction of the wave propagation speed in fluid. */ + interp_v3_v3v3(cloth->average_acceleration, total, cloth->average_acceleration, powf(0.25f, dt)); +} + static void cloth_solve_collisions( Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt) { @@ -1136,6 +1218,10 @@ int BPH_cloth_solve( float dt = clmd->sim_parms->dt * clmd->sim_parms->timescale; Implicit_Data *id = cloth->implicit; + /* Hydrostatic pressure gradient of the fluid inside the object is affected by acceleration. */ + bool use_acceleration = (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE) && + (clmd->sim_parms->fluid_density > 0); + BKE_sim_debug_data_clear_category("collision"); if (!clmd->solver_result) { @@ -1158,6 +1244,10 @@ int BPH_cloth_solve( } } + if (!use_acceleration) { + zero_v3(cloth->average_acceleration); + } + while (step < tf) { ImplicitSolverResult result; @@ -1181,6 +1271,10 @@ int BPH_cloth_solve( cloth_continuum_step(clmd, dt); } + if (use_acceleration) { + cloth_calc_average_acceleration(clmd, dt); + } + BPH_mass_spring_solve_positions(id, dt); BPH_mass_spring_apply_result(id); diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h index 490e727b5f2..69b50f7fa48 100644 --- a/source/blender/physics/intern/implicit.h +++ b/source/blender/physics/intern/implicit.h @@ -79,6 +79,7 @@ void BPH_mass_spring_get_motion_state(struct Implicit_Data *data, float x[3], float v[3]); void BPH_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3]); +void BPH_mass_spring_get_velocity(struct Implicit_Data *data, int index, float v[3]); /* access to modified motion state during solver step */ void BPH_mass_spring_get_new_position(struct Implicit_Data *data, int index, float x[3]); @@ -183,13 +184,15 @@ bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, float damping); float BPH_tri_tetra_volume_signed_6x(struct Implicit_Data *data, int v1, int v2, int v3); +float BPH_tri_area(struct Implicit_Data *data, int v1, int v2, int v3); void BPH_mass_spring_force_pressure(struct Implicit_Data *data, int v1, int v2, int v3, - float pressure_difference, - float weights[3]); + float common_pressure, + const float *vertex_pressure, + const float weights[3]); /* ======== Hair Volumetric Forces ======== */ diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c index b1afaa52ef2..063c224f158 100644 --- a/source/blender/physics/intern/implicit_blender.c +++ b/source/blender/physics/intern/implicit_blender.c @@ -1246,6 +1246,11 @@ void BPH_mass_spring_get_position(struct Implicit_Data *data, int index, float x root_to_world_v3(data, index, x, data->X[index]); } +void BPH_mass_spring_get_velocity(struct Implicit_Data *data, int index, float v[3]) +{ + root_to_world_v3(data, index, v, data->V[index]); +} + void BPH_mass_spring_get_new_position(struct Implicit_Data *data, int index, float x[3]) { root_to_world_v3(data, index, x, data->Xnew[index]); @@ -1488,21 +1493,54 @@ float BPH_tri_tetra_volume_signed_6x(Implicit_Data *data, int v1, int v2, int v3 return volume_tri_tetrahedron_signed_v3_6x(data->X[v1], data->X[v2], data->X[v3]); } -void BPH_mass_spring_force_pressure( - Implicit_Data *data, int v1, int v2, int v3, float pressure_difference, float weights[3]) +float BPH_tri_area(struct Implicit_Data *data, int v1, int v2, int v3) +{ + float nor[3]; + + return calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]); +} + +void BPH_mass_spring_force_pressure(Implicit_Data *data, + int v1, + int v2, + int v3, + float common_pressure, + const float *vertex_pressure, + const float weights[3]) { float nor[3], area; - float factor; + float factor, base_force; + float force[3]; /* calculate face normal and area */ area = calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]); /* The force is calculated and split up evenly for each of the three face verts */ - factor = pressure_difference * area / 3.0f; + factor = area / 3.0f; + base_force = common_pressure * factor; + + /* Compute per-vertex force values from local pressures. + * From integrating the pressure over the triangle and deriving + * equivalent vertex forces, it follows that: + * + * force[idx] = (sum(pressure) + pressure[idx]) * area / 12 + * + * Effectively, 1/4 of the pressure acts just on its vertex, + * while 3/4 is split evenly over all three. + */ + if (vertex_pressure) { + copy_v3_fl3(force, vertex_pressure[v1], vertex_pressure[v2], vertex_pressure[v3]); + mul_v3_fl(force, factor / 4.0f); + + base_force += force[0] + force[1] + force[2]; + } + else { + zero_v3(force); + } /* add pressure to each of the face verts */ - madd_v3_v3fl(data->F[v1], nor, factor * weights[0]); - madd_v3_v3fl(data->F[v2], nor, factor * weights[1]); - madd_v3_v3fl(data->F[v3], nor, factor * weights[2]); + madd_v3_v3fl(data->F[v1], nor, (base_force + force[0]) * weights[0]); + madd_v3_v3fl(data->F[v2], nor, (base_force + force[1]) * weights[1]); + madd_v3_v3fl(data->F[v3], nor, (base_force + force[2]) * weights[2]); } static void edge_wind_vertex(const float dir[3], diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index edade21fd27..8daad33b477 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -274,7 +274,7 @@ static void pointdensity_cache_psys( BLI_bvhtree_balance(pd->point_tree); if (psys->lattice_deform_data) { - end_latt_deform(psys->lattice_deform_data); + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } } @@ -823,7 +823,7 @@ static void particle_system_minmax(Depsgraph *depsgraph, } if (psys->lattice_deform_data) { - end_latt_deform(psys->lattice_deform_data); + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } } diff --git a/tests/gtests/blenlib/BLI_map_test.cc b/tests/gtests/blenlib/BLI_map_test.cc index 623055d5032..96e9879abe7 100644 --- a/tests/gtests/blenlib/BLI_map_test.cc +++ b/tests/gtests/blenlib/BLI_map_test.cc @@ -449,6 +449,15 @@ TEST(map, PointerKeys) EXPECT_TRUE(map.is_empty()); } +TEST(map, ConstKeysAndValues) +{ + Map<const std::string, const std::string> map; + map.reserve(10); + map.add("45", "643"); + EXPECT_TRUE(map.contains("45")); + EXPECT_FALSE(map.contains("54")); +} + /** * Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot. */ diff --git a/tests/gtests/blenlib/BLI_set_test.cc b/tests/gtests/blenlib/BLI_set_test.cc index 8e77a446a97..2387242c94b 100644 --- a/tests/gtests/blenlib/BLI_set_test.cc +++ b/tests/gtests/blenlib/BLI_set_test.cc @@ -9,7 +9,7 @@ #include "BLI_vector.hh" #include "testing/testing.h" -using namespace blender; +namespace blender { TEST(set, DefaultConstructor) { @@ -290,7 +290,7 @@ bool operator==(const Type2 &a, const Type1 &b) return a.value == b.value; } -template<> struct blender::DefaultHash<Type1> { +template<> struct DefaultHash<Type1> { uint32_t operator()(const Type1 &value) const { return value.value; @@ -511,3 +511,5 @@ TEST(set, Benchmark) */ #endif /* Benchmark */ + +} // namespace blender diff --git a/tests/gtests/functions/FN_cpp_type_test.cc b/tests/gtests/functions/FN_cpp_type_test.cc index ca8583bdc92..811e1a5d783 100644 --- a/tests/gtests/functions/FN_cpp_type_test.cc +++ b/tests/gtests/functions/FN_cpp_type_test.cc @@ -19,6 +19,9 @@ #include "FN_cpp_type.hh" +namespace blender { +namespace FN { + static const int default_constructed_value = 1; static const int copy_constructed_value = 2; static const int move_constructed_value = 3; @@ -297,3 +300,6 @@ TEST(cpp_type, FillUninitialized) EXPECT_EQ(buffer2[8], copy_constructed_value); EXPECT_EQ(buffer2[9], 0); } + +} // namespace FN +} // namespace blender |