Merge branch 'blender-v3.6-release' into goo-engine-v3.6-release
This commit is contained in:
+1
-1
@@ -506,7 +506,7 @@ if(NOT APPLE)
|
||||
mark_as_advanced(WITH_CYCLES_DEVICE_CUDA)
|
||||
|
||||
option(WITH_CYCLES_CUDA_BINARIES "Build Cycles NVIDIA CUDA binaries" OFF)
|
||||
set(CYCLES_CUDA_BINARIES_ARCH sm_30 sm_35 sm_37 sm_50 sm_52 sm_60 sm_61 sm_70 sm_75 sm_86 sm_89 compute_75 CACHE STRING "CUDA architectures to build binaries for")
|
||||
set(CYCLES_CUDA_BINARIES_ARCH sm_30 sm_35 sm_37 sm_50 sm_52 sm_60 sm_61 sm_70 sm_75 sm_86 sm_89 compute_89 CACHE STRING "CUDA architectures to build binaries for")
|
||||
option(WITH_CYCLES_CUDA_BUILD_SERIAL "Build cubins one after another (useful on machines with limited RAM)" OFF)
|
||||
option(WITH_CUDA_DYNLOAD "Dynamically load CUDA libraries at runtime (for developers, makes cuda-gdb work)" ON)
|
||||
|
||||
|
||||
@@ -106,7 +106,9 @@ ExternalProject_Add(external_openimageio
|
||||
CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR}
|
||||
PREFIX ${BUILD_DIR}/openimageio
|
||||
PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/openimageio.diff &&
|
||||
${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_3832.diff
|
||||
${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_3832.diff &&
|
||||
${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_deadlock.diff &&
|
||||
${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_psd_8da473e254.diff
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openimageio ${DEFAULT_CMAKE_FLAGS} ${OPENIMAGEIO_EXTRA_ARGS}
|
||||
INSTALL_DIR ${LIBDIR}/openimageio
|
||||
)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
diff -Naur orig/src/idiff/idiff.cpp external_openimageio/src/idiff/idiff.cpp
|
||||
--- orig/src/idiff/idiff.cpp 2023-06-07 07:47:42 -0600
|
||||
+++ external_openimageio/src/idiff/idiff.cpp 2023-06-07 09:46:47 -0600
|
||||
@@ -399,5 +399,6 @@
|
||||
|
||||
imagecache->invalidate_all(true);
|
||||
ImageCache::destroy(imagecache);
|
||||
+ default_thread_pool()->resize(0);
|
||||
return ret;
|
||||
}
|
||||
diff -Naur orig/src/libutil/thread.cpp external_openimageio/src/libutil/thread.cpp
|
||||
--- orig/src/libutil/thread.cpp 2023-06-07 07:47:42 -0600
|
||||
+++ external_openimageio/src/libutil/thread.cpp 2023-06-07 09:45:39 -0600
|
||||
@@ -151,9 +151,10 @@
|
||||
this->set_thread(i);
|
||||
}
|
||||
} else { // the number of threads is decreased
|
||||
+ std::vector<std::unique_ptr<std::thread>> terminating_threads;
|
||||
for (int i = oldNThreads - 1; i >= nThreads; --i) {
|
||||
*this->flags[i] = true; // this thread will finish
|
||||
- this->terminating_threads.push_back(
|
||||
+ terminating_threads.push_back(
|
||||
std::move(this->threads[i]));
|
||||
this->threads.erase(this->threads.begin() + i);
|
||||
}
|
||||
@@ -162,6 +163,11 @@
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
this->cv.notify_all();
|
||||
}
|
||||
+ // wait for the terminated threads to finish
|
||||
+ for (auto& thread : terminating_threads) {
|
||||
+ if (thread->joinable())
|
||||
+ thread->join();
|
||||
+ }
|
||||
this->threads.resize(
|
||||
nThreads); // safe to delete because the threads are detached
|
||||
this->flags.resize(
|
||||
@@ -238,16 +244,10 @@
|
||||
if (thread->joinable())
|
||||
thread->join();
|
||||
}
|
||||
- // wait for the terminated threads to finish
|
||||
- for (auto& thread : this->terminating_threads) {
|
||||
- if (thread->joinable())
|
||||
- thread->join();
|
||||
- }
|
||||
// if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads
|
||||
// therefore delete them here
|
||||
this->clear_queue();
|
||||
this->threads.clear();
|
||||
- this->terminating_threads.clear();
|
||||
this->flags.clear();
|
||||
}
|
||||
|
||||
@@ -349,7 +349,6 @@
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<std::thread>> threads;
|
||||
- std::vector<std::unique_ptr<std::thread>> terminating_threads;
|
||||
std::vector<std::shared_ptr<std::atomic<bool>>> flags;
|
||||
mutable pvt::ThreadsafeQueue<std::function<void(int id)>*> q;
|
||||
std::atomic<bool> isDone;
|
||||
@@ -0,0 +1,34 @@
|
||||
diff --git a/src/psd.imageio/psdinput.cpp b/src/psd.imageio/psdinput.cpp
|
||||
index 9dc240281..05b008e0a 100644
|
||||
--- a/src/psd.imageio/psdinput.cpp
|
||||
+++ b/src/psd.imageio/psdinput.cpp
|
||||
@@ -1344,9 +1344,27 @@ PSDInput::load_resource_thumbnail(uint32_t length, bool isBGR)
|
||||
if (!ioread(&jpeg_data[0], jpeg_length))
|
||||
return false;
|
||||
|
||||
+ // Create an IOMemReader that references the thumbnail JPEG blob and read
|
||||
+ // it with an ImageInput, into the memory owned by an ImageBuf.
|
||||
Filesystem::IOMemReader thumbblob(jpeg_data.data(), jpeg_length);
|
||||
- m_thumbnail = ImageBuf("thumbnail.jpg", 0, 0, nullptr, nullptr, &thumbblob);
|
||||
- m_thumbnail.read(0, 0, true);
|
||||
+ m_thumbnail.clear();
|
||||
+ auto imgin = ImageInput::open("thumbnail.jpg", nullptr, &thumbblob);
|
||||
+ if (imgin) {
|
||||
+ ImageSpec spec = imgin->spec(0);
|
||||
+ m_thumbnail.reset(spec, InitializePixels::No);
|
||||
+ ok = imgin->read_image(0, 0, 0, m_thumbnail.spec().nchannels,
|
||||
+ m_thumbnail.spec().format,
|
||||
+ m_thumbnail.localpixels());
|
||||
+ imgin.reset();
|
||||
+ } else {
|
||||
+ errorfmt("Failed to open thumbnail");
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (!ok) {
|
||||
+ errorfmt("Failed to read thumbnail: {}", m_thumbnail.geterror());
|
||||
+ m_thumbnail.clear();
|
||||
+ return false;
|
||||
+ }
|
||||
|
||||
// Set these attributes for the merged composite only (subimage 0)
|
||||
composite_attribute("thumbnail_width", (int)m_thumbnail.spec().width);
|
||||
Vendored
+2
@@ -2,6 +2,8 @@
|
||||
#include "config_mac.h"
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include "config_freebsd.h"
|
||||
#elif defined(__NetBSD__)
|
||||
#include "config_netbsd.h"
|
||||
#elif defined(__OpenBSD__)
|
||||
#include "config_openbsd.h"
|
||||
#elif defined(__MINGW32__)
|
||||
|
||||
Vendored
+192
@@ -0,0 +1,192 @@
|
||||
/* define if glog doesn't use RTTI */
|
||||
/* #undef DISABLE_RTTI */
|
||||
|
||||
/* Namespace for Google classes */
|
||||
#define GOOGLE_NAMESPACE google
|
||||
|
||||
/* Define if you have the `dladdr' function */
|
||||
/* #undef HAVE_DLADDR */
|
||||
|
||||
/* Define if you have the `snprintf' function */
|
||||
#define HAVE_SNPRINTF
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <execinfo.h> header file. */
|
||||
/* #undef HAVE_EXECINFO_H */
|
||||
|
||||
/* Define if you have the `fcntl' function */
|
||||
#define HAVE_FCNTL
|
||||
|
||||
/* Define to 1 if you have the <glob.h> header file. */
|
||||
#define HAVE_GLOB_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||
#define HAVE_LIBPTHREAD
|
||||
|
||||
/* Define to 1 if you have the <libunwind.h> header file. */
|
||||
/* #undef HAVE_LIBUNWIND_H */
|
||||
|
||||
/* define if you have google gflags library */
|
||||
#define HAVE_LIB_GFLAGS
|
||||
|
||||
/* define if you have google gmock library */
|
||||
/* #undef HAVE_LIB_GMOCK */
|
||||
|
||||
/* define if you have google gtest library */
|
||||
/* #undef HAVE_LIB_GTEST */
|
||||
|
||||
/* define if you have libunwind */
|
||||
/* #undef HAVE_LIB_UNWIND */
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H
|
||||
|
||||
/* define to disable multithreading support. */
|
||||
/* #undef NO_THREADS */
|
||||
|
||||
/* define if the compiler implements namespaces */
|
||||
#define HAVE_NAMESPACES
|
||||
|
||||
/* Define if you have the 'pread' function */
|
||||
#define HAVE_PREAD
|
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#define HAVE_PTHREAD
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#define HAVE_PWD_H
|
||||
|
||||
/* Define if you have the 'pwrite' function */
|
||||
#define HAVE_PWRITE
|
||||
|
||||
/* define if the compiler implements pthread_rwlock_* */
|
||||
#define HAVE_RWLOCK 1
|
||||
|
||||
/* Define if you have the 'sigaction' function */
|
||||
#define HAVE_SIGACTION
|
||||
|
||||
/* Define if you have the `sigaltstack' function */
|
||||
#define HAVE_SIGALTSTACK 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <syscall.h> header file. */
|
||||
/* #undef HAVE_SYSCALL_H */
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#define HAVE_SYSLOG_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/syscall.h> header file. */
|
||||
#define HAVE_SYS_SYSCALL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#define HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/ucontext.h> header file. */
|
||||
#define HAVE_SYS_UCONTEXT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/utsname.h> header file. */
|
||||
#define HAVE_SYS_UTSNAME_H
|
||||
|
||||
/* Define to 1 if you have the <ucontext.h> header file. */
|
||||
#define HAVE_UCONTEXT_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the <unwind.h> header file. */
|
||||
#define HAVE_UNWIND_H 1
|
||||
|
||||
/* define if the compiler supports using expression for operator */
|
||||
#define HAVE_USING_OPERATOR
|
||||
|
||||
/* define if your compiler has __attribute__ */
|
||||
#define HAVE___ATTRIBUTE__
|
||||
|
||||
/* define if your compiler has __builtin_expect */
|
||||
#define HAVE___BUILTIN_EXPECT 1
|
||||
|
||||
/* define if your compiler has __sync_val_compare_and_swap */
|
||||
#define HAVE___SYNC_VAL_COMPARE_AND_SWAP
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
/* #undef LT_OBJDIR */
|
||||
|
||||
/* Name of package */
|
||||
/* #undef PACKAGE */
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
/* #undef PACKAGE_BUGREPORT */
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
/* #undef PACKAGE_NAME */
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
/* #undef PACKAGE_STRING */
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
/* #undef PACKAGE_TARNAME */
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
/* #undef PACKAGE_URL */
|
||||
|
||||
/* Define to the version of this package. */
|
||||
/* #undef PACKAGE_VERSION */
|
||||
|
||||
/* How to access the PC from a struct ucontext */
|
||||
/* #undef PC_FROM_UCONTEXT */
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
/* #undef PTHREAD_CREATE_JOINABLE */
|
||||
|
||||
/* The size of `void *', as computed by sizeof. */
|
||||
#define SIZEOF_VOID_P 8
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* the namespace where STL code like vector<> is defined */
|
||||
#define STL_NAMESPACE std
|
||||
|
||||
/* location of source code */
|
||||
#define TEST_SRC_DIR "."
|
||||
|
||||
/* Version number of package */
|
||||
/* #undef VERSION */
|
||||
|
||||
/* Stops putting the code inside the Google namespace */
|
||||
#define _END_GOOGLE_NAMESPACE_ }
|
||||
|
||||
/* Puts following code inside the Google namespace */
|
||||
#define _START_GOOGLE_NAMESPACE_ namespace google {
|
||||
|
||||
#define GOOGLE_GLOG_DLL_DECL
|
||||
|
||||
/* isn't getting defined by configure script when clang compilers are used
|
||||
and cuases compilation errors in stactrace/unwind modules */
|
||||
#ifdef __clang__
|
||||
# define NO_FRAME_POINTER
|
||||
#endif
|
||||
@@ -146,7 +146,11 @@ void BlenderSync::sync_light(BL::Object &b_parent,
|
||||
light->set_is_shadow_catcher(b_ob_info.real_object.is_shadow_catcher());
|
||||
|
||||
/* lightgroup */
|
||||
light->set_lightgroup(ustring(b_ob_info.real_object.lightgroup()));
|
||||
string lightgroup = b_ob_info.real_object.lightgroup();
|
||||
if (lightgroup.empty()) {
|
||||
lightgroup = b_parent.lightgroup();
|
||||
}
|
||||
light->set_lightgroup(ustring(lightgroup));
|
||||
|
||||
/* tag */
|
||||
light->tag_update(scene);
|
||||
|
||||
@@ -349,7 +349,11 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
}
|
||||
|
||||
/* lightgroup */
|
||||
object->set_lightgroup(ustring(b_ob.lightgroup()));
|
||||
string lightgroup = b_ob.lightgroup();
|
||||
if (lightgroup.empty()) {
|
||||
lightgroup = b_parent.lightgroup();
|
||||
}
|
||||
object->set_lightgroup(ustring(lightgroup));
|
||||
|
||||
object->tag_update(scene);
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ endif()
|
||||
# oneAPI
|
||||
###########################################################################
|
||||
|
||||
if(WITH_CYCLES_DEVICE_ONEAPI)
|
||||
if(WITH_CYCLES_DEVICE_ONEAPI OR EMBREE_SYCL_SUPPORT)
|
||||
find_package(SYCL)
|
||||
find_package(LevelZero)
|
||||
set_and_warn_library_found("oneAPI" SYCL_FOUND WITH_CYCLES_DEVICE_ONEAPI)
|
||||
@@ -102,23 +102,23 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
|
||||
|
||||
if(SYCL_FOUND AND SYCL_VERSION VERSION_GREATER_EQUAL 6.0 AND LEVEL_ZERO_FOUND)
|
||||
message(STATUS "Found Level Zero: ${LEVEL_ZERO_LIBRARY}")
|
||||
|
||||
if(WITH_CYCLES_ONEAPI_BINARIES)
|
||||
if(NOT OCLOC_INSTALL_DIR)
|
||||
get_filename_component(_sycl_compiler_root ${SYCL_COMPILER} DIRECTORY)
|
||||
get_filename_component(OCLOC_INSTALL_DIR "${_sycl_compiler_root}/../lib/ocloc" ABSOLUTE)
|
||||
unset(_sycl_compiler_root)
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS ${OCLOC_INSTALL_DIR})
|
||||
set(OCLOC_FOUND OFF)
|
||||
message(STATUS "oneAPI ocloc not found in ${OCLOC_INSTALL_DIR}."
|
||||
" A different ocloc directory can be set using OCLOC_INSTALL_DIR cmake variable.")
|
||||
set_and_warn_library_found("ocloc" OCLOC_FOUND WITH_CYCLES_ONEAPI_BINARIES)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "SYCL 6.0+ or Level Zero not found, disabling WITH_CYCLES_DEVICE_ONEAPI")
|
||||
set(WITH_CYCLES_DEVICE_ONEAPI OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_DEVICE_ONEAPI AND WITH_CYCLES_ONEAPI_BINARIES)
|
||||
if(NOT OCLOC_INSTALL_DIR)
|
||||
get_filename_component(_sycl_compiler_root ${SYCL_COMPILER} DIRECTORY)
|
||||
get_filename_component(OCLOC_INSTALL_DIR "${_sycl_compiler_root}/../lib/ocloc" ABSOLUTE)
|
||||
unset(_sycl_compiler_root)
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS ${OCLOC_INSTALL_DIR})
|
||||
set(OCLOC_FOUND OFF)
|
||||
message(STATUS "oneAPI ocloc not found in ${OCLOC_INSTALL_DIR}."
|
||||
" A different ocloc directory can be set using OCLOC_INSTALL_DIR cmake variable.")
|
||||
set_and_warn_library_found("ocloc" OCLOC_FOUND WITH_CYCLES_ONEAPI_BINARIES)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -359,6 +359,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
|
||||
|
||||
info.has_nanovdb = true;
|
||||
info.has_light_tree = true;
|
||||
info.has_mnee = true;
|
||||
info.has_osl = true;
|
||||
info.has_guiding = true;
|
||||
info.has_profiling = true;
|
||||
@@ -408,6 +409,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
|
||||
/* Accumulate device info. */
|
||||
info.has_nanovdb &= device.has_nanovdb;
|
||||
info.has_light_tree &= device.has_light_tree;
|
||||
info.has_mnee &= device.has_mnee;
|
||||
info.has_osl &= device.has_osl;
|
||||
info.has_guiding &= device.has_guiding;
|
||||
info.has_profiling &= device.has_profiling;
|
||||
|
||||
@@ -75,6 +75,7 @@ class DeviceInfo {
|
||||
bool display_device; /* GPU is used as a display device. */
|
||||
bool has_nanovdb; /* Support NanoVDB volumes. */
|
||||
bool has_light_tree; /* Support light tree. */
|
||||
bool has_mnee; /* Support MNEE. */
|
||||
bool has_osl; /* Support Open Shading Language. */
|
||||
bool has_guiding; /* Support path guiding. */
|
||||
bool has_profiling; /* Supports runtime collection of profiling info. */
|
||||
@@ -97,6 +98,7 @@ class DeviceInfo {
|
||||
display_device = false;
|
||||
has_nanovdb = false;
|
||||
has_light_tree = true;
|
||||
has_mnee = true;
|
||||
has_osl = false;
|
||||
has_guiding = false;
|
||||
has_profiling = false;
|
||||
|
||||
@@ -155,6 +155,7 @@ void device_hip_info(vector<DeviceInfo> &devices)
|
||||
|
||||
info.has_nanovdb = true;
|
||||
info.has_light_tree = true;
|
||||
info.has_mnee = true;
|
||||
info.denoisers = 0;
|
||||
|
||||
info.has_gpu_queue = true;
|
||||
|
||||
@@ -59,6 +59,7 @@ void device_metal_info(vector<DeviceInfo> &devices)
|
||||
|
||||
info.has_nanovdb = vendor == METAL_GPU_APPLE;
|
||||
info.has_light_tree = vendor != METAL_GPU_AMD;
|
||||
info.has_mnee = vendor != METAL_GPU_AMD;
|
||||
|
||||
info.use_hardware_raytracing = vendor != METAL_GPU_INTEL;
|
||||
if (info.use_hardware_raytracing) {
|
||||
|
||||
@@ -367,7 +367,12 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: {
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
*roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y);
|
||||
*eta = CLOSURE_IS_REFRACTIVE(bsdf->type) ? 1.0f / bsdf->ior : bsdf->ior;
|
||||
if (CLOSURE_IS_REFRACTION(bsdf->type) || CLOSURE_IS_GLASS(bsdf->type)) {
|
||||
*eta = 1.0f / bsdf->ior;
|
||||
}
|
||||
else {
|
||||
*eta = bsdf->ior;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
|
||||
@@ -672,7 +677,9 @@ ccl_device void bsdf_blur(KernelGlobals kg, ccl_private ShaderClosure *sc, float
|
||||
}
|
||||
|
||||
ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc)
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const bool reflection,
|
||||
const bool transmission)
|
||||
{
|
||||
Spectrum albedo = sc->weight;
|
||||
/* Some closures include additional components such as Fresnel terms that cause their albedo to
|
||||
@@ -686,12 +693,16 @@ ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
|
||||
* extra overhead though. */
|
||||
#if defined(__SVM__) || defined(__OSL__)
|
||||
if (CLOSURE_IS_BSDF_MICROFACET(sc->type)) {
|
||||
albedo *= bsdf_microfacet_estimate_fresnel(sd, (ccl_private const MicrofacetBsdf *)sc);
|
||||
albedo *= bsdf_microfacet_estimate_fresnel(
|
||||
sd, (ccl_private const MicrofacetBsdf *)sc, reflection, transmission);
|
||||
}
|
||||
else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) {
|
||||
kernel_assert(reflection);
|
||||
albedo *= ((ccl_private const PrincipledSheenBsdf *)sc)->avg_value;
|
||||
}
|
||||
else if (sc->type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) {
|
||||
/* TODO(lukas): Principled Hair could also be split into a glossy and a transmission component,
|
||||
* similar to Glass BSDFs. */
|
||||
albedo *= bsdf_principled_hair_albedo(sd, sc);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -221,12 +221,20 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB
|
||||
const bool refraction)
|
||||
{
|
||||
if (bsdf->fresnel_type == MicrofacetFresnel::PRINCIPLED_V1) {
|
||||
/* For Principled v1 Glass, cspec0 only provides the specular tint, the main Fresnel term
|
||||
* is implicit in the phase function of the multi-scattering code.
|
||||
* Therefore, for Glass, include it here on top of the Principled-specific tints. */
|
||||
float F = 1.0f;
|
||||
if (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) {
|
||||
F = fresnel_dielectric_cos(dot(wi, H), bsdf->ior);
|
||||
}
|
||||
|
||||
ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel;
|
||||
if (refraction) {
|
||||
return fresnel->color;
|
||||
return (1.0f - F) * fresnel->color;
|
||||
}
|
||||
else {
|
||||
return interpolate_fresnel_color(wi, H, bsdf->ior, fresnel->cspec0);
|
||||
return F * interpolate_fresnel_color(wi, H, bsdf->ior, fresnel->cspec0);
|
||||
}
|
||||
}
|
||||
else if (bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC) {
|
||||
@@ -270,8 +278,15 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB
|
||||
else if (bsdf->fresnel_type == MicrofacetFresnel::CONSTANT) {
|
||||
/* CONSTANT is only used my MultiGGX, which doesn't call this function.
|
||||
* Therefore, this case only happens when determining the albedo of a MultiGGX closure.
|
||||
* In that case, return 1.0 since the constant color is already baked into the weight. */
|
||||
return one_spectrum();
|
||||
* In that case, the constant color is already baked into the weight.
|
||||
* So, just return the main dielectric Fresnel term for Glass and 1.0 for Glossy. */
|
||||
if (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) {
|
||||
const float F = fresnel_dielectric_cos(dot(wi, H), bsdf->ior);
|
||||
return make_spectrum(refraction ? (1.0f - F) : F);
|
||||
}
|
||||
else {
|
||||
return refraction ? zero_spectrum() : one_spectrum();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return one_spectrum();
|
||||
@@ -285,17 +300,20 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB
|
||||
* This is used to adjust the sample weight, as well as for the Diff/Gloss/Trans Color pass
|
||||
* and the Denoising Albedo pass. */
|
||||
ccl_device Spectrum bsdf_microfacet_estimate_fresnel(ccl_private const ShaderData *sd,
|
||||
ccl_private const MicrofacetBsdf *bsdf)
|
||||
ccl_private const MicrofacetBsdf *bsdf,
|
||||
const bool reflection,
|
||||
const bool transmission)
|
||||
{
|
||||
const bool is_glass = CLOSURE_IS_GLASS(bsdf->type);
|
||||
const bool is_refractive = CLOSURE_IS_REFRACTIVE(bsdf->type);
|
||||
const bool m_refraction = CLOSURE_IS_REFRACTION(bsdf->type);
|
||||
const bool m_glass = CLOSURE_IS_GLASS(bsdf->type);
|
||||
const bool m_reflection = !(m_refraction || m_glass);
|
||||
|
||||
Spectrum albedo = zero_spectrum();
|
||||
if (!is_refractive || is_glass) {
|
||||
if (reflection && (m_reflection || m_glass)) {
|
||||
/* BSDF has a reflective lobe. */
|
||||
albedo += microfacet_fresnel(bsdf, sd->wi, bsdf->N, false);
|
||||
}
|
||||
if (is_refractive) {
|
||||
if (transmission && (m_refraction || m_glass)) {
|
||||
/* BSDF has a refractive lobe (unless there's TIR). */
|
||||
albedo += microfacet_fresnel(bsdf, sd->wi, bsdf->N, true);
|
||||
}
|
||||
@@ -402,8 +420,12 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
|
||||
}
|
||||
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
const bool m_refractive = CLOSURE_IS_REFRACTIVE(bsdf->type);
|
||||
/* Refraction: Only consider BTDF
|
||||
* Glass: Consider both BRDF and BTDF, mix based on Fresnel
|
||||
* Reflection: Only consider BRDF */
|
||||
const bool m_refraction = CLOSURE_IS_REFRACTION(bsdf->type);
|
||||
const bool m_glass = CLOSURE_IS_GLASS(bsdf->type);
|
||||
const bool m_reflection = !(m_refraction || m_glass);
|
||||
|
||||
const float3 N = bsdf->N;
|
||||
const float cos_NI = dot(N, wi);
|
||||
@@ -413,7 +435,7 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
|
||||
const float alpha_x = bsdf->alpha_x;
|
||||
const float alpha_y = bsdf->alpha_y;
|
||||
|
||||
const bool is_refraction = (cos_NO < 0.0f);
|
||||
const bool is_transmission = (cos_NO < 0.0f);
|
||||
|
||||
/* Check whether the pair of directions is valid for evaluation:
|
||||
* - Incoming direction has to be in the upper hemisphere (Cycles convention)
|
||||
@@ -422,15 +444,15 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
|
||||
* - Purely reflective closures can't have refraction.
|
||||
* - Purely refractive closures can't have reflection.
|
||||
*/
|
||||
if ((cos_NI <= 0) || (alpha_x * alpha_y <= 5e-7f) || ((cos_NgO < 0.0f) != is_refraction) ||
|
||||
(is_refraction && !m_refractive) || (!is_refraction && m_refractive && !m_glass))
|
||||
if ((cos_NI <= 0) || (alpha_x * alpha_y <= 5e-7f) || ((cos_NgO < 0.0f) != is_transmission) ||
|
||||
(is_transmission && m_reflection) || (!is_transmission && m_refraction))
|
||||
{
|
||||
*pdf = 0.0f;
|
||||
return zero_spectrum();
|
||||
}
|
||||
|
||||
/* Compute half vector. */
|
||||
float3 H = is_refraction ? -(bsdf->ior * wo + wi) : (wi + wo);
|
||||
float3 H = is_transmission ? -(bsdf->ior * wo + wi) : (wi + wo);
|
||||
const float inv_len_H = 1.0f / len(H);
|
||||
H *= inv_len_H;
|
||||
|
||||
@@ -438,7 +460,7 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
|
||||
float D, lambdaI, lambdaO;
|
||||
|
||||
/* TODO: add support for anisotropic transmission. */
|
||||
if (alpha_x == alpha_y || is_refraction) { /* Isotropic. */
|
||||
if (alpha_x == alpha_y || is_transmission) { /* Isotropic. */
|
||||
float alpha2 = alpha_x * alpha_y;
|
||||
|
||||
if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) {
|
||||
@@ -470,19 +492,19 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
|
||||
}
|
||||
|
||||
float common = D / cos_NI *
|
||||
(is_refraction ? sqr(bsdf->ior * inv_len_H) * fabsf(dot(H, wi) * dot(H, wo)) :
|
||||
0.25f);
|
||||
(is_transmission ? sqr(bsdf->ior * inv_len_H) * fabsf(dot(H, wi) * dot(H, wo)) :
|
||||
0.25f);
|
||||
|
||||
float lobe_pdf = 1.0f;
|
||||
if (m_glass) {
|
||||
float fresnel = fresnel_dielectric_cos(dot(H, wi), bsdf->ior);
|
||||
float reflect_pdf = (fresnel == 1.0f) ? 1.0f : clamp(fresnel, 0.125f, 0.875f);
|
||||
lobe_pdf = is_refraction ? (1.0f - reflect_pdf) : reflect_pdf;
|
||||
lobe_pdf = is_transmission ? (1.0f - reflect_pdf) : reflect_pdf;
|
||||
}
|
||||
|
||||
*pdf = common * lobe_pdf / (1.0f + lambdaI);
|
||||
|
||||
const Spectrum F = microfacet_fresnel(bsdf, wi, H, is_refraction);
|
||||
const Spectrum F = microfacet_fresnel(bsdf, wi, H, is_transmission);
|
||||
return F * common / (1.0f + lambdaO + lambdaI);
|
||||
}
|
||||
|
||||
@@ -503,7 +525,9 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc,
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
|
||||
const float m_eta = bsdf->ior;
|
||||
const bool m_refractive = CLOSURE_IS_REFRACTIVE(bsdf->type);
|
||||
const bool m_refraction = CLOSURE_IS_REFRACTION(bsdf->type);
|
||||
const bool m_glass = CLOSURE_IS_GLASS(bsdf->type);
|
||||
const bool m_reflection = !(m_refraction || m_glass);
|
||||
const float alpha_x = bsdf->alpha_x;
|
||||
const float alpha_y = bsdf->alpha_y;
|
||||
bool m_singular = (m_type == MicrofacetType::SHARP) || (alpha_x * alpha_y <= 5e-7f);
|
||||
@@ -513,7 +537,7 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc,
|
||||
if (cos_NI <= 0) {
|
||||
*eval = zero_spectrum();
|
||||
*pdf = 0.0f;
|
||||
return (m_refractive ? LABEL_TRANSMIT : LABEL_REFLECT) |
|
||||
return (m_reflection ? LABEL_REFLECT : LABEL_TRANSMIT) |
|
||||
(m_singular ? LABEL_SINGULAR : LABEL_GLOSSY);
|
||||
}
|
||||
|
||||
@@ -552,13 +576,13 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc,
|
||||
bool valid;
|
||||
bool do_refract;
|
||||
float lobe_pdf;
|
||||
if (m_refractive) {
|
||||
if (m_refraction || m_glass) {
|
||||
bool inside;
|
||||
float fresnel = fresnel_dielectric(m_eta, H, wi, wo, &inside);
|
||||
valid = !inside;
|
||||
|
||||
/* For glass closures, we decide between reflection and refraction here. */
|
||||
if (CLOSURE_IS_GLASS(bsdf->type)) {
|
||||
if (m_glass) {
|
||||
if (fresnel == 1.0f) {
|
||||
/* TIR, reflection is the only option. */
|
||||
do_refract = false;
|
||||
@@ -675,7 +699,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_principledv1(
|
||||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
|
||||
}
|
||||
|
||||
ccl_device void bsdf_microfacet_setup_fresnel_conductor(ccl_private MicrofacetBsdf *bsdf,
|
||||
@@ -684,7 +708,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_conductor(ccl_private MicrofacetBs
|
||||
{
|
||||
bsdf->fresnel_type = MicrofacetFresnel::CONDUCTOR;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
|
||||
}
|
||||
|
||||
ccl_device void bsdf_microfacet_setup_fresnel_dielectric_tint(
|
||||
@@ -694,7 +718,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_dielectric_tint(
|
||||
{
|
||||
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC_TINT;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
|
||||
}
|
||||
|
||||
ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick(
|
||||
@@ -704,7 +728,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick(
|
||||
{
|
||||
bsdf->fresnel_type = MicrofacetFresnel::GENERALIZED_SCHLICK;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
|
||||
}
|
||||
|
||||
/* GGX microfacet with Smith shadow-masking from:
|
||||
@@ -739,7 +763,7 @@ ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *b
|
||||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC;
|
||||
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
|
||||
|
||||
return SD_BSDF | SD_BSDF_HAS_EVAL;
|
||||
}
|
||||
|
||||
@@ -407,7 +407,7 @@ ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(ccl_private MicrofacetBsd
|
||||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1;
|
||||
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
|
||||
|
||||
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
|
||||
}
|
||||
@@ -618,7 +618,7 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(ccl_private Microfa
|
||||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1;
|
||||
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
|
||||
|
||||
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ ccl_device_forceinline void film_write_denoising_features_surface(KernelGlobals
|
||||
}
|
||||
}
|
||||
|
||||
Spectrum closure_albedo = bsdf_albedo(sd, sc);
|
||||
Spectrum closure_albedo = bsdf_albedo(sd, sc, true, true);
|
||||
if (bsdf_get_specular_roughness_squared(sc) > sqr(0.075f)) {
|
||||
diffuse_albedo += closure_albedo;
|
||||
sum_nonspecular_weight += sc->sample_weight;
|
||||
|
||||
@@ -20,36 +20,61 @@ CCL_NAMESPACE_BEGIN
|
||||
* them separately. */
|
||||
|
||||
ccl_device_inline void bsdf_eval_init(ccl_private BsdfEval *eval,
|
||||
const ClosureType closure_type,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const float3 wo,
|
||||
Spectrum value)
|
||||
{
|
||||
eval->diffuse = zero_spectrum();
|
||||
eval->glossy = zero_spectrum();
|
||||
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(closure_type)) {
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
|
||||
eval->diffuse = value;
|
||||
}
|
||||
else if (CLOSURE_IS_BSDF_GLOSSY(closure_type)) {
|
||||
else if (CLOSURE_IS_BSDF_GLOSSY(sc->type)) {
|
||||
eval->glossy = value;
|
||||
}
|
||||
else if (CLOSURE_IS_GLASS(sc->type)) {
|
||||
/* Glass can count as glossy or transmission, depending on which side we end up on. */
|
||||
if (dot(sc->N, wo) > 0.0f) {
|
||||
eval->glossy = value;
|
||||
}
|
||||
}
|
||||
|
||||
eval->sum = value;
|
||||
}
|
||||
|
||||
ccl_device_inline void bsdf_eval_init(ccl_private BsdfEval *eval, Spectrum value)
|
||||
{
|
||||
eval->diffuse = zero_spectrum();
|
||||
eval->glossy = zero_spectrum();
|
||||
eval->sum = value;
|
||||
}
|
||||
|
||||
ccl_device_inline void bsdf_eval_accum(ccl_private BsdfEval *eval,
|
||||
const ClosureType closure_type,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const float3 wo,
|
||||
Spectrum value)
|
||||
{
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(closure_type)) {
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
|
||||
eval->diffuse += value;
|
||||
}
|
||||
else if (CLOSURE_IS_BSDF_GLOSSY(closure_type)) {
|
||||
else if (CLOSURE_IS_BSDF_GLOSSY(sc->type)) {
|
||||
eval->glossy += value;
|
||||
}
|
||||
else if (CLOSURE_IS_GLASS(sc->type)) {
|
||||
if (dot(sc->N, wo) > 0.0f) {
|
||||
eval->glossy += value;
|
||||
}
|
||||
}
|
||||
|
||||
eval->sum += value;
|
||||
}
|
||||
|
||||
ccl_device_inline void bsdf_eval_accum(ccl_private BsdfEval *eval, Spectrum value)
|
||||
{
|
||||
eval->sum += value;
|
||||
}
|
||||
|
||||
ccl_device_inline bool bsdf_eval_is_zero(ccl_private BsdfEval *eval)
|
||||
{
|
||||
return is_zero(eval->sum);
|
||||
|
||||
@@ -981,7 +981,7 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg,
|
||||
bool found_refractive_microfacet_bsdf = false;
|
||||
for (int ci = 0; ci < sd_mnee->num_closure; ci++) {
|
||||
ccl_private ShaderClosure *bsdf = &sd_mnee->closure[ci];
|
||||
if (CLOSURE_IS_REFRACTIVE(bsdf->type)) {
|
||||
if (CLOSURE_IS_REFRACTION(bsdf->type) || CLOSURE_IS_GLASS(bsdf->type)) {
|
||||
/* Note that Glass closures are treated as refractive further below. */
|
||||
|
||||
found_refractive_microfacet_bsdf = true;
|
||||
|
||||
@@ -90,31 +90,33 @@ ccl_device_inline void surface_shader_prepare_closures(KernelGlobals kg,
|
||||
{
|
||||
/* Filter out closures. */
|
||||
if (kernel_data.integrator.filter_closures) {
|
||||
if (kernel_data.integrator.filter_closures & FILTER_CLOSURE_EMISSION) {
|
||||
const int filter_closures = kernel_data.integrator.filter_closures;
|
||||
if (filter_closures & FILTER_CLOSURE_EMISSION) {
|
||||
sd->closure_emission_background = zero_spectrum();
|
||||
}
|
||||
|
||||
if (kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIRECT_LIGHT) {
|
||||
sd->flag &= ~SD_BSDF_HAS_EVAL;
|
||||
}
|
||||
|
||||
if (path_flag & PATH_RAY_CAMERA) {
|
||||
if (filter_closures & FILTER_CLOSURE_DIRECT_LIGHT) {
|
||||
sd->flag &= ~SD_BSDF_HAS_EVAL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ccl_private ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if ((CLOSURE_IS_BSDF_DIFFUSE(sc->type) &&
|
||||
(kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIFFUSE)) ||
|
||||
(CLOSURE_IS_BSDF_GLOSSY(sc->type) &&
|
||||
(kernel_data.integrator.filter_closures & FILTER_CLOSURE_GLOSSY)) ||
|
||||
(CLOSURE_IS_BSDF_TRANSMISSION(sc->type) &&
|
||||
(kernel_data.integrator.filter_closures & FILTER_CLOSURE_TRANSMISSION)))
|
||||
const bool filter_diffuse = (filter_closures & FILTER_CLOSURE_DIFFUSE);
|
||||
const bool filter_glossy = (filter_closures & FILTER_CLOSURE_GLOSSY);
|
||||
const bool filter_transmission = (filter_closures & FILTER_CLOSURE_TRANSMISSION);
|
||||
const bool filter_glass = filter_glossy && filter_transmission;
|
||||
if ((CLOSURE_IS_BSDF_DIFFUSE(sc->type) && filter_diffuse) ||
|
||||
(CLOSURE_IS_BSDF_GLOSSY(sc->type) && filter_glossy) ||
|
||||
(CLOSURE_IS_BSDF_TRANSMISSION(sc->type) && filter_transmission) ||
|
||||
(CLOSURE_IS_GLASS(sc->type) && filter_glass))
|
||||
{
|
||||
sc->type = CLOSURE_NONE_ID;
|
||||
sc->sample_weight = 0.0f;
|
||||
}
|
||||
else if ((CLOSURE_IS_BSDF_TRANSPARENT(sc->type) &&
|
||||
(kernel_data.integrator.filter_closures & FILTER_CLOSURE_TRANSPARENT)))
|
||||
{
|
||||
(filter_closures & FILTER_CLOSURE_TRANSPARENT))) {
|
||||
sc->type = CLOSURE_HOLDOUT_ID;
|
||||
sc->sample_weight = 0.0f;
|
||||
sd->flag |= SD_HOLDOUT;
|
||||
@@ -218,6 +220,13 @@ ccl_device_forceinline bool _surface_shader_exclude(ClosureType type, uint light
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/* Glass closures are both glossy and transmissive, so only exclude them if both are filtered. */
|
||||
const uint exclude_glass = SHADER_EXCLUDE_TRANSMIT | SHADER_EXCLUDE_GLOSSY;
|
||||
if ((light_shader_flags & exclude_glass) == exclude_glass) {
|
||||
if (CLOSURE_IS_GLASS(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -245,7 +254,7 @@ ccl_device_inline float _surface_shader_bsdf_eval_mis(KernelGlobals kg,
|
||||
Spectrum eval = bsdf_eval(kg, sd, sc, wo, &bsdf_pdf);
|
||||
|
||||
if (bsdf_pdf != 0.0f) {
|
||||
bsdf_eval_accum(result_eval, sc->type, eval * sc->weight);
|
||||
bsdf_eval_accum(result_eval, sc, wo, eval * sc->weight);
|
||||
sum_pdf += bsdf_pdf * sc->sample_weight;
|
||||
}
|
||||
}
|
||||
@@ -268,7 +277,7 @@ ccl_device_inline float surface_shader_bsdf_eval_pdfs(const KernelGlobals kg,
|
||||
* factors drop out when using balance heuristic weighting. */
|
||||
float sum_pdf = 0.0f;
|
||||
float sum_sample_weight = 0.0f;
|
||||
bsdf_eval_init(result_eval, CLOSURE_NONE_ID, zero_spectrum());
|
||||
bsdf_eval_init(result_eval, zero_spectrum());
|
||||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ccl_private const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
@@ -278,7 +287,7 @@ ccl_device_inline float surface_shader_bsdf_eval_pdfs(const KernelGlobals kg,
|
||||
Spectrum eval = bsdf_eval(kg, sd, sc, wo, &bsdf_pdf);
|
||||
kernel_assert(bsdf_pdf >= 0.0f);
|
||||
if (bsdf_pdf != 0.0f) {
|
||||
bsdf_eval_accum(result_eval, sc->type, eval * sc->weight);
|
||||
bsdf_eval_accum(result_eval, sc, wo, eval * sc->weight);
|
||||
sum_pdf += bsdf_pdf * sc->sample_weight;
|
||||
kernel_assert(bsdf_pdf * sc->sample_weight >= 0.0f);
|
||||
pdfs[i] = bsdf_pdf * sc->sample_weight;
|
||||
@@ -319,7 +328,7 @@ ccl_device_inline
|
||||
ccl_private BsdfEval *bsdf_eval,
|
||||
const uint light_shader_flags)
|
||||
{
|
||||
bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, zero_spectrum());
|
||||
bsdf_eval_init(bsdf_eval, zero_spectrum());
|
||||
|
||||
float pdf = _surface_shader_bsdf_eval_mis(
|
||||
kg, sd, wo, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags);
|
||||
@@ -441,7 +450,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
||||
/* Initialize to zero. */
|
||||
int label = LABEL_NONE;
|
||||
Spectrum eval = zero_spectrum();
|
||||
bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, eval);
|
||||
bsdf_eval_init(bsdf_eval, eval);
|
||||
|
||||
*unguided_bsdf_pdf = 0.0f;
|
||||
float guide_pdf = 0.0f;
|
||||
@@ -505,7 +514,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
||||
# endif
|
||||
|
||||
if (*unguided_bsdf_pdf != 0.0f) {
|
||||
bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight);
|
||||
bsdf_eval_init(bsdf_eval, sc, *wo, eval * sc->weight);
|
||||
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
|
||||
@@ -554,7 +563,7 @@ ccl_device int surface_shader_bsdf_sample_closure(KernelGlobals kg,
|
||||
label = bsdf_sample(kg, sd, sc, path_flag, rand_bsdf, &eval, wo, pdf, sampled_roughness, eta);
|
||||
|
||||
if (*pdf != 0.0f) {
|
||||
bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight);
|
||||
bsdf_eval_init(bsdf_eval, sc, *wo, eval * sc->weight);
|
||||
|
||||
if (sd->num_closure > 1) {
|
||||
float sweight = sc->sample_weight;
|
||||
@@ -562,7 +571,7 @@ ccl_device int surface_shader_bsdf_sample_closure(KernelGlobals kg,
|
||||
}
|
||||
}
|
||||
else {
|
||||
bsdf_eval_init(bsdf_eval, sc->type, zero_spectrum());
|
||||
bsdf_eval_init(bsdf_eval, zero_spectrum());
|
||||
}
|
||||
|
||||
return label;
|
||||
@@ -634,7 +643,7 @@ ccl_device Spectrum surface_shader_diffuse(KernelGlobals kg, ccl_private const S
|
||||
ccl_private const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSSRDF(sc->type))
|
||||
eval += bsdf_albedo(sd, sc);
|
||||
eval += bsdf_albedo(sd, sc, true, true);
|
||||
}
|
||||
|
||||
return eval;
|
||||
@@ -647,8 +656,8 @@ ccl_device Spectrum surface_shader_glossy(KernelGlobals kg, ccl_private const Sh
|
||||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ccl_private const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if (CLOSURE_IS_BSDF_GLOSSY(sc->type))
|
||||
eval += bsdf_albedo(sd, sc);
|
||||
if (CLOSURE_IS_BSDF_GLOSSY(sc->type) || CLOSURE_IS_GLASS(sc->type))
|
||||
eval += bsdf_albedo(sd, sc, true, false);
|
||||
}
|
||||
|
||||
return eval;
|
||||
@@ -661,8 +670,8 @@ ccl_device Spectrum surface_shader_transmission(KernelGlobals kg, ccl_private co
|
||||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ccl_private const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if (CLOSURE_IS_BSDF_TRANSMISSION(sc->type))
|
||||
eval += bsdf_albedo(sd, sc);
|
||||
if (CLOSURE_IS_BSDF_TRANSMISSION(sc->type) || CLOSURE_IS_GLASS(sc->type))
|
||||
eval += bsdf_albedo(sd, sc, false, true);
|
||||
}
|
||||
|
||||
return eval;
|
||||
|
||||
@@ -217,7 +217,7 @@ ccl_device_inline float _volume_shader_phase_eval_mis(ccl_private const ShaderDa
|
||||
Spectrum eval = volume_phase_eval(sd, svc, wo, &phase_pdf);
|
||||
|
||||
if (phase_pdf != 0.0f) {
|
||||
bsdf_eval_accum(result_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
|
||||
bsdf_eval_accum(result_eval, eval);
|
||||
sum_pdf += phase_pdf * svc->sample_weight;
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ ccl_device float volume_shader_phase_eval(KernelGlobals kg,
|
||||
Spectrum eval = volume_phase_eval(sd, svc, wo, &phase_pdf);
|
||||
|
||||
if (phase_pdf != 0.0f) {
|
||||
bsdf_eval_accum(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
|
||||
bsdf_eval_accum(phase_eval, eval);
|
||||
}
|
||||
|
||||
return phase_pdf;
|
||||
@@ -250,7 +250,7 @@ ccl_device float volume_shader_phase_eval(KernelGlobals kg,
|
||||
const float3 wo,
|
||||
ccl_private BsdfEval *phase_eval)
|
||||
{
|
||||
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, zero_spectrum());
|
||||
bsdf_eval_init(phase_eval, zero_spectrum());
|
||||
|
||||
float pdf = _volume_shader_phase_eval_mis(sd, phases, wo, -1, phase_eval, 0.0f, 0.0f);
|
||||
|
||||
@@ -300,7 +300,7 @@ ccl_device int volume_shader_phase_guided_sample(KernelGlobals kg,
|
||||
float guide_pdf = 0.0f;
|
||||
*sampled_roughness = 1.0f - fabsf(svc->g);
|
||||
|
||||
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, zero_spectrum());
|
||||
bsdf_eval_init(phase_eval, zero_spectrum());
|
||||
|
||||
if (sample_guiding) {
|
||||
/* Sample guiding distribution. */
|
||||
@@ -321,7 +321,7 @@ ccl_device int volume_shader_phase_guided_sample(KernelGlobals kg,
|
||||
sd, svc, rand_phase.x, rand_phase.y, &eval, wo, unguided_phase_pdf);
|
||||
|
||||
if (*unguided_phase_pdf != 0.0f) {
|
||||
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
|
||||
bsdf_eval_init(phase_eval, eval);
|
||||
|
||||
*phase_pdf = *unguided_phase_pdf;
|
||||
if (use_volume_guiding) {
|
||||
@@ -333,7 +333,7 @@ ccl_device int volume_shader_phase_guided_sample(KernelGlobals kg,
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(phase_eval)) >= 0.0f);
|
||||
}
|
||||
else {
|
||||
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, zero_spectrum());
|
||||
bsdf_eval_init(phase_eval, zero_spectrum());
|
||||
}
|
||||
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(phase_eval)) >= 0.0f);
|
||||
@@ -360,7 +360,7 @@ ccl_device int volume_shader_phase_sample(KernelGlobals kg,
|
||||
int label = volume_phase_sample(sd, svc, rand_phase.x, rand_phase.y, &eval, wo, pdf);
|
||||
|
||||
if (*pdf != 0.0f) {
|
||||
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
|
||||
bsdf_eval_init(phase_eval, eval);
|
||||
}
|
||||
|
||||
return label;
|
||||
|
||||
@@ -316,7 +316,7 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
|
||||
return;
|
||||
}
|
||||
point_to_centroid = -bcone.axis;
|
||||
cos_theta_u = fast_cosf(bcone.theta_o);
|
||||
cos_theta_u = fast_cosf(bcone.theta_o + bcone.theta_e);
|
||||
distance = 1.0f;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -434,12 +434,14 @@ typedef enum ClosureType {
|
||||
CLOSURE_BSDF_REFRACTION_ID,
|
||||
CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID,
|
||||
CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
|
||||
CLOSURE_BSDF_HAIR_PRINCIPLED_ID,
|
||||
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
|
||||
|
||||
/* Glass */
|
||||
CLOSURE_BSDF_SHARP_GLASS_ID,
|
||||
CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
|
||||
CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
|
||||
CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID,
|
||||
CLOSURE_BSDF_HAIR_PRINCIPLED_ID,
|
||||
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
|
||||
|
||||
/* Special cases */
|
||||
CLOSURE_BSDF_TRANSPARENT_ID,
|
||||
@@ -473,15 +475,15 @@ typedef enum ClosureType {
|
||||
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
|
||||
#define CLOSURE_IS_BSDF_SINGULAR(type) \
|
||||
(type == CLOSURE_BSDF_REFLECTION_ID || type == CLOSURE_BSDF_REFRACTION_ID || \
|
||||
type == CLOSURE_BSDF_TRANSPARENT_ID)
|
||||
type == CLOSURE_BSDF_TRANSPARENT_ID || type == CLOSURE_BSDF_SHARP_GLASS_ID)
|
||||
#define CLOSURE_IS_BSDF_TRANSPARENT(type) (type == CLOSURE_BSDF_TRANSPARENT_ID)
|
||||
#define CLOSURE_IS_BSDF_MULTISCATTER(type) \
|
||||
(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID || \
|
||||
type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
|
||||
#define CLOSURE_IS_BSDF_MICROFACET(type) \
|
||||
((type >= CLOSURE_BSDF_MICROFACET_GGX_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) || \
|
||||
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
|
||||
type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID))
|
||||
((type >= CLOSURE_BSDF_REFLECTION_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) || \
|
||||
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID) || \
|
||||
(type >= CLOSURE_BSDF_SHARP_GLASS_ID && type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID))
|
||||
#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
|
||||
#define CLOSURE_IS_BSSRDF(type) \
|
||||
(type >= CLOSURE_BSSRDF_BURLEY_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
|
||||
@@ -491,8 +493,8 @@ typedef enum ClosureType {
|
||||
#define CLOSURE_IS_VOLUME_ABSORPTION(type) (type == CLOSURE_VOLUME_ABSORPTION_ID)
|
||||
#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
|
||||
#define CLOSURE_IS_PHASE(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
|
||||
#define CLOSURE_IS_REFRACTIVE(type) \
|
||||
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
|
||||
#define CLOSURE_IS_REFRACTION(type) \
|
||||
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID)
|
||||
#define CLOSURE_IS_GLASS(type) \
|
||||
(type >= CLOSURE_BSDF_SHARP_GLASS_ID && type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
|
||||
#define CLOSURE_IS_PRINCIPLED(type) (type == CLOSURE_BSDF_PRINCIPLED_ID)
|
||||
|
||||
@@ -79,11 +79,6 @@ CCL_NAMESPACE_BEGIN
|
||||
#define __VISIBILITY_FLAG__
|
||||
#define __VOLUME__
|
||||
|
||||
/* TODO: solve internal compiler perf issue and enable light tree on Metal/AMD. */
|
||||
#if defined(__KERNEL_METAL_AMD__)
|
||||
# undef __LIGHT_TREE__
|
||||
#endif
|
||||
|
||||
/* Device specific features */
|
||||
#ifdef WITH_OSL
|
||||
# define __OSL__
|
||||
@@ -105,6 +100,13 @@ CCL_NAMESPACE_BEGIN
|
||||
# define __MNEE__
|
||||
#endif
|
||||
|
||||
#if defined(__KERNEL_METAL_AMD__)
|
||||
/* Disabled due to internal compiler perf issue and enable light tree on Metal/AMD. */
|
||||
# undef __LIGHT_TREE__
|
||||
/* Disabled due to compiler crash on Metal/AMD. */
|
||||
# undef __MNEE__
|
||||
#endif
|
||||
|
||||
/* Scene-based selective features compilation. */
|
||||
#ifdef __KERNEL_FEATURES__
|
||||
# if !(__KERNEL_FEATURES & KERNEL_FEATURE_OBJECT_MOTION)
|
||||
|
||||
@@ -611,6 +611,41 @@ void AlembicObject::load_data_in_cache(CachedData &cached_data,
|
||||
data_loaded = true;
|
||||
}
|
||||
|
||||
void AlembicObject::load_data_in_cache(CachedData &cached_data,
|
||||
AlembicProcedural *proc,
|
||||
const IPointsSchema &schema,
|
||||
Progress &progress)
|
||||
{
|
||||
/* Only load data for the original Geometry. */
|
||||
if (instance_of) {
|
||||
return;
|
||||
}
|
||||
|
||||
cached_data.clear();
|
||||
|
||||
PointsSchemaData data;
|
||||
data.positions = schema.getPositionsProperty();
|
||||
data.radiuses = schema.getWidthsParam();
|
||||
data.velocities = schema.getVelocitiesProperty();
|
||||
data.time_sampling = schema.getTimeSampling();
|
||||
data.num_samples = schema.getNumSamples();
|
||||
data.default_radius = proc->get_default_radius();
|
||||
data.radius_scale = get_radius_scale();
|
||||
|
||||
read_geometry_data(proc, cached_data, data, progress);
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use the schema as the base compound property to also be able to look for top level properties.
|
||||
*/
|
||||
read_attributes(proc, cached_data, schema, {}, get_requested_attributes(), progress);
|
||||
|
||||
cached_data.invalidate_last_loaded_time(true);
|
||||
data_loaded = true;
|
||||
}
|
||||
|
||||
void AlembicObject::setup_transform_cache(CachedData &cached_data, float scale)
|
||||
{
|
||||
cached_data.transforms.clear();
|
||||
|
||||
@@ -398,6 +398,10 @@ class AlembicObject : public Node {
|
||||
AlembicProcedural *proc,
|
||||
const Alembic::AbcGeom::ICurvesSchema &schema,
|
||||
Progress &progress);
|
||||
void load_data_in_cache(CachedData &cached_data,
|
||||
AlembicProcedural *proc,
|
||||
const Alembic::AbcGeom::IPointsSchema &schema,
|
||||
Progress &progress);
|
||||
|
||||
bool has_data_loaded() const;
|
||||
|
||||
|
||||
@@ -663,8 +663,8 @@ static void read_points_data(CachedData &cached_data, const PointsSchemaData &da
|
||||
|
||||
if (do_radius) {
|
||||
radius = (*radiuses)[offset + i];
|
||||
a_radius.push_back_slow(radius);
|
||||
}
|
||||
a_radius.push_back_slow(radius * data.radius_scale);
|
||||
|
||||
a_shader.push_back_slow((int)0);
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ void read_geometry_data(AlembicProcedural *proc,
|
||||
const CurvesSchemaData &data,
|
||||
Progress &progress);
|
||||
|
||||
/* Data of a ICurvesSchema that we need to read. */
|
||||
/* Data of a IPointsSchema that we need to read. */
|
||||
struct PointsSchemaData {
|
||||
Alembic::AbcGeom::TimeSamplingPtr time_sampling;
|
||||
size_t num_samples;
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
# define HAVE_MALLOC_STATS
|
||||
#elif defined(__FreeBSD__)
|
||||
# include <malloc_np.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# undef USE_MALLOC_USABLE_SIZE
|
||||
#elif defined(__APPLE__)
|
||||
# include <malloc/malloc.h>
|
||||
|
||||
Binary file not shown.
@@ -22,11 +22,10 @@ PERFORMANCE OF THIS SOFTWARE.
|
||||
** Audaspace; version 1.3.0 -- https://audaspace.github.io/
|
||||
** Cuda Wrangler; version cbf465b -- https://github.com/CudaWrangler/cuew
|
||||
** Draco; version 1.3.6 -- https://google.github.io/draco/
|
||||
** Embree; version 3.13.4 -- https://github.com/embree/embree
|
||||
** Intel(R) oneAPI DPC++ compiler; version 20221019 --
|
||||
** Embree; version 4.1.0 -- https://github.com/embree/embree
|
||||
** Intel(R) oneAPI DPC++ compiler; version 2022-12 --
|
||||
https://github.com/intel/llvm#oneapi-dpc-compiler
|
||||
** Intel® Open Path Guiding Library; version v0.4.1-beta --
|
||||
http://www.openpgl.org/
|
||||
** Intel® Open Path Guiding Library; version 0.5.0 -- http://www.openpgl.org/
|
||||
** Mantaflow; version 0.13 -- http://mantaflow.com/
|
||||
** materialX; version 1.38.6 --
|
||||
https://github.com/AcademySoftwareFoundation/MaterialX
|
||||
@@ -40,6 +39,8 @@ https://software.intel.com/en-us/oneapi/onetbb
|
||||
** SDL Extension Wrangler; version 15edf8e --
|
||||
https://github.com/SDLWrangler/sdlew
|
||||
** ShaderC; version 2022.3 -- https://github.com/google/shaderc
|
||||
** SYCL Unified Runtime ; version fd711c920acc4434cb52ff18b078c082d9d7f44d --
|
||||
https://github.com/oneapi-src/unified-runtime
|
||||
** Vulkan Loader; version 1.2.198 --
|
||||
https://github.com/KhronosGroup/Vulkan-Loader
|
||||
|
||||
@@ -279,6 +280,8 @@ limitations under the License.
|
||||
Copyright 2014 Blender Foundation
|
||||
* For ShaderC see also this required NOTICE:
|
||||
Copyright 2015 The Shaderc Authors. All rights reserved.
|
||||
* For SYCL Unified Runtime see also this required NOTICE:
|
||||
Copyright (C) 2022-2023 Intel Corporation
|
||||
* For Vulkan Loader see also this required NOTICE:
|
||||
Copyright (c) 2019 The Khronos Group Inc.
|
||||
Copyright (c) 2019 Valve Corporation
|
||||
@@ -378,7 +381,7 @@ All rights reserved.
|
||||
** Google Logging; version 4.4.0 -- https://github.com/google/glog
|
||||
Copyright (c) 2006, Google Inc.
|
||||
All rights reserved.
|
||||
** Imath; version 3.1.5 -- https://github.com/AcademySoftwareFoundation/Imath
|
||||
** Imath; version 3.1.7 -- https://github.com/AcademySoftwareFoundation/Imath
|
||||
Copyright Contributors to the OpenEXR Project. All rights reserved.
|
||||
** ISPC; version 1.17.0 -- https://github.com/ispc/ispc
|
||||
Copyright Intel Corporation
|
||||
@@ -395,10 +398,10 @@ Copyright Contributors to the Open Shading Language project.
|
||||
** OpenColorIO; version 2.2.0 --
|
||||
https://github.com/AcademySoftwareFoundation/OpenColorIO
|
||||
Copyright Contributors to the OpenColorIO Project.
|
||||
** OpenEXR; version 3.1.5 --
|
||||
** OpenEXR; version 3.1.7 --
|
||||
https://github.com/AcademySoftwareFoundation/openexr
|
||||
Copyright Contributors to the OpenEXR Project. All rights reserved.
|
||||
** OpenImageIO; version 2.4.9.0 -- http://www.openimageio.org
|
||||
** OpenImageIO; version 2.4.11.0 -- http://www.openimageio.org
|
||||
Copyright (c) 2008-present by Contributors to the OpenImageIO project. All
|
||||
Rights Reserved.
|
||||
** Pystring; version 1.1.3 -- https://github.com/imageworks/pystring
|
||||
@@ -571,7 +574,7 @@ effect of CC0 on those rights.
|
||||
|
||||
------
|
||||
|
||||
** FLAC; version 1.3.4 -- https://xiph.org/flac/
|
||||
** FLAC; version 1.4.2 -- https://xiph.org/flac/
|
||||
Copyright (C) 2001-2009 Josh Coalson
|
||||
Copyright (C) 2011-2016 Xiph.Org Foundation
|
||||
** Potrace; version 1.16 -- http://potrace.sourceforge.net/
|
||||
@@ -1242,7 +1245,7 @@ Copyright (C) 2003-2021 x264 project
|
||||
** miniLZO; version 2.08 -- http://www.oberhumer.com/opensource/lzo/
|
||||
LZO and miniLZO are Copyright (C) 1996-2014 Markus Franz Xaver Oberhumer
|
||||
All Rights Reserved.
|
||||
** The FreeType Project; version 2.12.1 --
|
||||
** The FreeType Project; version 2.13.0 --
|
||||
https://sourceforge.net/projects/freetype
|
||||
Copyright (C) 1996-2020 by David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
** X Drag and Drop; version 2000-08-08 --
|
||||
@@ -2796,7 +2799,7 @@ That's all there is to it!
|
||||
|
||||
------
|
||||
|
||||
** FFmpeg; version 5.1.2 -- http://ffmpeg.org/
|
||||
** FFmpeg; version 6.0 -- http://ffmpeg.org/
|
||||
Copyright: The FFmpeg contributors
|
||||
https://github.com/FFmpeg/FFmpeg/blob/master/CREDITS
|
||||
** Libsndfile; version 1.1.0 -- http://libsndfile.github.io/libsndfile/
|
||||
@@ -3425,7 +3428,35 @@ December 9, 2010
|
||||
|
||||
------
|
||||
|
||||
** {fmt}; version 8.0.0 -- https://github.com/fmtlib/fmt
|
||||
** vcintrinsics; version 782fbf7301dc73acaa049a4324c976ad94f587f7 --
|
||||
https://github.com/intel/vc-intrinsics
|
||||
Copyright (c) 2019 Intel Corporation
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Intel Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
------
|
||||
|
||||
** {fmt}; version 9.1.0 -- https://github.com/fmtlib/fmt
|
||||
Copyright (c) 2012 - present, Victor Zverovich
|
||||
** Brotli; version 1.0.9 -- https://github.com/google/brotli
|
||||
Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
|
||||
@@ -3454,11 +3485,11 @@ Copyright (c) 2006, 2008 Junio C Hamano
|
||||
Copyright © 2017-2018 Red Hat Inc.
|
||||
Copyright © 2012 Collabora, Ltd.
|
||||
Copyright © 2008 Kristian Høgsberg
|
||||
** Libxml2; version 2.10.3 -- http://xmlsoft.org/
|
||||
** Libxml2; version 2.10.4 -- http://xmlsoft.org/
|
||||
Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved.
|
||||
** Mesa 3D; version 21.1.5 -- https://www.mesa3d.org/
|
||||
Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
|
||||
** oneAPI Level Zero; version v1.8.5 --
|
||||
** oneAPI Level Zero; version v1.8.8 --
|
||||
https://github.com/oneapi-src/level-zero
|
||||
Copyright (C) 2019-2021 Intel Corporation
|
||||
** OPENCollada; version 1.6.68 -- https://github.com/KhronosGroup/OpenCOLLADA
|
||||
@@ -3470,12 +3501,11 @@ Copyright (c) 2018 Jingwei Huang, Yichao Zhou, Matthias Niessner,
|
||||
Jonathan Shewchuk and Leonidas Guibas. All rights reserved.
|
||||
** robin-map; version 0.6.2 -- https://github.com/Tessil/robin-map
|
||||
Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil@gmx.com>
|
||||
** sse2neon; version fe5ff00bb8d19b327714a3c290f3e2ce81ba3525 --
|
||||
https://github.com/DLTcollab/sse2neon
|
||||
** sse2neon; version 1.6.0 -- https://github.com/DLTcollab/sse2neon
|
||||
Copyright sse2neon contributors
|
||||
** TinyGLTF; version 2.5.0 -- https://github.com/syoyo/tinygltf
|
||||
Copyright (c) 2017 Syoyo Fujita, Aurélien Chatelain and many contributors
|
||||
** Wayland protocols; version 1.21 --
|
||||
** Wayland protocols; version 1.31 --
|
||||
https://gitlab.freedesktop.org/wayland/wayland-protocols
|
||||
Copyright © 2008-2013 Kristian Høgsberg
|
||||
Copyright © 2010-2013 Intel Corporation
|
||||
@@ -3973,7 +4003,7 @@ the following restrictions:
|
||||
|
||||
------
|
||||
|
||||
** LibTIFF; version 4.4.0 -- http://www.libtiff.org/
|
||||
** LibTIFF; version 4.5.1 -- http://www.libtiff.org/
|
||||
Copyright (c) 1988-1997 Sam Leffler
|
||||
Copyright (c) 1991-1997 Silicon Graphics, Inc.
|
||||
|
||||
@@ -4029,7 +4059,7 @@ Software.
|
||||
|
||||
** OpenSubdiv; version 3.5.0 -- http://graphics.pixar.com/opensubdiv
|
||||
Copyright 2013 Pixar
|
||||
** Universal Scene Description; version 22.11 -- http://www.openusd.org/
|
||||
** Universal Scene Description; version 23.05 -- http://www.openusd.org/
|
||||
Copyright 2016 Pixar
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "Apache License") with the
|
||||
@@ -4215,7 +4245,7 @@ disclaims all warranties with regard to this software.
|
||||
|
||||
------
|
||||
|
||||
** Wayland; version 1.21.0 -- https://gitlab.freedesktop.org/wayland/wayland
|
||||
** Wayland; version 1.22.0 -- https://gitlab.freedesktop.org/wayland/wayland
|
||||
Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
|
||||
Copyright © 2011 Kristian Høgsberg
|
||||
Copyright © 2011 Benjamin Franzke
|
||||
@@ -4240,7 +4270,7 @@ MIT Expat
|
||||
|
||||
------
|
||||
|
||||
** OpenSSL; version 1.1.1q -- https://www.openssl.org/
|
||||
** OpenSSL; version 3.1.1 -- https://www.openssl.org/
|
||||
Copyright (c) 1998-2021 The OpenSSL Project
|
||||
Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson
|
||||
|
||||
@@ -4363,7 +4393,7 @@ OpenSSL License
|
||||
|
||||
------
|
||||
|
||||
** Python; version 3.10.9 -- https://www.python.org
|
||||
** Python; version 3.10.12 -- https://www.python.org
|
||||
Copyright (c) 2001-2021 Python Software Foundation. All rights reserved.
|
||||
|
||||
A. HISTORY OF THE SOFTWARE
|
||||
|
||||
@@ -178,6 +178,8 @@ class Object(bpy_types.ID):
|
||||
def children(self):
|
||||
"""All the children of this object.
|
||||
|
||||
:type: tuple of `Object`
|
||||
|
||||
.. note:: Takes ``O(len(bpy.data.objects))`` time."""
|
||||
import bpy
|
||||
return tuple(child for child in bpy.data.objects
|
||||
@@ -187,6 +189,8 @@ class Object(bpy_types.ID):
|
||||
def children_recursive(self):
|
||||
"""A list of all children from this object.
|
||||
|
||||
:type: tuple of `Object`
|
||||
|
||||
.. note:: Takes ``O(len(bpy.data.objects))`` time."""
|
||||
import bpy
|
||||
parent_child_map = {}
|
||||
@@ -209,6 +213,8 @@ class Object(bpy_types.ID):
|
||||
"""
|
||||
The collections this object is in.
|
||||
|
||||
:type: tuple of `Collection`
|
||||
|
||||
.. note:: Takes ``O(len(bpy.data.collections) + len(bpy.data.scenes))`` time."""
|
||||
import bpy
|
||||
return (
|
||||
@@ -225,6 +231,8 @@ class Object(bpy_types.ID):
|
||||
def users_scene(self):
|
||||
"""The scenes this object is in.
|
||||
|
||||
:type: tuple of `Scene`
|
||||
|
||||
.. note:: Takes ``O(len(bpy.data.scenes) * len(bpy.data.objects))`` time."""
|
||||
import bpy
|
||||
return tuple(scene for scene in bpy.data.scenes
|
||||
@@ -526,7 +534,7 @@ def ord_ind(i1, i2):
|
||||
class Mesh(bpy_types.ID):
|
||||
__slots__ = ()
|
||||
|
||||
def from_pydata(self, vertices, edges, faces):
|
||||
def from_pydata(self, vertices, edges, faces, shade_flat=True):
|
||||
"""
|
||||
Make a mesh from a list of vertices/edges/faces
|
||||
Until we have a nicer way to make geometry, use this.
|
||||
@@ -583,6 +591,9 @@ class Mesh(bpy_types.ID):
|
||||
self.polygons.foreach_set("loop_start", loop_starts)
|
||||
self.polygons.foreach_set("vertices", vertex_indices)
|
||||
|
||||
if shade_flat:
|
||||
self.shade_flat()
|
||||
|
||||
if edges_len or faces_len:
|
||||
self.update(
|
||||
# Needed to either:
|
||||
@@ -597,6 +608,35 @@ class Mesh(bpy_types.ID):
|
||||
def edge_keys(self):
|
||||
return [ed.key for ed in self.edges]
|
||||
|
||||
def shade_flat(self):
|
||||
"""
|
||||
Render and display faces uniform, using face normals,
|
||||
setting the "sharp_face" attribute true for every face
|
||||
"""
|
||||
attr = self.attributes.get("sharp_face")
|
||||
if attr is None:
|
||||
pass
|
||||
elif attr.data_type == 'BOOLEAN' and attr.domain == 'FACE':
|
||||
pass
|
||||
else:
|
||||
self.attributes.remove(attr)
|
||||
attr = None
|
||||
|
||||
if attr is None:
|
||||
attr = self.attributes.new("sharp_face", 'BOOLEAN', 'FACE')
|
||||
|
||||
for value in attr.data:
|
||||
value.value = True
|
||||
|
||||
def shade_smooth(self):
|
||||
"""
|
||||
Render and display faces smooth, using interpolated vertex normals,
|
||||
removing the "sharp_face" attribute
|
||||
"""
|
||||
attr = self.attributes.get("sharp_face")
|
||||
if attr is not None:
|
||||
self.attributes.remove(attr)
|
||||
|
||||
|
||||
class MeshEdge(StructRNA):
|
||||
__slots__ = ()
|
||||
|
||||
@@ -243,6 +243,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
|
||||
mesh.vertices.foreach_set("co", verts_loc)
|
||||
mesh.polygons.foreach_set("loop_start", range(0, nbr_loops, 4))
|
||||
mesh.loops.foreach_set("vertex_index", faces)
|
||||
mesh.shade_flat()
|
||||
|
||||
if self.generate_uvs:
|
||||
add_uvs(mesh, self.minor_segments, self.major_segments)
|
||||
|
||||
@@ -29,7 +29,7 @@ def draw_ui_list(
|
||||
context,
|
||||
class_name="UI_UL_list",
|
||||
*,
|
||||
unique_id="",
|
||||
unique_id,
|
||||
list_path,
|
||||
active_index_path,
|
||||
insertion_operators=True,
|
||||
@@ -46,7 +46,7 @@ def draw_ui_list(
|
||||
:type context: :class:`Context`
|
||||
:arg class_name: Name of the UIList class to draw. The default is the UIList class that ships with Blender.
|
||||
:type class_name: str
|
||||
:arg unique_id: Optional identifier, in case wanting to draw multiple unique copies of a list.
|
||||
:arg unique_id: Unique identifier to differentiate this from other UI lists.
|
||||
:type unique_id: str
|
||||
:arg list_path: Data path of the list relative to context, eg. "object.vertex_groups".
|
||||
:type list_path: str
|
||||
|
||||
@@ -1876,7 +1876,7 @@ class SEQUENCER_PT_time(SequencerButtonsPanel, Panel):
|
||||
split.label(text="Channel")
|
||||
split.prop(strip, "channel", text="")
|
||||
|
||||
if strip.type == 'SOUND':
|
||||
if not is_effect:
|
||||
split = layout.split(factor=0.5 + max_factor)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Speed Factor")
|
||||
|
||||
@@ -2529,18 +2529,6 @@ class _defs_sequencer_generic:
|
||||
options={'KEYMAP_FALLBACK'},
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def retime():
|
||||
return dict(
|
||||
idname="builtin.retime",
|
||||
label="Retime",
|
||||
icon="ops.sequencer.retime",
|
||||
widget="SEQUENCER_GGT_gizmo_retime",
|
||||
operator=None,
|
||||
keymap=None,
|
||||
options={'KEYMAP_FALLBACK'},
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def sample():
|
||||
return dict(
|
||||
@@ -3222,7 +3210,6 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel):
|
||||
'SEQUENCER': [
|
||||
*_tools_select,
|
||||
_defs_sequencer_generic.blade,
|
||||
_defs_sequencer_generic.retime,
|
||||
],
|
||||
'SEQUENCER_PREVIEW': [
|
||||
*_tools_select,
|
||||
|
||||
@@ -18,8 +18,9 @@ class MyPanel(bpy.types.Panel):
|
||||
draw_ui_list(
|
||||
layout,
|
||||
context,
|
||||
list_context_path="scene.my_list",
|
||||
active_index_context_path="scene.my_list_active_index"
|
||||
list_path="scene.my_list",
|
||||
active_index_path="scene.my_list_active_index",
|
||||
unique_id="my_list_id",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ void BKE_mesh_legacy_edge_crease_from_layers(struct Mesh *mesh);
|
||||
* Copy edge creases from edges to a separate layer.
|
||||
*/
|
||||
void BKE_mesh_legacy_edge_crease_to_layers(struct Mesh *mesh);
|
||||
void BKE_mesh_crease_layers_from_future(struct Mesh *mesh);
|
||||
|
||||
/**
|
||||
* Copy bevel weights from separate layers into vertices and edges.
|
||||
|
||||
@@ -865,7 +865,7 @@ void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Obj
|
||||
*/
|
||||
struct MultiresModifierData *BKE_sculpt_multires_active(const struct Scene *scene,
|
||||
struct Object *ob);
|
||||
int *BKE_sculpt_face_sets_ensure(struct Mesh *mesh);
|
||||
int *BKE_sculpt_face_sets_ensure(struct Object *ob);
|
||||
/**
|
||||
* Create the attribute used to store face visibility and retrieve its data.
|
||||
* Note that changes to the face visibility have to be propagated to other domains
|
||||
|
||||
@@ -149,6 +149,9 @@ struct StatesAroundFrame {
|
||||
class ModifierSimulationCache {
|
||||
private:
|
||||
mutable std::mutex states_at_frames_mutex_;
|
||||
/**
|
||||
* All simulation states, sorted by frame.
|
||||
*/
|
||||
Vector<std::unique_ptr<ModifierSimulationStateAtFrame>> states_at_frames_;
|
||||
/**
|
||||
* Used for baking to deduplicate arrays when writing and writing from storage. Sharing info
|
||||
@@ -184,4 +187,12 @@ class ModifierSimulationCache {
|
||||
void clear_prev_states();
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap simulation cache in `std::shared_ptr` so that it can be owned by evaluated modifier even if
|
||||
* the original modifier has been deleted.
|
||||
*/
|
||||
struct ModifierSimulationCachePtr {
|
||||
std::shared_ptr<ModifierSimulationCache> ptr;
|
||||
};
|
||||
|
||||
} // namespace blender::bke::sim
|
||||
|
||||
@@ -154,13 +154,6 @@ void BKE_sound_set_scene_sound_volume(void *handle, float volume, char animated)
|
||||
|
||||
void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated);
|
||||
|
||||
void BKE_sound_set_scene_sound_pitch_at_frame(void *handle, int frame, float pitch, char animated);
|
||||
|
||||
void BKE_sound_set_scene_sound_pitch_constant_range(void *handle,
|
||||
int frame_start,
|
||||
int frame_end,
|
||||
float pitch);
|
||||
|
||||
void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated);
|
||||
|
||||
void BKE_sound_update_sequencer(struct Main *main, struct bSound *sound);
|
||||
|
||||
@@ -38,7 +38,7 @@ typedef struct bMovieHandle {
|
||||
void (*end_movie)(void *context_v);
|
||||
|
||||
/* Optional function. */
|
||||
void (*get_movie_path)(char *filepath,
|
||||
void (*get_movie_path)(char filepath[/*FILE_MAX*/ 1024],
|
||||
const struct RenderData *rd,
|
||||
bool preview,
|
||||
const char *suffix);
|
||||
@@ -52,7 +52,7 @@ bMovieHandle *BKE_movie_handle_get(char imtype);
|
||||
/**
|
||||
* \note Similar to #BKE_image_path_from_imformat()
|
||||
*/
|
||||
void BKE_movie_filepath_get(char *filepath,
|
||||
void BKE_movie_filepath_get(char filepath[/*FILE_MAX*/ 1024],
|
||||
const struct RenderData *rd,
|
||||
bool preview,
|
||||
const char *suffix);
|
||||
|
||||
@@ -64,7 +64,7 @@ int BKE_ffmpeg_append(void *context_v,
|
||||
int recty,
|
||||
const char *suffix,
|
||||
struct ReportList *reports);
|
||||
void BKE_ffmpeg_filepath_get(char *filepath,
|
||||
void BKE_ffmpeg_filepath_get(char filepath[/*FILE_MAX*/ 1024],
|
||||
const struct RenderData *rd,
|
||||
bool preview,
|
||||
const char *suffix);
|
||||
|
||||
@@ -664,6 +664,23 @@ static void bvhtree_from_editmesh_setup_data(BVHTree *tree,
|
||||
}
|
||||
}
|
||||
|
||||
static BVHTree *bvhtree_new_commom(
|
||||
float epsilon, int tree_type, int axis, int elems_num, int &elems_num_active)
|
||||
{
|
||||
if (elems_num_active != -1) {
|
||||
BLI_assert(IN_RANGE_INCL(elems_num_active, 0, elems_num));
|
||||
}
|
||||
else {
|
||||
elems_num_active = elems_num;
|
||||
}
|
||||
|
||||
if (elems_num_active == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return BLI_bvhtree_new(elems_num_active, epsilon, tree_type, axis);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -677,20 +694,15 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(float epsilon,
|
||||
const BitSpan verts_mask,
|
||||
int verts_num_active)
|
||||
{
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
|
||||
const int verts_num = em->bm->totvert;
|
||||
if (!verts_mask.is_empty()) {
|
||||
BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
|
||||
}
|
||||
else {
|
||||
verts_num_active = verts_num;
|
||||
}
|
||||
|
||||
BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
|
||||
BVHTree *tree = bvhtree_new_commom(epsilon, tree_type, axis, verts_num, verts_num_active);
|
||||
if (!tree) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
|
||||
|
||||
for (int i = 0; i < verts_num; i++) {
|
||||
if (!verts_mask.is_empty() && !verts_mask[i]) {
|
||||
continue;
|
||||
@@ -711,17 +723,7 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(float epsilon,
|
||||
const BitSpan verts_mask,
|
||||
int verts_num_active)
|
||||
{
|
||||
if (!verts_mask.is_empty()) {
|
||||
BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
|
||||
}
|
||||
else {
|
||||
verts_num_active = verts_num;
|
||||
}
|
||||
if (verts_num_active == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
|
||||
BVHTree *tree = bvhtree_new_commom(epsilon, tree_type, axis, verts_num, verts_num_active);
|
||||
if (!tree) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -799,21 +801,15 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(float epsilon,
|
||||
const BitSpan edges_mask,
|
||||
int edges_num_active)
|
||||
{
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
|
||||
const int edges_num = em->bm->totedge;
|
||||
|
||||
if (!edges_mask.is_empty()) {
|
||||
BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num));
|
||||
}
|
||||
else {
|
||||
edges_num_active = edges_num;
|
||||
}
|
||||
|
||||
BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
|
||||
BVHTree *tree = bvhtree_new_commom(epsilon, tree_type, axis, edges_num, edges_num_active);
|
||||
if (!tree) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
|
||||
|
||||
int i;
|
||||
BMIter iter;
|
||||
BMEdge *eed;
|
||||
@@ -840,18 +836,7 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(const float (*positions)[3],
|
||||
int tree_type,
|
||||
int axis)
|
||||
{
|
||||
if (!edges_mask.is_empty()) {
|
||||
BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges.size()));
|
||||
}
|
||||
else {
|
||||
edges_num_active = edges.size();
|
||||
}
|
||||
if (edges_num_active == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Create a BVH-tree of the given target */
|
||||
BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
|
||||
BVHTree *tree = bvhtree_new_commom(epsilon, tree_type, axis, edges.size(), edges_num_active);
|
||||
if (!tree) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -935,20 +920,7 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(float epsilon,
|
||||
const BitSpan faces_mask,
|
||||
int faces_num_active)
|
||||
{
|
||||
if (faces_num == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!faces_mask.is_empty()) {
|
||||
BLI_assert(IN_RANGE_INCL(faces_num_active, 0, faces_num));
|
||||
}
|
||||
else {
|
||||
faces_num_active = faces_num;
|
||||
}
|
||||
|
||||
/* Create a BVH-tree of the given target. */
|
||||
// printf("%s: building BVH, total=%d\n", __func__, numFaces);
|
||||
BVHTree *tree = BLI_bvhtree_new(faces_num_active, epsilon, tree_type, axis);
|
||||
BVHTree *tree = bvhtree_new_commom(epsilon, tree_type, axis, faces_num, faces_num_active);
|
||||
if (!tree) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -989,20 +961,8 @@ static BVHTree *bvhtree_from_editmesh_looptri_create_tree(float epsilon,
|
||||
int looptri_num_active)
|
||||
{
|
||||
const int looptri_num = em->tottri;
|
||||
if (looptri_num == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!looptri_mask.is_empty()) {
|
||||
BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
|
||||
}
|
||||
else {
|
||||
looptri_num_active = looptri_num;
|
||||
}
|
||||
|
||||
/* Create a BVH-tree of the given target */
|
||||
// printf("%s: building BVH, total=%d\n", __func__, numFaces);
|
||||
BVHTree *tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
|
||||
BVHTree *tree = bvhtree_new_commom(epsilon, tree_type, axis, looptri_num, looptri_num_active);
|
||||
if (!tree) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1041,37 +1001,30 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(float epsilon,
|
||||
const BitSpan looptri_mask,
|
||||
int looptri_num_active)
|
||||
{
|
||||
if (!looptri_mask.is_empty()) {
|
||||
BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptris.size()));
|
||||
}
|
||||
else {
|
||||
looptri_num_active = looptris.size();
|
||||
}
|
||||
if (looptri_num_active == 0) {
|
||||
if (positions == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Create a BVH-tree of the given target */
|
||||
// printf("%s: building BVH, total=%d\n", __func__, numFaces);
|
||||
BVHTree *tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
|
||||
BVHTree *tree = bvhtree_new_commom(
|
||||
epsilon, tree_type, axis, looptris.size(), looptri_num_active);
|
||||
|
||||
if (!tree) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (positions && !looptris.is_empty()) {
|
||||
for (const int i : looptris.index_range()) {
|
||||
float co[3][3];
|
||||
if (!looptri_mask.is_empty() && !looptri_mask[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
copy_v3_v3(co[0], positions[corner_verts[looptris[i].tri[0]]]);
|
||||
copy_v3_v3(co[1], positions[corner_verts[looptris[i].tri[1]]]);
|
||||
copy_v3_v3(co[2], positions[corner_verts[looptris[i].tri[2]]]);
|
||||
|
||||
BLI_bvhtree_insert(tree, i, co[0], 3);
|
||||
for (const int i : looptris.index_range()) {
|
||||
float co[3][3];
|
||||
if (!looptri_mask.is_empty() && !looptri_mask[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
copy_v3_v3(co[0], positions[corner_verts[looptris[i].tri[0]]]);
|
||||
copy_v3_v3(co[1], positions[corner_verts[looptris[i].tri[1]]]);
|
||||
copy_v3_v3(co[2], positions[corner_verts[looptris[i].tri[2]]]);
|
||||
|
||||
BLI_bvhtree_insert(tree, i, co[0], 3);
|
||||
}
|
||||
|
||||
BLI_assert(BLI_bvhtree_get_len(tree) == looptri_num_active);
|
||||
|
||||
return tree;
|
||||
@@ -1401,7 +1354,8 @@ BVHTree *BKE_bvhtree_from_pointcloud_get(BVHTreeFromPointCloud *data,
|
||||
const PointCloud *pointcloud,
|
||||
const int tree_type)
|
||||
{
|
||||
BVHTree *tree = BLI_bvhtree_new(pointcloud->totpoint, 0.0f, tree_type, 6);
|
||||
int tot_point = pointcloud->totpoint;
|
||||
BVHTree *tree = bvhtree_new_commom(0.0f, tree_type, 6, tot_point, tot_point);
|
||||
if (!tree) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1410,7 +1364,8 @@ BVHTree *BKE_bvhtree_from_pointcloud_get(BVHTreeFromPointCloud *data,
|
||||
for (const int i : positions.index_range()) {
|
||||
BLI_bvhtree_insert(tree, i, positions[i], 1);
|
||||
}
|
||||
BLI_assert(BLI_bvhtree_get_len(tree) == pointcloud->totpoint);
|
||||
|
||||
BLI_assert(BLI_bvhtree_get_len(tree) == tot_point);
|
||||
bvhtree_balance(tree, false);
|
||||
|
||||
data->coords = (const float(*)[3])positions.data();
|
||||
|
||||
@@ -188,7 +188,8 @@ void BKE_cachefile_reader_open(CacheFile *cache_file,
|
||||
case CACHEFILE_TYPE_ALEMBIC:
|
||||
# ifdef WITH_ALEMBIC
|
||||
/* Open Alembic cache reader. */
|
||||
*reader = CacheReader_open_alembic_object(cache_file->handle, *reader, object, object_path);
|
||||
*reader = CacheReader_open_alembic_object(
|
||||
cache_file->handle, *reader, object, object_path, cache_file->is_sequence);
|
||||
# endif
|
||||
break;
|
||||
case CACHEFILE_TYPE_USD:
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_task.hh"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_timeit.hh"
|
||||
@@ -19,43 +20,14 @@
|
||||
|
||||
namespace blender::bke::calc_edges {
|
||||
|
||||
/** This is used to uniquely identify edges in a hash map. */
|
||||
struct OrderedEdge {
|
||||
int v_low, v_high;
|
||||
|
||||
OrderedEdge(const int v1, const int v2)
|
||||
{
|
||||
if (v1 < v2) {
|
||||
v_low = v1;
|
||||
v_high = v2;
|
||||
}
|
||||
else {
|
||||
v_low = v2;
|
||||
v_high = v1;
|
||||
}
|
||||
}
|
||||
|
||||
OrderedEdge(const uint v1, const uint v2) : OrderedEdge(int(v1), int(v2)) {}
|
||||
|
||||
uint64_t hash() const
|
||||
{
|
||||
return (this->v_low << 8) ^ this->v_high;
|
||||
}
|
||||
|
||||
/** Return a hash value that is likely to be different in the low bits from the normal `hash()`
|
||||
* function. This is necessary to avoid collisions in #BKE_mesh_calc_edges. */
|
||||
uint64_t hash2() const
|
||||
{
|
||||
return this->v_low;
|
||||
}
|
||||
|
||||
friend bool operator==(const OrderedEdge &e1, const OrderedEdge &e2)
|
||||
{
|
||||
BLI_assert(e1.v_low < e1.v_high);
|
||||
BLI_assert(e2.v_low < e2.v_high);
|
||||
return e1.v_low == e2.v_low && e1.v_high == e2.v_high;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Return a hash value that is likely to be different in the low bits from the normal `hash()`
|
||||
* function. This is necessary to avoid collisions in #BKE_mesh_calc_edges.
|
||||
*/
|
||||
static uint64_t edge_hash_2(const OrderedEdge &edge)
|
||||
{
|
||||
return edge.v_low;
|
||||
}
|
||||
|
||||
/* The map first contains an edge pointer and later an index. */
|
||||
union OrigEdgeOrIndex {
|
||||
@@ -84,7 +56,7 @@ static void add_existing_edges_to_hash_maps(Mesh *mesh,
|
||||
for (const int2 &edge : edges) {
|
||||
OrderedEdge ordered_edge{edge[0], edge[1]};
|
||||
/* Only add the edge when it belongs into this map. */
|
||||
if (task_index == (parallel_mask & ordered_edge.hash2())) {
|
||||
if (task_index == (parallel_mask & edge_hash_2(ordered_edge))) {
|
||||
edge_map.add_new(ordered_edge, {&edge});
|
||||
}
|
||||
}
|
||||
@@ -107,7 +79,7 @@ static void add_polygon_edges_to_hash_maps(Mesh *mesh,
|
||||
if (vert_prev != vert) {
|
||||
OrderedEdge ordered_edge{vert_prev, vert};
|
||||
/* Only add the edge when it belongs into this map. */
|
||||
if (task_index == (parallel_mask & ordered_edge.hash2())) {
|
||||
if (task_index == (parallel_mask & edge_hash_2(ordered_edge))) {
|
||||
edge_map.lookup_or_add(ordered_edge, {nullptr});
|
||||
}
|
||||
}
|
||||
@@ -169,7 +141,7 @@ static void update_edge_indices_in_poly_loops(const OffsetIndices<int> polys,
|
||||
if (vert_prev != vert) {
|
||||
OrderedEdge ordered_edge{vert_prev, vert};
|
||||
/* Double lookup: First find the map that contains the edge, then lookup the edge. */
|
||||
const EdgeMap &edge_map = edge_maps[parallel_mask & ordered_edge.hash2()];
|
||||
const EdgeMap &edge_map = edge_maps[parallel_mask & edge_hash_2(ordered_edge)];
|
||||
edge_index = edge_map.lookup(ordered_edge).index;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1449,7 +1449,7 @@ void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh)
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Edge Crease Conversion
|
||||
/** \name Crease Conversion
|
||||
* \{ */
|
||||
|
||||
void BKE_mesh_legacy_edge_crease_from_layers(Mesh *mesh)
|
||||
@@ -1488,6 +1488,40 @@ void BKE_mesh_legacy_edge_crease_to_layers(Mesh *mesh)
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_mesh_crease_layers_from_future(Mesh *mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::bke;
|
||||
if (const std::optional<AttributeMetaData> meta_data = mesh->attributes().lookup_meta_data(
|
||||
"crease_vert"))
|
||||
{
|
||||
if (meta_data->domain == ATTR_DOMAIN_POINT && meta_data->data_type == CD_PROP_FLOAT) {
|
||||
if (const void *data = CustomData_get_layer_named(
|
||||
&mesh->vdata, CD_PROP_FLOAT, "crease_vert")) {
|
||||
if (void *new_data = CustomData_add_layer(
|
||||
&mesh->vdata, CD_CREASE, CD_CONSTRUCT, mesh->totvert)) {
|
||||
memcpy(new_data, data, sizeof(float) * mesh->totvert);
|
||||
CustomData_free_layer_named(&mesh->vdata, "crease_vert", mesh->totvert);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (const std::optional<AttributeMetaData> meta_data = mesh->attributes().lookup_meta_data(
|
||||
"crease_edge"))
|
||||
{
|
||||
if (meta_data->domain == ATTR_DOMAIN_EDGE && meta_data->data_type == CD_PROP_FLOAT) {
|
||||
if (const void *data = CustomData_get_layer_named(
|
||||
&mesh->edata, CD_PROP_FLOAT, "crease_edge")) {
|
||||
if (void *new_data = CustomData_add_layer(
|
||||
&mesh->edata, CD_CREASE, CD_CONSTRUCT, mesh->totedge)) {
|
||||
memcpy(new_data, data, sizeof(float) * mesh->totedge);
|
||||
CustomData_free_layer_named(&mesh->edata, "crease_edge", mesh->totedge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
@@ -1978,8 +1978,11 @@ void BKE_sculpt_update_object_for_edit(
|
||||
sculpt_update_object(depsgraph, ob_orig, ob_eval, need_pmap, is_paint_tool);
|
||||
}
|
||||
|
||||
int *BKE_sculpt_face_sets_ensure(Mesh *mesh)
|
||||
int *BKE_sculpt_face_sets_ensure(Object *ob)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
||||
|
||||
using namespace blender;
|
||||
using namespace blender::bke;
|
||||
MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
@@ -1991,8 +1994,14 @@ int *BKE_sculpt_face_sets_ensure(Mesh *mesh)
|
||||
face_sets.finish();
|
||||
}
|
||||
|
||||
return static_cast<int *>(CustomData_get_layer_named_for_write(
|
||||
int *face_sets = static_cast<int *>(CustomData_get_layer_named_for_write(
|
||||
&mesh->pdata, CD_PROP_INT32, ".sculpt_face_set", mesh->totpoly));
|
||||
|
||||
if (ss->pbvh && ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_GRIDS)) {
|
||||
BKE_pbvh_face_sets_set(ss->pbvh, face_sets);
|
||||
}
|
||||
|
||||
return face_sets;
|
||||
}
|
||||
|
||||
bool *BKE_sculpt_hide_poly_ensure(Mesh *mesh)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_pointcloud_types.h"
|
||||
|
||||
#include "BLI_binary_search.hh"
|
||||
#include "BLI_fileops.hh"
|
||||
#include "BLI_hash_md5.h"
|
||||
#include "BLI_path_util.h"
|
||||
@@ -86,22 +87,40 @@ void ModifierSimulationCache::try_discover_bake(const StringRefNull absolute_bak
|
||||
new_state_at_frame->state.owner_ = this;
|
||||
states_at_frames_.append(std::move(new_state_at_frame));
|
||||
}
|
||||
|
||||
bdata_sharing_ = std::make_unique<BDataSharing>();
|
||||
cache_state_ = CacheState::Baked;
|
||||
}
|
||||
}
|
||||
|
||||
bdata_sharing_ = std::make_unique<BDataSharing>();
|
||||
static int64_t find_state_at_frame(
|
||||
const Span<std::unique_ptr<ModifierSimulationStateAtFrame>> states, const SubFrame &frame)
|
||||
{
|
||||
const int64_t i = binary_search::find_predicate_begin(
|
||||
states, [&](const auto &item) { return item->frame >= frame; });
|
||||
if (i == states.size()) {
|
||||
return -1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
cache_state_ = CacheState::Baked;
|
||||
static int64_t find_state_at_frame_exact(
|
||||
const Span<std::unique_ptr<ModifierSimulationStateAtFrame>> states, const SubFrame &frame)
|
||||
{
|
||||
const int64_t i = find_state_at_frame(states, frame);
|
||||
if (i == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (states[i]->frame != frame) {
|
||||
return -1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
bool ModifierSimulationCache::has_state_at_frame(const SubFrame &frame) const
|
||||
{
|
||||
std::lock_guard lock(states_at_frames_mutex_);
|
||||
for (const auto &item : states_at_frames_) {
|
||||
if (item->frame == frame) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return find_state_at_frame_exact(states_at_frames_, frame) != -1;
|
||||
}
|
||||
|
||||
bool ModifierSimulationCache::has_states() const
|
||||
@@ -114,23 +133,26 @@ const ModifierSimulationState *ModifierSimulationCache::get_state_at_exact_frame
|
||||
const SubFrame &frame) const
|
||||
{
|
||||
std::lock_guard lock(states_at_frames_mutex_);
|
||||
for (const auto &item : states_at_frames_) {
|
||||
if (item->frame == frame) {
|
||||
return &item->state;
|
||||
}
|
||||
const int64_t i = find_state_at_frame_exact(states_at_frames_, frame);
|
||||
if (i == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
return &states_at_frames_[i]->state;
|
||||
}
|
||||
|
||||
ModifierSimulationState &ModifierSimulationCache::get_state_at_frame_for_write(
|
||||
const SubFrame &frame)
|
||||
{
|
||||
std::lock_guard lock(states_at_frames_mutex_);
|
||||
for (const auto &item : states_at_frames_) {
|
||||
if (item->frame == frame) {
|
||||
return item->state;
|
||||
}
|
||||
const int64_t i = find_state_at_frame_exact(states_at_frames_, frame);
|
||||
if (i != -1) {
|
||||
return states_at_frames_[i]->state;
|
||||
}
|
||||
|
||||
if (!states_at_frames_.is_empty()) {
|
||||
BLI_assert(frame > states_at_frames_.last()->frame);
|
||||
}
|
||||
|
||||
states_at_frames_.append(std::make_unique<ModifierSimulationStateAtFrame>());
|
||||
states_at_frames_.last()->frame = frame;
|
||||
states_at_frames_.last()->state.owner_ = this;
|
||||
@@ -140,23 +162,22 @@ ModifierSimulationState &ModifierSimulationCache::get_state_at_frame_for_write(
|
||||
StatesAroundFrame ModifierSimulationCache::get_states_around_frame(const SubFrame &frame) const
|
||||
{
|
||||
std::lock_guard lock(states_at_frames_mutex_);
|
||||
StatesAroundFrame states_around_frame;
|
||||
for (const auto &item : states_at_frames_) {
|
||||
if (item->frame < frame) {
|
||||
if (states_around_frame.prev == nullptr || item->frame > states_around_frame.prev->frame) {
|
||||
states_around_frame.prev = item.get();
|
||||
}
|
||||
}
|
||||
if (item->frame == frame) {
|
||||
if (states_around_frame.current == nullptr) {
|
||||
states_around_frame.current = item.get();
|
||||
}
|
||||
}
|
||||
if (item->frame > frame) {
|
||||
if (states_around_frame.next == nullptr || item->frame < states_around_frame.next->frame) {
|
||||
states_around_frame.next = item.get();
|
||||
}
|
||||
const int64_t i = find_state_at_frame(states_at_frames_, frame);
|
||||
StatesAroundFrame states_around_frame{};
|
||||
if (i == -1) {
|
||||
if (!states_at_frames_.is_empty() && states_at_frames_.last()->frame < frame) {
|
||||
states_around_frame.prev = states_at_frames_.last().get();
|
||||
}
|
||||
return states_around_frame;
|
||||
}
|
||||
if (states_at_frames_[i]->frame == frame) {
|
||||
states_around_frame.current = states_at_frames_[i].get();
|
||||
}
|
||||
if (i > 0) {
|
||||
states_around_frame.prev = states_at_frames_[i - 1].get();
|
||||
}
|
||||
if (i < states_at_frames_.size() - 2) {
|
||||
states_around_frame.next = states_at_frames_[i + 1].get();
|
||||
}
|
||||
return states_around_frame;
|
||||
}
|
||||
|
||||
@@ -819,20 +819,6 @@ void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated)
|
||||
AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, sound_cfra, &pitch, animated);
|
||||
}
|
||||
|
||||
void BKE_sound_set_scene_sound_pitch_at_frame(void *handle, int frame, float pitch, char animated)
|
||||
{
|
||||
AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, frame, &pitch, animated);
|
||||
}
|
||||
|
||||
void BKE_sound_set_scene_sound_pitch_constant_range(void *handle,
|
||||
int frame_start,
|
||||
int frame_end,
|
||||
float pitch)
|
||||
{
|
||||
AUD_SequenceEntry_setConstantRangeAnimationData(
|
||||
handle, AUD_AP_PITCH, frame_start, frame_end, &pitch);
|
||||
}
|
||||
|
||||
void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated)
|
||||
{
|
||||
AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated);
|
||||
@@ -1384,18 +1370,6 @@ void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle),
|
||||
char UNUSED(animated))
|
||||
{
|
||||
}
|
||||
void BKE_sound_set_scene_sound_pitch_at_frame(void *UNUSED(handle),
|
||||
int UNUSED(frame),
|
||||
float UNUSED(pitch),
|
||||
char UNUSED(animated))
|
||||
{
|
||||
}
|
||||
void BKE_sound_set_scene_sound_pitch_constant_range(void *UNUSED(handle),
|
||||
int UNUSED(frame_start),
|
||||
int UNUSED(frame_end),
|
||||
float UNUSED(pitch))
|
||||
{
|
||||
}
|
||||
float BKE_sound_get_length(struct Main *UNUSED(bmain), bSound *UNUSED(sound))
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -82,7 +82,10 @@ static int append_avi(void *context_v,
|
||||
int recty,
|
||||
const char *suffix,
|
||||
ReportList *reports);
|
||||
static void filepath_avi(char *string, const RenderData *rd, bool preview, const char *suffix);
|
||||
static void filepath_avi(char filepath[FILE_MAX],
|
||||
const RenderData *rd,
|
||||
bool preview,
|
||||
const char *suffix);
|
||||
static void *context_create_avi(void);
|
||||
static void context_free_avi(void *context_v);
|
||||
#endif /* WITH_AVI */
|
||||
@@ -140,7 +143,10 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
|
||||
|
||||
#ifdef WITH_AVI
|
||||
|
||||
static void filepath_avi(char *filepath, const RenderData *rd, bool preview, const char *suffix)
|
||||
static void filepath_avi(char filepath[FILE_MAX],
|
||||
const RenderData *rd,
|
||||
bool preview,
|
||||
const char *suffix)
|
||||
{
|
||||
int sfra, efra;
|
||||
|
||||
@@ -157,7 +163,7 @@ static void filepath_avi(char *filepath, const RenderData *rd, bool preview, con
|
||||
efra = rd->efra;
|
||||
}
|
||||
|
||||
strcpy(filepath, rd->pic);
|
||||
BLI_strncpy(filepath, rd->pic, FILE_MAX);
|
||||
BLI_path_abs(filepath, BKE_main_blendfile_path_from_global());
|
||||
|
||||
BLI_file_ensure_parent_dir_exists(filepath);
|
||||
@@ -187,13 +193,13 @@ static int start_avi(void *context_v,
|
||||
const char *suffix)
|
||||
{
|
||||
int x, y;
|
||||
char name[256];
|
||||
char filepath[FILE_MAX];
|
||||
AviFormat format;
|
||||
int quality;
|
||||
double framerate;
|
||||
AviMovie *avi = context_v;
|
||||
|
||||
filepath_avi(name, rd, preview, suffix);
|
||||
filepath_avi(filepath, rd, preview, suffix);
|
||||
|
||||
x = rectx;
|
||||
y = recty;
|
||||
@@ -208,7 +214,7 @@ static int start_avi(void *context_v,
|
||||
format = AVI_FORMAT_MJPEG;
|
||||
}
|
||||
|
||||
if (AVI_open_compress(name, avi, 1, format) != AVI_ERROR_NONE) {
|
||||
if (AVI_open_compress(filepath, avi, 1, format) != AVI_ERROR_NONE) {
|
||||
BKE_report(reports, RPT_ERROR, "Cannot open or start AVI movie file");
|
||||
return 0;
|
||||
}
|
||||
@@ -221,7 +227,7 @@ static int start_avi(void *context_v,
|
||||
avi->interlace = 0;
|
||||
avi->odd_fields = 0;
|
||||
|
||||
printf("Created avi: %s\n", name);
|
||||
printf("Created avi: %s\n", filepath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -297,7 +303,10 @@ static void context_free_avi(void *context_v)
|
||||
|
||||
#endif /* WITH_AVI */
|
||||
|
||||
void BKE_movie_filepath_get(char *filepath, const RenderData *rd, bool preview, const char *suffix)
|
||||
void BKE_movie_filepath_get(char filepath[/*FILE_MAX*/ 1024],
|
||||
const RenderData *rd,
|
||||
bool preview,
|
||||
const char *suffix)
|
||||
{
|
||||
bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
|
||||
if (mh && mh->get_movie_path) {
|
||||
|
||||
@@ -1426,7 +1426,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context,
|
||||
BLI_path_suffix(string, FILE_MAX, suffix, "");
|
||||
}
|
||||
|
||||
void BKE_ffmpeg_filepath_get(char *filepath,
|
||||
void BKE_ffmpeg_filepath_get(char filepath[/*FILE_MAX*/ 1024],
|
||||
const RenderData *rd,
|
||||
bool preview,
|
||||
const char *suffix)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup bli
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
namespace blender::binary_search {
|
||||
|
||||
/**
|
||||
* Find the index of the first element where the predicate is true. The predicate must also be
|
||||
* true for all following elements. If the predicate is false for all elements, the size of the
|
||||
* range is returned.
|
||||
*/
|
||||
template<typename Iterator, typename Predicate>
|
||||
int64_t find_predicate_begin(Iterator begin, Iterator end, Predicate &&predicate)
|
||||
{
|
||||
return std::lower_bound(begin,
|
||||
end,
|
||||
nullptr,
|
||||
[&](const auto &value, void * /*dummy*/) { return !predicate(value); }) -
|
||||
begin;
|
||||
}
|
||||
|
||||
template<typename Range, typename Predicate>
|
||||
int64_t find_predicate_begin(const Range &range, Predicate &&predicate)
|
||||
{
|
||||
return find_predicate_begin(range.begin(), range.end(), predicate);
|
||||
}
|
||||
|
||||
} // namespace blender::binary_search
|
||||
@@ -0,0 +1,47 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
/**
|
||||
* A version of `int2` used as a key for hash-maps, agnostic of the arbitrary order of the two
|
||||
* vertices in a mesh edge.
|
||||
*/
|
||||
struct OrderedEdge {
|
||||
int v_low;
|
||||
int v_high;
|
||||
|
||||
OrderedEdge(const int v1, const int v2)
|
||||
{
|
||||
if (v1 < v2) {
|
||||
v_low = v1;
|
||||
v_high = v2;
|
||||
}
|
||||
else {
|
||||
v_low = v2;
|
||||
v_high = v1;
|
||||
}
|
||||
}
|
||||
OrderedEdge(const int2 edge) : OrderedEdge(edge[0], edge[1]) {}
|
||||
OrderedEdge(const uint v1, const uint v2) : OrderedEdge(int(v1), int(v2)) {}
|
||||
|
||||
uint64_t hash() const
|
||||
{
|
||||
return (this->v_low << 8) ^ this->v_high;
|
||||
}
|
||||
|
||||
friend bool operator==(const OrderedEdge &e1, const OrderedEdge &e2)
|
||||
{
|
||||
BLI_assert(e1.v_low < e1.v_high);
|
||||
BLI_assert(e2.v_low < e2.v_high);
|
||||
return e1.v_low == e2.v_low && e1.v_high == e2.v_high;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender
|
||||
@@ -182,6 +182,7 @@ set(SRC
|
||||
BLI_assert.h
|
||||
BLI_astar.h
|
||||
BLI_atomic_disjoint_set.hh
|
||||
BLI_binary_search.hh
|
||||
BLI_bit_group_vector.hh
|
||||
BLI_bit_ref.hh
|
||||
BLI_bit_span.hh
|
||||
@@ -318,6 +319,7 @@ set(SRC
|
||||
BLI_noise.h
|
||||
BLI_noise.hh
|
||||
BLI_offset_indices.hh
|
||||
BLI_ordered_edge.hh
|
||||
BLI_parameter_pack_utils.hh
|
||||
BLI_path_util.h
|
||||
BLI_polyfill_2d.h
|
||||
|
||||
@@ -116,7 +116,7 @@ int BLI_path_sequence_decode(const char *path,
|
||||
if (head) {
|
||||
/* Name_end points to last character of head,
|
||||
* make it +1 so null-terminator is nicely placed. */
|
||||
BLI_strncpy(head, path, name_end + 1);
|
||||
BLI_strncpy(head, path, MIN2(head_maxncpy, name_end + 1));
|
||||
}
|
||||
if (r_digits_len) {
|
||||
*r_digits_len = 0;
|
||||
|
||||
@@ -181,6 +181,8 @@ void BLO_blendfiledata_free(BlendFileData *bfd);
|
||||
typedef struct BLODataBlockInfo {
|
||||
char name[64]; /* MAX_NAME */
|
||||
struct AssetMetaData *asset_data;
|
||||
/** Ownership over #asset_data above can be "stolen out" of this struct, for more permanent
|
||||
* storage. In that case, set this to false to avoid double freeing of the stolen data. */
|
||||
bool free_asset_data;
|
||||
/* Optimization: Tag data-blocks for which we know there is no preview.
|
||||
* Knowing this can be used to skip the (potentially expensive) preview loading process. If this
|
||||
|
||||
@@ -82,7 +82,6 @@
|
||||
#include "SEQ_channels.h"
|
||||
#include "SEQ_effects.h"
|
||||
#include "SEQ_iterator.h"
|
||||
#include "SEQ_retiming.h"
|
||||
#include "SEQ_sequencer.h"
|
||||
#include "SEQ_time.h"
|
||||
|
||||
@@ -697,25 +696,6 @@ static bool seq_speed_factor_set(Sequence *seq, void *user_data)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_versions_sequencer_init_retiming_tool_data(Sequence *seq, void *user_data)
|
||||
{
|
||||
const Scene *scene = static_cast<const Scene *>(user_data);
|
||||
|
||||
if (seq->speed_factor == 1 || !SEQ_retiming_is_allowed(seq)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const int content_length = SEQ_time_strip_length_get(scene, seq);
|
||||
|
||||
SEQ_retiming_data_ensure(seq);
|
||||
|
||||
SeqRetimingHandle *handle = &seq->retiming_handles[seq->retiming_handle_num - 1];
|
||||
handle->strip_frame_index = round_fl_to_int(content_length / seq->speed_factor);
|
||||
seq->speed_factor = 1.0f;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void version_geometry_nodes_replace_transfer_attribute_node(bNodeTree *ntree)
|
||||
{
|
||||
using namespace blender;
|
||||
@@ -1362,18 +1342,6 @@ void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain)
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 306, 6)) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
Editing *ed = SEQ_editing_get(scene);
|
||||
if (ed == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SEQ_for_each_callback(
|
||||
&scene->ed->seqbase, do_versions_sequencer_init_retiming_tool_data, scene);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
@@ -1800,7 +1768,6 @@ static bool version_seq_fix_broken_sound_strips(Sequence *seq, void * /*user_dat
|
||||
}
|
||||
|
||||
seq->speed_factor = 1.0f;
|
||||
SEQ_retiming_data_clear(seq);
|
||||
seq->startofs = 0.0f;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ static void version_mesh_legacy_to_struct_of_array_format(Mesh &mesh)
|
||||
BKE_mesh_legacy_convert_polys_to_offsets(&mesh);
|
||||
BKE_mesh_legacy_convert_edges_to_generic(&mesh);
|
||||
BKE_mesh_bevel_weight_layers_from_future(&mesh);
|
||||
BKE_mesh_crease_layers_from_future(&mesh);
|
||||
}
|
||||
|
||||
static void version_motion_tracking_legacy_camera_object(MovieClip &movieclip)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_collection.h"
|
||||
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
@@ -182,6 +183,14 @@ void deg_graph_build_finalize(Main *bmain, Depsgraph *graph)
|
||||
flag |= ID_RECALC_NTREE_OUTPUT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Collection content might have changed (children collection might have been added or
|
||||
* removed from the graph based on their inclusion and visibility flags). */
|
||||
const ID_Type id_type = GS(id_node->id_cow->name);
|
||||
if (id_type == ID_GR) {
|
||||
BKE_collection_object_cache_free(reinterpret_cast<Collection *>(id_node->id_cow));
|
||||
}
|
||||
}
|
||||
/* Restore recalc flags from original ID, which could possibly contain recalc flags set by
|
||||
* an operator and then were carried on by the undo system. */
|
||||
flag |= id_orig->recalc;
|
||||
|
||||
@@ -914,9 +914,8 @@ void DepsgraphNodeBuilder::build_object_modifiers(Object *object)
|
||||
return;
|
||||
}
|
||||
if (modifier_node->flag & DEPSOP_FLAG_USER_MODIFIED) {
|
||||
if (nmd->simulation_cache &&
|
||||
nmd->simulation_cache->cache_state() == bke::sim::CacheState::Valid) {
|
||||
nmd->simulation_cache->invalidate();
|
||||
if (nmd->simulation_cache->ptr->cache_state() == bke::sim::CacheState::Valid) {
|
||||
nmd->simulation_cache->ptr->invalidate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -265,7 +265,7 @@ static bool need_extra_redraw_after_scrubbing_ends(bContext *C)
|
||||
return true;
|
||||
}
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
if (scene->eevee.flag & SCE_EEVEE_TAA_REPROJECTION) {
|
||||
if (scene->eevee.taa_samples != 1) {
|
||||
return true;
|
||||
}
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
|
||||
@@ -872,7 +872,6 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
|
||||
ops.sculpt.mask_by_color
|
||||
ops.sculpt.mesh_filter
|
||||
ops.sequencer.blade
|
||||
ops.sequencer.retime
|
||||
ops.transform.bone_envelope
|
||||
ops.transform.bone_size
|
||||
ops.transform.edge_slide
|
||||
|
||||
@@ -346,72 +346,19 @@ static bool *gpencil_vgroup_bone_deformed_map_get(Object *ob, const int defbase_
|
||||
* for points in vertex groups deformed by bones.
|
||||
* The logic is copied from `editors/sculpt_paint/paint_vertex.cc`. */
|
||||
|
||||
/**
|
||||
* Normalize weights of a stroke point deformed by bones.
|
||||
*/
|
||||
static void do_weight_paint_normalize_all(MDeformVert *dvert,
|
||||
const int defbase_tot,
|
||||
const bool *vgroup_bone_deformed)
|
||||
{
|
||||
float sum = 0.0f, fac;
|
||||
uint tot = 0;
|
||||
MDeformWeight *dw;
|
||||
|
||||
dw = dvert->dw;
|
||||
for (int i = dvert->totweight; i != 0; i--, dw++) {
|
||||
if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) {
|
||||
tot++;
|
||||
sum += dw->weight;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tot == 0) || (sum == 1.0f)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sum != 0.0f) {
|
||||
fac = 1.0f / sum;
|
||||
|
||||
dw = dvert->dw;
|
||||
for (int i = dvert->totweight; i != 0; i--, dw++) {
|
||||
if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) {
|
||||
dw->weight *= fac;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
fac = 1.0f / tot;
|
||||
|
||||
dw = dvert->dw;
|
||||
for (int i = dvert->totweight; i != 0; i--, dw++) {
|
||||
if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) {
|
||||
dw->weight = fac;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #do_weight_paint_normalize_all that only changes unlocked weights.
|
||||
*/
|
||||
static bool do_weight_paint_normalize_all_unlocked(MDeformVert *dvert,
|
||||
const int defbase_tot,
|
||||
const bool *vgroup_bone_deformed,
|
||||
const bool *vgroup_locked,
|
||||
const bool lock_active_vgroup,
|
||||
const int active_vgroup)
|
||||
static bool do_weight_paint_normalize(MDeformVert *dvert,
|
||||
const int defbase_tot,
|
||||
const bool *vgroup_bone_deformed,
|
||||
const bool *vgroup_locked,
|
||||
const bool lock_active_vgroup,
|
||||
const int active_vgroup)
|
||||
{
|
||||
float sum = 0.0f, fac;
|
||||
float sum_unlock = 0.0f;
|
||||
float sum_lock = 0.0f;
|
||||
uint tot = 0;
|
||||
uint lock_tot = 0, unlock_tot = 0;
|
||||
MDeformWeight *dw;
|
||||
|
||||
if (vgroup_locked == NULL) {
|
||||
do_weight_paint_normalize_all(dvert, defbase_tot, vgroup_bone_deformed);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dvert->totweight <= 1) {
|
||||
return true;
|
||||
}
|
||||
@@ -423,10 +370,11 @@ static bool do_weight_paint_normalize_all_unlocked(MDeformVert *dvert,
|
||||
sum += dw->weight;
|
||||
|
||||
if (vgroup_locked[dw->def_nr] || (lock_active_vgroup && active_vgroup == dw->def_nr)) {
|
||||
lock_tot++;
|
||||
sum_lock += dw->weight;
|
||||
}
|
||||
else {
|
||||
tot++;
|
||||
unlock_tot++;
|
||||
sum_unlock += dw->weight;
|
||||
}
|
||||
}
|
||||
@@ -436,8 +384,10 @@ static bool do_weight_paint_normalize_all_unlocked(MDeformVert *dvert,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tot == 0) {
|
||||
return false;
|
||||
if (unlock_tot == 0) {
|
||||
/* There are no unlocked vertex groups to normalize. We don't need
|
||||
* a second pass when there is only one locked group (the active group). */
|
||||
return (lock_tot == 1);
|
||||
}
|
||||
|
||||
if (sum_lock >= 1.0f - VERTEX_WEIGHT_LOCK_EPSILON) {
|
||||
@@ -445,7 +395,6 @@ static bool do_weight_paint_normalize_all_unlocked(MDeformVert *dvert,
|
||||
* zero out what we can and return false. */
|
||||
dw = dvert->dw;
|
||||
for (int i = dvert->totweight; i != 0; i--, dw++) {
|
||||
*dw = dvert->dw[i];
|
||||
if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) {
|
||||
if ((vgroup_locked[dw->def_nr] == false) &&
|
||||
!(lock_active_vgroup && active_vgroup == dw->def_nr)) {
|
||||
@@ -472,7 +421,7 @@ static bool do_weight_paint_normalize_all_unlocked(MDeformVert *dvert,
|
||||
}
|
||||
}
|
||||
else {
|
||||
fac = (1.0f - sum_lock) / tot;
|
||||
fac = (1.0f - sum_lock) / unlock_tot;
|
||||
CLAMP(fac, 0.0f, 1.0f);
|
||||
|
||||
dw = dvert->dw;
|
||||
@@ -491,18 +440,18 @@ static bool do_weight_paint_normalize_all_unlocked(MDeformVert *dvert,
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #do_weight_paint_normalize_all that only changes unlocked weights
|
||||
* A version of #do_weight_paint_normalize that only changes unlocked weights
|
||||
* and does a second pass without the active vertex group locked when the first pass fails.
|
||||
*/
|
||||
static void do_weight_paint_normalize_all_try(MDeformVert *dvert, tGP_BrushWeightpaintData *gso)
|
||||
static void do_weight_paint_normalize_try(MDeformVert *dvert, tGP_BrushWeightpaintData *gso)
|
||||
{
|
||||
/* First pass with both active and explicitly locked vertex groups restricted from change. */
|
||||
bool succes = do_weight_paint_normalize_all_unlocked(
|
||||
bool succes = do_weight_paint_normalize(
|
||||
dvert, gso->vgroup_tot, gso->vgroup_bone_deformed, gso->vgroup_locked, true, gso->vrgroup);
|
||||
|
||||
if (!succes) {
|
||||
/* Second pass with active vertex group unlocked. */
|
||||
do_weight_paint_normalize_all_unlocked(
|
||||
do_weight_paint_normalize(
|
||||
dvert, gso->vgroup_tot, gso->vgroup_bone_deformed, gso->vgroup_locked, false, -1);
|
||||
}
|
||||
}
|
||||
@@ -584,7 +533,7 @@ static bool brush_draw_apply(tGP_BrushWeightpaintData *gso,
|
||||
|
||||
/* Perform auto-normalize. */
|
||||
if (gso->auto_normalize) {
|
||||
do_weight_paint_normalize_all_try(dvert, gso);
|
||||
do_weight_paint_normalize_try(dvert, gso);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -614,7 +563,7 @@ static bool brush_average_apply(tGP_BrushWeightpaintData *gso,
|
||||
|
||||
/* Perform auto-normalize. */
|
||||
if (gso->auto_normalize) {
|
||||
do_weight_paint_normalize_all_try(dvert, gso);
|
||||
do_weight_paint_normalize_try(dvert, gso);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -666,7 +615,7 @@ static bool brush_blur_apply(tGP_BrushWeightpaintData *gso,
|
||||
|
||||
/* Perform auto-normalize. */
|
||||
if (gso->auto_normalize) {
|
||||
do_weight_paint_normalize_all_try(dvert, gso);
|
||||
do_weight_paint_normalize_try(dvert, gso);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -748,7 +697,7 @@ static bool brush_smear_apply(tGP_BrushWeightpaintData *gso,
|
||||
|
||||
/* Perform auto-normalize. */
|
||||
if (gso->auto_normalize) {
|
||||
do_weight_paint_normalize_all_try(dvert, gso);
|
||||
do_weight_paint_normalize_try(dvert, gso);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -127,10 +127,13 @@ void ED_file_indexer_entries_clear(FileIndexerEntries *indexer_entries);
|
||||
* Adds all entries from the given `datablock_infos` to the `indexer_entries`.
|
||||
* The datablock_infos must only contain data for a single IDType. The specific IDType must be
|
||||
* passed in the `idcode` parameter.
|
||||
*
|
||||
* \note This can "steal" data contained in \a datablock_infos, to avoid expensive copies, which is
|
||||
* supported by the #BLODataBlockInfo type.
|
||||
*/
|
||||
void ED_file_indexer_entries_extend_from_datablock_infos(
|
||||
FileIndexerEntries *indexer_entries,
|
||||
const LinkNode * /*BLODataBlockInfo*/ datablock_infos,
|
||||
struct LinkNode * /*BLODataBlockInfo*/ datablock_infos,
|
||||
int idcode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_blendfile.h"
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_colorband.h"
|
||||
#include "BKE_colortools.h"
|
||||
#include "BKE_constraint.h"
|
||||
@@ -65,6 +66,7 @@
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_build.h"
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "ED_fileselect.h"
|
||||
#include "ED_object.h"
|
||||
@@ -6804,8 +6806,16 @@ void uiTemplateCacheFileProcedural(uiLayout *layout, const bContext *C, PointerR
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type,
|
||||
scene);
|
||||
CacheFile *cache_file = static_cast<CacheFile *>(fileptr->data);
|
||||
CacheFile *cache_file_eval = reinterpret_cast<CacheFile *>(
|
||||
DEG_get_evaluated_id(CTX_data_depsgraph_pointer(C), &cache_file->id));
|
||||
bool is_alembic = cache_file_eval->type == CACHEFILE_TYPE_ALEMBIC;
|
||||
|
||||
if (!engine_supports_procedural) {
|
||||
if (!is_alembic) {
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiItemL(row, TIP_("Only Alembic Procedurals supported"), ICON_INFO);
|
||||
}
|
||||
else if (!engine_supports_procedural) {
|
||||
row = uiLayoutRow(layout, false);
|
||||
/* For Cycles, verify that experimental features are enabled. */
|
||||
if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) {
|
||||
@@ -6822,7 +6832,7 @@ void uiTemplateCacheFileProcedural(uiLayout *layout, const bContext *C, PointerR
|
||||
}
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiLayoutSetActive(row, engine_supports_procedural);
|
||||
uiLayoutSetActive(row, is_alembic && engine_supports_procedural);
|
||||
uiItemR(row, fileptr, "use_render_procedural", 0, nullptr, ICON_NONE);
|
||||
|
||||
const bool use_render_procedural = RNA_boolean_get(fileptr, "use_render_procedural");
|
||||
|
||||
@@ -3728,12 +3728,13 @@ static bool knife_snap_angle_relative(KnifeTool_OpData *kcd)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Re-calculate current ray in object space. */
|
||||
knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, curr_origin, curr_origin_ofs);
|
||||
sub_v3_v3v3(curr_ray, curr_origin_ofs, curr_origin);
|
||||
normalize_v3_v3(curr_ray_normal, curr_ray);
|
||||
/* Use normal global direction. */
|
||||
float no_global[3];
|
||||
copy_v3_v3(no_global, fprev->no);
|
||||
mul_transposed_mat3_m4_v3(kcd->curr.ob->world_to_object, no_global);
|
||||
normalize_v3(no_global);
|
||||
|
||||
plane_from_point_normal_v3(plane, kcd->prev.cage, fprev->no);
|
||||
plane_from_point_normal_v3(plane, kcd->prev.cage, no_global);
|
||||
|
||||
if (isect_ray_plane_v3(curr_origin, curr_ray_normal, plane, &lambda, false)) {
|
||||
madd_v3_v3v3fl(ray_hit, curr_origin, curr_ray_normal, lambda);
|
||||
@@ -3755,7 +3756,7 @@ static bool knife_snap_angle_relative(KnifeTool_OpData *kcd)
|
||||
/* Maybe check for vectors being zero here? */
|
||||
sub_v3_v3v3(v1, ray_hit, kcd->prev.cage);
|
||||
copy_v3_v3(v2, refv);
|
||||
kcd->angle = snap_v3_angle_plane(rotated_vec, v1, v2, fprev->no, snap_step);
|
||||
kcd->angle = snap_v3_angle_plane(rotated_vec, v1, v2, no_global, snap_step);
|
||||
add_v3_v3(rotated_vec, kcd->prev.cage);
|
||||
|
||||
knife_project_v2(kcd, rotated_vec, kcd->curr.mval);
|
||||
|
||||
@@ -49,6 +49,10 @@
|
||||
|
||||
#include "object_intern.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
namespace blender::ed::object::bake_simulation {
|
||||
|
||||
static bool calculate_to_frame_poll(bContext *C)
|
||||
@@ -89,9 +93,7 @@ static void calculate_simulation_job_startjob(void *customdata,
|
||||
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
|
||||
if (md->type == eModifierType_Nodes) {
|
||||
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
||||
if (nmd->simulation_cache != nullptr) {
|
||||
nmd->simulation_cache->reset();
|
||||
}
|
||||
nmd->simulation_cache->ptr->reset();
|
||||
}
|
||||
}
|
||||
objects_to_calc.append(object);
|
||||
@@ -251,13 +253,7 @@ static void bake_simulation_job_startjob(void *customdata,
|
||||
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
|
||||
if (md->type == eModifierType_Nodes) {
|
||||
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
||||
if (nmd->simulation_cache != nullptr) {
|
||||
nmd->simulation_cache->reset();
|
||||
}
|
||||
if (StringRef(nmd->simulation_bake_directory).is_empty()) {
|
||||
nmd->simulation_bake_directory = BLI_strdup(
|
||||
bke::sim::get_default_modifier_bake_directory(*job.bmain, *object, *md).c_str());
|
||||
}
|
||||
nmd->simulation_cache->ptr->reset();
|
||||
char absolute_bake_dir[FILE_MAX];
|
||||
STRNCPY(absolute_bake_dir, nmd->simulation_bake_directory);
|
||||
BLI_path_abs(absolute_bake_dir, base_path);
|
||||
@@ -299,7 +295,7 @@ static void bake_simulation_job_startjob(void *customdata,
|
||||
if (nmd.simulation_cache == nullptr) {
|
||||
continue;
|
||||
}
|
||||
ModifierSimulationCache &sim_cache = *nmd.simulation_cache;
|
||||
ModifierSimulationCache &sim_cache = *nmd.simulation_cache->ptr;
|
||||
const ModifierSimulationState *sim_state = sim_cache.get_state_at_exact_frame(frame);
|
||||
if (sim_state == nullptr || sim_state->zone_states_.is_empty()) {
|
||||
continue;
|
||||
@@ -343,7 +339,7 @@ static void bake_simulation_job_startjob(void *customdata,
|
||||
NodesModifierData &nmd = *modifier_bake_data.nmd;
|
||||
if (nmd.simulation_cache) {
|
||||
/* Tag the caches as being baked so that they are not changed anymore. */
|
||||
nmd.simulation_cache->cache_state_ = CacheState::Baked;
|
||||
nmd.simulation_cache->ptr->cache_state_ = CacheState::Baked;
|
||||
}
|
||||
}
|
||||
DEG_id_tag_update(&object_bake_data.object->id, ID_RECALC_GEOMETRY);
|
||||
@@ -364,7 +360,7 @@ static void bake_simulation_job_endjob(void *customdata)
|
||||
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, nullptr);
|
||||
}
|
||||
|
||||
static int bake_simulation_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
static int bake_simulation_execute(bContext *C, wmOperator *op)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
@@ -407,6 +403,160 @@ static int bake_simulation_invoke(bContext *C, wmOperator *op, const wmEvent * /
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
struct PathStringHash {
|
||||
uint64_t operator()(const StringRef s) const
|
||||
{
|
||||
/* Normalize the paths so we can compare them. */
|
||||
DynamicStackBuffer<256> norm_buf(s.size() + 1, 8);
|
||||
memcpy(norm_buf.buffer(), s.data(), s.size() + 1);
|
||||
char *norm = static_cast<char *>(norm_buf.buffer());
|
||||
|
||||
BLI_path_slash_native(norm);
|
||||
|
||||
/* Strip ending slash. */
|
||||
BLI_path_slash_rstrip(norm);
|
||||
|
||||
BLI_path_normalize(norm);
|
||||
return get_default_hash(norm);
|
||||
}
|
||||
};
|
||||
|
||||
struct PathStringEquality {
|
||||
bool operator()(const StringRef a, const StringRef b) const
|
||||
{
|
||||
return BLI_path_cmp_normalized(a.data(), b.data()) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
static bool bake_directory_has_data(const StringRefNull absolute_bake_dir)
|
||||
{
|
||||
char meta_dir[FILE_MAX];
|
||||
BLI_path_join(meta_dir, sizeof(meta_dir), absolute_bake_dir.c_str(), "meta");
|
||||
char bdata_dir[FILE_MAX];
|
||||
BLI_path_join(bdata_dir, sizeof(bdata_dir), absolute_bake_dir.c_str(), "bdata");
|
||||
|
||||
if (!BLI_is_dir(meta_dir) || !BLI_is_dir(bdata_dir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bake_simulation_validate_paths(bContext *C,
|
||||
wmOperator *op,
|
||||
const Span<Object *> objects)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
for (Object *object : objects) {
|
||||
if (!BKE_id_is_editable(bmain, &object->id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
|
||||
if (md->type != eModifierType_Nodes) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
||||
if (StringRef(nmd->simulation_bake_directory).is_empty()) {
|
||||
BKE_reportf(op->reports,
|
||||
RPT_INFO,
|
||||
"Bake directory of object %s, modifier %s is empty, setting default path",
|
||||
object->id.name + 2,
|
||||
md->name);
|
||||
|
||||
nmd->simulation_bake_directory = BLI_strdup(
|
||||
bke::sim::get_default_modifier_bake_directory(*bmain, *object, *md).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Map for counting path references. */
|
||||
using PathUsersMap = Map<std::string,
|
||||
int,
|
||||
default_inline_buffer_capacity(sizeof(std::string)),
|
||||
DefaultProbingStrategy,
|
||||
PathStringHash,
|
||||
PathStringEquality>;
|
||||
|
||||
static PathUsersMap bake_simulation_get_path_users(bContext *C, const Span<Object *> objects)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
PathUsersMap path_users;
|
||||
for (const Object *object : objects) {
|
||||
const char *base_path = ID_BLEND_PATH(bmain, &object->id);
|
||||
|
||||
LISTBASE_FOREACH (const ModifierData *, md, &object->modifiers) {
|
||||
if (md->type != eModifierType_Nodes) {
|
||||
continue;
|
||||
}
|
||||
const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
|
||||
if (StringRef(nmd->simulation_bake_directory).is_empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char absolute_bake_dir[FILE_MAX];
|
||||
STRNCPY(absolute_bake_dir, nmd->simulation_bake_directory);
|
||||
BLI_path_abs(absolute_bake_dir, base_path);
|
||||
path_users.add_or_modify(
|
||||
absolute_bake_dir, [](int *value) { *value = 1; }, [](int *value) { ++(*value); });
|
||||
}
|
||||
}
|
||||
|
||||
return path_users;
|
||||
}
|
||||
|
||||
static int bake_simulation_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
Vector<Object *> objects;
|
||||
if (RNA_boolean_get(op->ptr, "selected")) {
|
||||
CTX_DATA_BEGIN (C, Object *, object, selected_objects) {
|
||||
objects.append(object);
|
||||
}
|
||||
CTX_DATA_END;
|
||||
}
|
||||
else {
|
||||
if (Object *object = CTX_data_active_object(C)) {
|
||||
objects.append(object);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set empty paths to default. */
|
||||
bake_simulation_validate_paths(C, op, objects);
|
||||
|
||||
PathUsersMap path_users = bake_simulation_get_path_users(C, objects);
|
||||
bool has_path_conflict = false;
|
||||
bool has_existing_bake_data = false;
|
||||
for (const auto &item : path_users.items()) {
|
||||
/* Check if multiple caches are writing to the same bake directory. */
|
||||
if (item.value > 1) {
|
||||
BKE_reportf(op->reports,
|
||||
RPT_ERROR,
|
||||
"Path conflict: %d caches set to path %s",
|
||||
item.value,
|
||||
item.key.data());
|
||||
has_path_conflict = true;
|
||||
}
|
||||
|
||||
/* Check if path exists and contains bake data already. */
|
||||
if (bake_directory_has_data(item.key.data())) {
|
||||
has_existing_bake_data = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_path_conflict) {
|
||||
UI_popup_menu_reports(C, op->reports);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
if (has_existing_bake_data) {
|
||||
return WM_operator_confirm_message(C, op, "Overwrite existing bake data");
|
||||
}
|
||||
return bake_simulation_execute(C, op);
|
||||
}
|
||||
|
||||
static int bake_simulation_modal(bContext *C, wmOperator * /*op*/, const wmEvent * /*event*/)
|
||||
{
|
||||
if (!WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_BAKE_SIMULATION_NODES)) {
|
||||
@@ -441,9 +591,7 @@ static int delete_baked_simulation_exec(bContext *C, wmOperator *op)
|
||||
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
|
||||
if (md->type == eModifierType_Nodes) {
|
||||
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
||||
if (nmd->simulation_cache != nullptr) {
|
||||
nmd->simulation_cache->reset();
|
||||
}
|
||||
nmd->simulation_cache->ptr->reset();
|
||||
if (StringRef(nmd->simulation_bake_directory).is_empty()) {
|
||||
continue;
|
||||
}
|
||||
@@ -497,6 +645,7 @@ void OBJECT_OT_simulation_nodes_cache_bake(wmOperatorType *ot)
|
||||
ot->description = "Bake simulations in geometry nodes modifiers";
|
||||
ot->idname = __func__;
|
||||
|
||||
ot->exec = bake_simulation_execute;
|
||||
ot->invoke = bake_simulation_invoke;
|
||||
ot->modal = bake_simulation_modal;
|
||||
ot->poll = bake_simulation_poll;
|
||||
|
||||
@@ -722,7 +722,7 @@ static const EnumPropertyItem WT_vertex_group_select_item[] = {
|
||||
|
||||
const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext *C,
|
||||
PointerRNA * /*ptr*/,
|
||||
PropertyRNA *prop,
|
||||
PropertyRNA * /*prop*/,
|
||||
bool *r_free,
|
||||
const uint selection_mask)
|
||||
{
|
||||
@@ -760,12 +760,6 @@ const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext *
|
||||
RNA_enum_items_add_value(&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_ALL);
|
||||
}
|
||||
|
||||
/* Set `Deform Bone` as default selection if armature is present. */
|
||||
if (ob) {
|
||||
RNA_def_property_enum_default(
|
||||
prop, BKE_modifiers_is_deformed_by_armature(ob) ? WT_VGROUP_BONE_DEFORM : WT_VGROUP_ALL);
|
||||
}
|
||||
|
||||
RNA_enum_item_end(&item, &totitem);
|
||||
*r_free = true;
|
||||
|
||||
@@ -2907,6 +2901,12 @@ void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
|
||||
static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob = ED_object_context(C);
|
||||
|
||||
/* If armature is present, default to `Deform Bones` otherwise `All Groups`. */
|
||||
RNA_enum_set(op->ptr,
|
||||
"group_select_mode",
|
||||
BKE_modifiers_is_deformed_by_armature(ob) ? WT_VGROUP_BONE_DEFORM : WT_VGROUP_ALL);
|
||||
|
||||
bool lock_active = RNA_boolean_get(op->ptr, "lock_active");
|
||||
eVGroupSelect subset_type = static_cast<eVGroupSelect>(
|
||||
RNA_enum_get(op->ptr, "group_select_mode"));
|
||||
|
||||
@@ -6640,7 +6640,8 @@ static void default_paint_slot_color_get(int layer_type, Material *ma, float col
|
||||
bNode *in_node = nullptr;
|
||||
if (ma && ma->nodetree) {
|
||||
ma->nodetree->ensure_topology_cache();
|
||||
const blender::Span<bNode *> nodes = ma->nodetree->nodes_by_type("ShaderNodeBsdfPrincipled");
|
||||
const blender::Span<bNode *> nodes = ma->nodetree->nodes_by_type(
|
||||
"ShaderNodeBsdfPrincipled");
|
||||
in_node = nodes.is_empty() ? nullptr : nodes.first();
|
||||
}
|
||||
if (!in_node) {
|
||||
|
||||
@@ -784,7 +784,7 @@ static void sculpt_gesture_init_face_set_properties(SculptGestureContext *sgcont
|
||||
sgcontext->operation = reinterpret_cast<SculptGestureOperation *>(
|
||||
MEM_cnew<SculptGestureFaceSetOperation>(__func__));
|
||||
|
||||
sgcontext->ss->face_sets = BKE_sculpt_face_sets_ensure(mesh);
|
||||
sgcontext->ss->face_sets = BKE_sculpt_face_sets_ensure(sgcontext->vc.obact);
|
||||
|
||||
SculptGestureFaceSetOperation *face_set_operation = (SculptGestureFaceSetOperation *)
|
||||
sgcontext->operation;
|
||||
@@ -1404,8 +1404,7 @@ static void sculpt_gesture_trim_begin(bContext *C, SculptGestureContext *sgconte
|
||||
{
|
||||
Object *object = sgcontext->vc.obact;
|
||||
SculptSession *ss = object->sculpt;
|
||||
Mesh *mesh = (Mesh *)object->data;
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(mesh);
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(object);
|
||||
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
sculpt_gesture_trim_calculate_depth(sgcontext);
|
||||
|
||||
@@ -389,8 +389,7 @@ static int palette_color_add_exec(bContext *C, wmOperator * /*op*/)
|
||||
PAINT_MODE_TEXTURE_3D,
|
||||
PAINT_MODE_TEXTURE_2D,
|
||||
PAINT_MODE_VERTEX,
|
||||
PAINT_MODE_SCULPT))
|
||||
{
|
||||
PAINT_MODE_SCULPT)) {
|
||||
copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
|
||||
color->value = 0.0;
|
||||
}
|
||||
|
||||
@@ -5889,8 +5889,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
|
||||
BKE_sculpt_mask_layers_ensure(CTX_data_depsgraph_pointer(C), CTX_data_main(C), ob, mmd);
|
||||
}
|
||||
if (SCULPT_tool_is_face_sets(brush->sculpt_tool)) {
|
||||
Mesh *mesh = BKE_object_get_original_mesh(ob);
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(mesh);
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(ob);
|
||||
}
|
||||
|
||||
stroke = paint_stroke_new(C,
|
||||
|
||||
@@ -2199,7 +2199,7 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even
|
||||
|
||||
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
||||
if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS) {
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(mesh);
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(ob);
|
||||
}
|
||||
|
||||
/* Face Set operations are not supported in dyntopo. */
|
||||
|
||||
@@ -344,8 +344,8 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(ob);
|
||||
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(mesh);
|
||||
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, mode == SCULPT_FACE_SET_MASKED, false);
|
||||
|
||||
@@ -651,7 +651,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
|
||||
const float threshold = RNA_float_get(op->ptr, "threshold");
|
||||
|
||||
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(mesh);
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(ob);
|
||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||
|
||||
switch (mode) {
|
||||
@@ -1410,7 +1410,7 @@ static bool sculpt_face_set_edit_init(bContext *C, wmOperator *op)
|
||||
return false;
|
||||
}
|
||||
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(BKE_mesh_from_object(ob));
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(ob);
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -618,10 +618,9 @@ static bool sculpt_undo_restore_face_sets(bContext *C,
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
Object *ob = BKE_view_layer_active_object_get(view_layer);
|
||||
Mesh *me = BKE_object_get_original_mesh(ob);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(me);
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(ob);
|
||||
BKE_pbvh_face_sets_set(ss->pbvh, ss->face_sets);
|
||||
|
||||
bool modified = false;
|
||||
|
||||
@@ -774,7 +774,7 @@ void timeline_draw_cache(const SpaceAction *saction, const Object *ob, const Sce
|
||||
continue;
|
||||
}
|
||||
timeline_cache_draw_simulation_nodes(
|
||||
*scene, *nmd->simulation_cache, y_offset, cache_draw_height, pos_id);
|
||||
*scene, *nmd->simulation_cache->ptr, y_offset, cache_draw_height, pos_id);
|
||||
y_offset += cache_draw_height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,14 @@ constexpr FileIndexerType default_indexer()
|
||||
}
|
||||
|
||||
static FileIndexerEntry *file_indexer_entry_create_from_datablock_info(
|
||||
const BLODataBlockInfo *datablock_info, const int idcode)
|
||||
BLODataBlockInfo *datablock_info, const int idcode)
|
||||
{
|
||||
FileIndexerEntry *entry = static_cast<FileIndexerEntry *>(
|
||||
MEM_mallocN(sizeof(FileIndexerEntry), __func__));
|
||||
entry->datablock_info = *datablock_info;
|
||||
entry->idcode = idcode;
|
||||
/* Shallow copy data-block info and mark original as having its asset data ownership stolen. */
|
||||
entry->datablock_info = *datablock_info;
|
||||
datablock_info->free_asset_data = false;
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -55,11 +57,11 @@ extern "C" {
|
||||
|
||||
void ED_file_indexer_entries_extend_from_datablock_infos(
|
||||
FileIndexerEntries *indexer_entries,
|
||||
const LinkNode * /*BLODataBlockInfo*/ datablock_infos,
|
||||
LinkNode * /*BLODataBlockInfo*/ datablock_infos,
|
||||
const int idcode)
|
||||
{
|
||||
for (const LinkNode *ln = datablock_infos; ln; ln = ln->next) {
|
||||
const BLODataBlockInfo *datablock_info = static_cast<const BLODataBlockInfo *>(ln->link);
|
||||
for (LinkNode *ln = datablock_infos; ln; ln = ln->next) {
|
||||
BLODataBlockInfo *datablock_info = static_cast<BLODataBlockInfo *>(ln->link);
|
||||
FileIndexerEntry *file_indexer_entry =
|
||||
blender::ed::file::indexer::file_indexer_entry_create_from_datablock_info(datablock_info,
|
||||
idcode);
|
||||
|
||||
@@ -245,6 +245,13 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bNode *new_node = bke::node_copy_with_mapping(
|
||||
&tree, node, LIB_ID_COPY_DEFAULT, true, socket_map);
|
||||
/* Reset socket shape in case a node is copied to a different tree type. */
|
||||
LISTBASE_FOREACH (bNodeSocket *, socket, &new_node->inputs) {
|
||||
socket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
|
||||
}
|
||||
LISTBASE_FOREACH (bNodeSocket *, socket, &new_node->outputs) {
|
||||
socket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
|
||||
}
|
||||
node_map.add_new(&node, new_node);
|
||||
}
|
||||
else {
|
||||
@@ -269,6 +276,8 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
|
||||
for (bNode *new_node : node_map.values()) {
|
||||
nodeSetSelected(new_node, true);
|
||||
|
||||
new_node->flag &= ~NODE_ACTIVE;
|
||||
|
||||
/* The parent pointer must be redirected to new node. */
|
||||
if (new_node->parent) {
|
||||
if (node_map.contains(new_node->parent)) {
|
||||
|
||||
@@ -3327,15 +3327,13 @@ static bool realtime_compositor_is_in_use(const bContext &context)
|
||||
return false;
|
||||
}
|
||||
|
||||
const Main *main = CTX_data_main(&context);
|
||||
LISTBASE_FOREACH (const bScreen *, screen, &main->screens) {
|
||||
wmWindowManager *wm = CTX_wm_manager(&context);
|
||||
LISTBASE_FOREACH (const wmWindow *, win, &wm->windows) {
|
||||
const bScreen *screen = WM_window_get_active_screen(win);
|
||||
LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
|
||||
LISTBASE_FOREACH (const SpaceLink *, space, &area->spacedata) {
|
||||
if (space->spacetype != SPACE_VIEW3D) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const View3D &view_3d = *reinterpret_cast<const View3D *>(space);
|
||||
const SpaceLink &space = *static_cast<const SpaceLink *>(area->spacedata.first);
|
||||
if (space.spacetype == SPACE_VIEW3D) {
|
||||
const View3D &view_3d = reinterpret_cast<const View3D &>(space);
|
||||
|
||||
if (view_3d.shading.use_compositor == V3D_SHADING_USE_COMPOSITOR_DISABLED) {
|
||||
continue;
|
||||
|
||||
@@ -913,16 +913,19 @@ static void node_group_make_insert_selected(const bContext &C,
|
||||
links_to_remove.add(link);
|
||||
continue;
|
||||
}
|
||||
if (link->fromnode == gnode) {
|
||||
links_to_remove.add(link);
|
||||
continue;
|
||||
}
|
||||
if (nodes_to_move.contains(link->fromnode)) {
|
||||
internal_links_to_move.add(link);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
InputSocketInfo &info = input_links.lookup_or_add_default(link->fromsock);
|
||||
info.from_node = link->fromnode;
|
||||
info.links.append(link);
|
||||
if (!info.interface_socket) {
|
||||
info.interface_socket = add_interface_from_socket(ntree, group, *link->tosock);
|
||||
}
|
||||
InputSocketInfo &info = input_links.lookup_or_add_default(link->fromsock);
|
||||
info.from_node = link->fromnode;
|
||||
info.links.append(link);
|
||||
if (!info.interface_socket) {
|
||||
info.interface_socket = add_interface_from_socket(ntree, group, *link->tosock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -932,12 +935,15 @@ static void node_group_make_insert_selected(const bContext &C,
|
||||
links_to_remove.add(link);
|
||||
continue;
|
||||
}
|
||||
if (link->tonode == gnode) {
|
||||
links_to_remove.add(link);
|
||||
continue;
|
||||
}
|
||||
if (nodes_to_move.contains(link->tonode)) {
|
||||
internal_links_to_move.add(link);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
output_links.append({link, add_interface_from_socket(ntree, group, *link->fromsock)});
|
||||
}
|
||||
output_links.append({link, add_interface_from_socket(ntree, group, *link->fromsock)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,13 +35,10 @@ set(SRC
|
||||
sequencer_drag_drop.c
|
||||
sequencer_draw.c
|
||||
sequencer_edit.c
|
||||
sequencer_gizmo_retime.cc
|
||||
sequencer_gizmo_retime_type.cc
|
||||
sequencer_modifier.c
|
||||
sequencer_ops.c
|
||||
sequencer_preview.c
|
||||
sequencer_proxy.c
|
||||
sequencer_retiming.cc
|
||||
sequencer_scopes.c
|
||||
sequencer_select.c
|
||||
sequencer_thumbnails.c
|
||||
|
||||
@@ -414,6 +414,7 @@ static void draw_seq_waveform_overlay(
|
||||
|
||||
const float frames_per_pixel = BLI_rctf_size_x(®ion->v2d.cur) / region->winx;
|
||||
const float samples_per_frame = SOUND_WAVE_SAMPLES_PER_SECOND / FPS;
|
||||
float samples_per_pixel = samples_per_frame * frames_per_pixel;
|
||||
|
||||
/* Align strip start with nearest pixel to prevent waveform flickering. */
|
||||
const float x1_aligned = align_frame_with_pixel(x1, frames_per_pixel);
|
||||
@@ -439,17 +440,15 @@ static void draw_seq_waveform_overlay(
|
||||
size_t wave_data_len = 0;
|
||||
|
||||
/* Offset must be also aligned, otherwise waveform flickers when moving left handle. */
|
||||
float start_frame = SEQ_time_left_handle_frame_get(scene, seq);
|
||||
|
||||
const float strip_offset = align_frame_with_pixel(seq->startofs + seq->anim_startofs,
|
||||
frames_per_pixel);
|
||||
float start_sample = strip_offset * samples_per_frame;
|
||||
start_sample += seq->sound->offset_time * SOUND_WAVE_SAMPLES_PER_SECOND;
|
||||
/* Add off-screen part of strip to offset. */
|
||||
start_frame += (frame_start - x1_aligned);
|
||||
start_frame += seq->sound->offset_time / FPS;
|
||||
start_sample += (frame_start - x1_aligned) * samples_per_frame;
|
||||
|
||||
for (int i = 0; i < pixels_to_draw; i++) {
|
||||
float timeline_frame = start_frame + i * frames_per_pixel;
|
||||
/* TODO: Use linear interpolation between frames to avoid bad drawing quality. */
|
||||
float frame_index = SEQ_give_frame_index(scene, seq, timeline_frame);
|
||||
float sample = frame_index * samples_per_frame;
|
||||
float sample = start_sample + i * samples_per_pixel;
|
||||
int sample_index = round_fl_to_int(sample);
|
||||
|
||||
if (sample_index < 0) {
|
||||
@@ -470,8 +469,6 @@ static void draw_seq_waveform_overlay(
|
||||
value_min = (1.0f - f) * value_min + f * waveform->data[sample_index * 3 + 3];
|
||||
value_max = (1.0f - f) * value_max + f * waveform->data[sample_index * 3 + 4];
|
||||
rms = (1.0f - f) * rms + f * waveform->data[sample_index * 3 + 5];
|
||||
|
||||
float samples_per_pixel = samples_per_frame * frames_per_pixel;
|
||||
if (samples_per_pixel > 1.0f) {
|
||||
/* We need to sum up the values we skip over until the next step. */
|
||||
float next_pos = sample + samples_per_pixel;
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2022 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup spseq
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "BLI_span.hh"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "ED_gizmo_library.h"
|
||||
#include "ED_gizmo_utils.h"
|
||||
|
||||
#include "SEQ_iterator.h"
|
||||
#include "SEQ_retiming.h"
|
||||
#include "SEQ_retiming.hh"
|
||||
#include "SEQ_sequencer.h"
|
||||
|
||||
/* Own include. */
|
||||
#include "sequencer_intern.h"
|
||||
|
||||
typedef struct GizmoGroup_retime {
|
||||
wmGizmo *add_handle_gizmo;
|
||||
wmGizmo *move_handle_gizmo;
|
||||
wmGizmo *remove_handle_gizmo;
|
||||
} GizmoGroup_retime;
|
||||
|
||||
static bool gizmogroup_retime_poll(const bContext *C, wmGizmoGroupType *gzgt)
|
||||
{
|
||||
/* Needed to prevent drawing gizmos when retiming tool is not activated. */
|
||||
if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((U.gizmo_flag & USER_GIZMO_DRAW) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
if (area == nullptr && area->spacetype != SPACE_SEQ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const SpaceSeq *sseq = (SpaceSeq *)area->spacedata.first;
|
||||
if (sseq->gizmo_flag & (SEQ_GIZMO_HIDE | SEQ_GIZMO_HIDE_TOOL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Editing *ed = SEQ_editing_get(CTX_data_scene(C));
|
||||
Sequence *seq = ed->act_seq;
|
||||
|
||||
if (ed == nullptr || seq == nullptr || !SEQ_retiming_is_allowed(seq)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void gizmogroup_retime_setup(const bContext * /* C */, wmGizmoGroup *gzgroup)
|
||||
{
|
||||
GizmoGroup_retime *ggd = (GizmoGroup_retime *)MEM_callocN(sizeof(GizmoGroup_retime), __func__);
|
||||
|
||||
/* Assign gizmos. */
|
||||
const wmGizmoType *gzt_add_handle = WM_gizmotype_find("GIZMO_GT_retime_handle_add", true);
|
||||
ggd->add_handle_gizmo = WM_gizmo_new_ptr(gzt_add_handle, gzgroup, nullptr);
|
||||
const wmGizmoType *gzt_remove_handle = WM_gizmotype_find("GIZMO_GT_retime_handle_remove", true);
|
||||
ggd->remove_handle_gizmo = WM_gizmo_new_ptr(gzt_remove_handle, gzgroup, nullptr);
|
||||
const wmGizmoType *gzt_move_handle = WM_gizmotype_find("GIZMO_GT_retime_handle_move", true);
|
||||
ggd->move_handle_gizmo = WM_gizmo_new_ptr(gzt_move_handle, gzgroup, nullptr);
|
||||
gzgroup->customdata = ggd;
|
||||
|
||||
/* Assign operators. */
|
||||
wmOperatorType *ot = WM_operatortype_find("SEQUENCER_OT_retiming_handle_move", true);
|
||||
WM_gizmo_operator_set(ggd->move_handle_gizmo, 0, ot, nullptr);
|
||||
ot = WM_operatortype_find("SEQUENCER_OT_retiming_handle_add", true);
|
||||
WM_gizmo_operator_set(ggd->add_handle_gizmo, 0, ot, nullptr);
|
||||
ot = WM_operatortype_find("SEQUENCER_OT_retiming_handle_remove", true);
|
||||
WM_gizmo_operator_set(ggd->remove_handle_gizmo, 0, ot, nullptr);
|
||||
}
|
||||
|
||||
void SEQUENCER_GGT_gizmo_retime(wmGizmoGroupType *gzgt)
|
||||
{
|
||||
gzgt->name = "Sequencer Transform Gizmo Retime";
|
||||
gzgt->idname = "SEQUENCER_GGT_gizmo_retime";
|
||||
|
||||
gzgt->flag = WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
|
||||
|
||||
gzgt->gzmap_params.spaceid = SPACE_SEQ;
|
||||
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
|
||||
|
||||
gzgt->poll = gizmogroup_retime_poll;
|
||||
gzgt->setup = gizmogroup_retime_setup;
|
||||
}
|
||||
@@ -1,621 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2022 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup spseq
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_sequence_types.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "BLF_api.h"
|
||||
|
||||
#include "GPU_batch.h"
|
||||
#include "GPU_batch_utils.h"
|
||||
#include "GPU_immediate.h"
|
||||
#include "GPU_immediate_util.h"
|
||||
#include "GPU_matrix.h"
|
||||
#include "GPU_select.h"
|
||||
#include "GPU_state.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "ED_gizmo_library.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_interface_icons.h"
|
||||
#include "UI_resources.h"
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#include "SEQ_iterator.h"
|
||||
#include "SEQ_retiming.h"
|
||||
#include "SEQ_retiming.hh"
|
||||
#include "SEQ_sequencer.h"
|
||||
#include "SEQ_time.h"
|
||||
|
||||
/* Own include. */
|
||||
#include "sequencer_intern.h"
|
||||
|
||||
using blender::MutableSpan;
|
||||
|
||||
/** Size in pixels. */
|
||||
#define RETIME_HANDLE_MOUSEOVER_THRESHOLD (16.0f * UI_SCALE_FAC)
|
||||
/** Factor based on icon size. */
|
||||
#define RETIME_BUTTON_SIZE 0.6f
|
||||
|
||||
static float remove_gizmo_height_get(const View2D *v2d)
|
||||
{
|
||||
const float max_size = (SEQ_STRIP_OFSTOP - SEQ_STRIP_OFSBOTTOM) * UI_view2d_scale_get_y(v2d);
|
||||
return min_ff(14.0f * UI_SCALE_FAC, max_size * 0.4f);
|
||||
}
|
||||
|
||||
static float strip_y_rescale(const Sequence *seq, const float y_value)
|
||||
{
|
||||
const float y_range = SEQ_STRIP_OFSTOP - SEQ_STRIP_OFSBOTTOM;
|
||||
return (y_value * y_range) + seq->machine + SEQ_STRIP_OFSBOTTOM;
|
||||
}
|
||||
|
||||
static float handle_x_get(const Scene *scene, const Sequence *seq, const SeqRetimingHandle *handle)
|
||||
{
|
||||
|
||||
const SeqRetimingHandle *last_handle = SEQ_retiming_last_handle_get(seq);
|
||||
const bool is_last_handle = (handle == last_handle);
|
||||
|
||||
return SEQ_retiming_handle_timeline_frame_get(scene, seq, handle) + (is_last_handle ? 1 : 0);
|
||||
}
|
||||
|
||||
static const SeqRetimingHandle *mouse_over_handle_get(const Scene *scene,
|
||||
const Sequence *seq,
|
||||
const View2D *v2d,
|
||||
const int mval[2])
|
||||
{
|
||||
int best_distance = INT_MAX;
|
||||
const SeqRetimingHandle *best_handle = nullptr;
|
||||
|
||||
MutableSpan handles = SEQ_retiming_handles_get(seq);
|
||||
for (const SeqRetimingHandle &handle : handles) {
|
||||
int distance = round_fl_to_int(
|
||||
fabsf(UI_view2d_view_to_region_x(v2d, handle_x_get(scene, seq, &handle)) - mval[0]));
|
||||
|
||||
if (distance < RETIME_HANDLE_MOUSEOVER_THRESHOLD && distance < best_distance) {
|
||||
best_distance = distance;
|
||||
best_handle = &handle;
|
||||
}
|
||||
}
|
||||
|
||||
return best_handle;
|
||||
}
|
||||
|
||||
static float pixels_to_view_width(const bContext *C, const float width)
|
||||
{
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
float scale_x = UI_view2d_view_to_region_x(v2d, 1) - UI_view2d_view_to_region_x(v2d, 0.0f);
|
||||
return width / scale_x;
|
||||
}
|
||||
|
||||
static float pixels_to_view_height(const bContext *C, const float height)
|
||||
{
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
float scale_y = UI_view2d_view_to_region_y(v2d, 1) - UI_view2d_view_to_region_y(v2d, 0.0f);
|
||||
return height / scale_y;
|
||||
}
|
||||
|
||||
static float strip_start_screenspace_get(const bContext *C, const Sequence *seq)
|
||||
{
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
return UI_view2d_view_to_region_x(v2d, SEQ_time_left_handle_frame_get(scene, seq));
|
||||
}
|
||||
|
||||
static float strip_end_screenspace_get(const bContext *C, const Sequence *seq)
|
||||
{
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
return UI_view2d_view_to_region_x(v2d, SEQ_time_right_handle_frame_get(scene, seq));
|
||||
}
|
||||
|
||||
static Sequence *active_seq_from_context(const bContext *C)
|
||||
{
|
||||
const Editing *ed = SEQ_editing_get(CTX_data_scene(C));
|
||||
return ed->act_seq;
|
||||
}
|
||||
|
||||
static rctf strip_box_get(const bContext *C, const Sequence *seq)
|
||||
{
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
rctf rect;
|
||||
rect.xmin = strip_start_screenspace_get(C, seq);
|
||||
rect.xmax = strip_end_screenspace_get(C, seq);
|
||||
rect.ymin = UI_view2d_view_to_region_y(v2d, strip_y_rescale(seq, 0));
|
||||
rect.ymax = UI_view2d_view_to_region_y(v2d, strip_y_rescale(seq, 1));
|
||||
return rect;
|
||||
}
|
||||
|
||||
static rctf remove_box_get(const bContext *C, const Sequence *seq)
|
||||
{
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
rctf rect = strip_box_get(C, seq);
|
||||
rect.ymax = rect.ymin + remove_gizmo_height_get(v2d);
|
||||
return rect;
|
||||
}
|
||||
|
||||
static bool mouse_is_inside_box(const rctf *box, const int mval[2])
|
||||
{
|
||||
return mval[0] >= box->xmin && mval[0] <= box->xmax && mval[1] >= box->ymin &&
|
||||
mval[1] <= box->ymax;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Retiming Add Handle Gizmo
|
||||
* \{ */
|
||||
|
||||
typedef struct RetimeButtonGizmo {
|
||||
wmGizmo gizmo;
|
||||
int icon_id;
|
||||
const Sequence *seq_under_mouse;
|
||||
bool is_mouse_over_gizmo;
|
||||
} RetimeButtonGizmo;
|
||||
|
||||
typedef struct ButtonDimensions {
|
||||
float height;
|
||||
float width;
|
||||
float x;
|
||||
float y;
|
||||
} ButtonDimensions;
|
||||
|
||||
static ButtonDimensions button_dimensions_get(const bContext *C, const RetimeButtonGizmo *gizmo)
|
||||
{
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
const Sequence *seq = active_seq_from_context(C);
|
||||
|
||||
const float icon_height = UI_icon_get_height(gizmo->icon_id) * UI_SCALE_FAC;
|
||||
const float icon_width = UI_icon_get_width(gizmo->icon_id) * UI_SCALE_FAC;
|
||||
const float icon_x = UI_view2d_view_to_region_x(v2d, BKE_scene_frame_get(scene)) +
|
||||
icon_width / 2;
|
||||
const float icon_y = UI_view2d_view_to_region_y(v2d, strip_y_rescale(seq, 0.5)) -
|
||||
icon_height / 2;
|
||||
const ButtonDimensions dimensions = {icon_height, icon_width, icon_x, icon_y};
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
static rctf button_box_get(const bContext *C, const RetimeButtonGizmo *gizmo)
|
||||
{
|
||||
ButtonDimensions button_dimensions = button_dimensions_get(C, gizmo);
|
||||
|
||||
float x_range = button_dimensions.width;
|
||||
float y_range = button_dimensions.height;
|
||||
|
||||
rctf rect;
|
||||
rect.xmin = button_dimensions.x;
|
||||
rect.xmax = button_dimensions.x + x_range;
|
||||
rect.ymin = button_dimensions.y;
|
||||
rect.ymax = button_dimensions.y + y_range;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
static void gizmo_retime_handle_add_draw(const bContext *C, wmGizmo *gz)
|
||||
{
|
||||
RetimeButtonGizmo *gizmo = (RetimeButtonGizmo *)gz;
|
||||
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const Sequence *seq = active_seq_from_context(C);
|
||||
const int frame_index = BKE_scene_frame_get(scene) - SEQ_time_start_frame_get(seq);
|
||||
const SeqRetimingHandle *handle = SEQ_retiming_find_segment_start_handle(seq, frame_index);
|
||||
|
||||
if (handle != nullptr && SEQ_retiming_handle_is_transition_type(handle)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ButtonDimensions button = button_dimensions_get(C, gizmo);
|
||||
const rctf strip_box = strip_box_get(C, active_seq_from_context(C));
|
||||
if (!BLI_rctf_isect_pt(&strip_box, button.x, button.y)) {
|
||||
return;
|
||||
}
|
||||
|
||||
wmOrtho2_region_pixelspace(CTX_wm_region(C));
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
|
||||
|
||||
const float alpha = gizmo->is_mouse_over_gizmo ? 1.0f : 0.6f;
|
||||
|
||||
immUniformColor4f(0.2f, 0.2f, 0.2f, alpha);
|
||||
imm_draw_circle_fill_2d(pos,
|
||||
button.x + button.width / 2,
|
||||
button.y + button.height / 2,
|
||||
button.width * RETIME_BUTTON_SIZE,
|
||||
32);
|
||||
immUnbindProgram();
|
||||
|
||||
GPU_polygon_smooth(false);
|
||||
UI_icon_draw_alpha(button.x, button.y, gizmo->icon_id, alpha);
|
||||
GPU_polygon_smooth(true);
|
||||
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
}
|
||||
|
||||
static int gizmo_retime_handle_add_test_select(bContext *C, wmGizmo *gz, const int mval[2])
|
||||
{
|
||||
RetimeButtonGizmo *gizmo = (RetimeButtonGizmo *)gz;
|
||||
Sequence *seq = active_seq_from_context(C);
|
||||
|
||||
Sequence *mouse_over_seq = nullptr;
|
||||
gizmo->is_mouse_over_gizmo = false;
|
||||
|
||||
/* Store strip under mouse cursor. */
|
||||
const rctf strip_box = strip_box_get(C, seq);
|
||||
if (mouse_is_inside_box(&strip_box, mval)) {
|
||||
mouse_over_seq = seq;
|
||||
}
|
||||
|
||||
if (gizmo->seq_under_mouse != mouse_over_seq) {
|
||||
gizmo->seq_under_mouse = mouse_over_seq;
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, CTX_data_scene(C));
|
||||
}
|
||||
|
||||
if (gizmo->seq_under_mouse == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const rctf button_box = button_box_get(C, gizmo);
|
||||
if (!mouse_is_inside_box(&button_box, mval)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gizmo->is_mouse_over_gizmo = true;
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
wmGizmoOpElem *op_elem = WM_gizmo_operator_get(gz, 0);
|
||||
RNA_int_set(&op_elem->ptr, "timeline_frame", BKE_scene_frame_get(scene));
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, CTX_data_scene(C));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gizmo_retime_handle_add_setup(wmGizmo *gz)
|
||||
{
|
||||
RetimeButtonGizmo *gizmo = (RetimeButtonGizmo *)gz;
|
||||
gizmo->icon_id = ICON_ADD;
|
||||
}
|
||||
|
||||
void GIZMO_GT_retime_handle_add(wmGizmoType *gzt)
|
||||
{
|
||||
/* Identifiers. */
|
||||
gzt->idname = "GIZMO_GT_retime_handle_add";
|
||||
|
||||
/* Api callbacks. */
|
||||
gzt->setup = gizmo_retime_handle_add_setup;
|
||||
gzt->draw = gizmo_retime_handle_add_draw;
|
||||
gzt->test_select = gizmo_retime_handle_add_test_select;
|
||||
gzt->struct_size = sizeof(RetimeButtonGizmo);
|
||||
|
||||
/* Currently only used for cursor display. */
|
||||
RNA_def_boolean(gzt->srna, "show_drag", true, "Show Drag", "");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Retiming Move Handle Gizmo
|
||||
* \{ */
|
||||
|
||||
typedef struct RetimeHandleMoveGizmo {
|
||||
wmGizmo gizmo;
|
||||
const Sequence *mouse_over_seq;
|
||||
int mouse_over_handle_x;
|
||||
bool create_transition_operation;
|
||||
} RetimeHandleMoveGizmo;
|
||||
|
||||
static void retime_handle_draw(const bContext *C,
|
||||
const RetimeHandleMoveGizmo *gizmo,
|
||||
uint pos,
|
||||
const Sequence *seq,
|
||||
const SeqRetimingHandle *handle)
|
||||
{
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const float handle_x = handle_x_get(scene, seq, handle);
|
||||
|
||||
if (handle_x == SEQ_time_left_handle_frame_get(scene, seq)) {
|
||||
return;
|
||||
}
|
||||
if (handle_x == SEQ_time_right_handle_frame_get(scene, seq)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
const rctf strip_box = strip_box_get(C, seq);
|
||||
if (!BLI_rctf_isect_x(&strip_box, UI_view2d_view_to_region_x(v2d, handle_x))) {
|
||||
return; /* Handle out of strip bounds. */
|
||||
}
|
||||
|
||||
const int ui_triangle_size = remove_gizmo_height_get(v2d);
|
||||
const float bottom = UI_view2d_view_to_region_y(v2d, strip_y_rescale(seq, 0.0f)) + 2;
|
||||
const float top = UI_view2d_view_to_region_y(v2d, strip_y_rescale(seq, 1.0f)) - 2;
|
||||
const float handle_position = UI_view2d_view_to_region_x(v2d, handle_x);
|
||||
|
||||
float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
if (seq == gizmo->mouse_over_seq && handle_x == gizmo->mouse_over_handle_x) {
|
||||
if (gizmo->create_transition_operation) {
|
||||
bool handle_is_transition = SEQ_retiming_handle_is_transition_type(handle);
|
||||
bool prev_handle_is_transition = SEQ_retiming_handle_is_transition_type(handle - 1);
|
||||
if (!(handle_is_transition || prev_handle_is_transition)) {
|
||||
col[0] = 0.5f;
|
||||
col[2] = 0.4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mul_v3_fl(col, 0.65f);
|
||||
}
|
||||
|
||||
immUniformColor4fv(col);
|
||||
|
||||
immBegin(GPU_PRIM_TRI_FAN, 3);
|
||||
immVertex2f(pos, handle_position - ui_triangle_size / 2, bottom);
|
||||
immVertex2f(pos, handle_position + ui_triangle_size / 2, bottom);
|
||||
immVertex2f(pos, handle_position, bottom + ui_triangle_size);
|
||||
|
||||
immEnd();
|
||||
|
||||
immBegin(GPU_PRIM_LINES, 2);
|
||||
immVertex2f(pos, handle_position, bottom);
|
||||
immVertex2f(pos, handle_position, top);
|
||||
immEnd();
|
||||
}
|
||||
|
||||
static void retime_speed_text_draw(const bContext *C,
|
||||
const Sequence *seq,
|
||||
const SeqRetimingHandle *handle)
|
||||
{
|
||||
SeqRetimingHandle *last_handle = SEQ_retiming_last_handle_get(seq);
|
||||
if (handle == last_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const int start_frame = SEQ_time_left_handle_frame_get(scene, seq);
|
||||
const int end_frame = SEQ_time_right_handle_frame_get(scene, seq);
|
||||
|
||||
int next_handle_index = SEQ_retiming_handle_index_get(seq, handle) + 1;
|
||||
const SeqRetimingHandle *next_handle = &SEQ_retiming_handles_get(seq)[next_handle_index];
|
||||
if (handle_x_get(scene, seq, next_handle) < start_frame ||
|
||||
handle_x_get(scene, seq, handle) > end_frame)
|
||||
{
|
||||
return; /* Label out of strip bounds. */
|
||||
}
|
||||
|
||||
char label_str[40];
|
||||
size_t label_len;
|
||||
|
||||
if (SEQ_retiming_handle_is_transition_type(handle)) {
|
||||
const float prev_speed = SEQ_retiming_handle_speed_get(seq, handle - 1);
|
||||
const float next_speed = SEQ_retiming_handle_speed_get(seq, next_handle + 1);
|
||||
label_len = SNPRINTF_RLEN(label_str,
|
||||
"%d%% - %d%%",
|
||||
round_fl_to_int(prev_speed * 100.0f),
|
||||
round_fl_to_int(next_speed * 100.0f));
|
||||
}
|
||||
else {
|
||||
const float speed = SEQ_retiming_handle_speed_get(seq, next_handle);
|
||||
label_len = SNPRINTF_RLEN(label_str, "%d%%", round_fl_to_int(speed * 100.0f));
|
||||
}
|
||||
|
||||
const float width = pixels_to_view_width(C, BLF_width(BLF_default(), label_str, label_len));
|
||||
|
||||
const float xmin = max_ff(SEQ_time_left_handle_frame_get(scene, seq),
|
||||
handle_x_get(scene, seq, handle));
|
||||
const float xmax = min_ff(SEQ_time_right_handle_frame_get(scene, seq),
|
||||
handle_x_get(scene, seq, next_handle));
|
||||
|
||||
const float text_x = (xmin + xmax - width) / 2;
|
||||
const float text_y = strip_y_rescale(seq, 0) + pixels_to_view_height(C, 5);
|
||||
|
||||
if (width > xmax - xmin) {
|
||||
return; /* Not enough space to draw label. */
|
||||
}
|
||||
|
||||
const uchar col[4] = {255, 255, 255, 255};
|
||||
UI_view2d_text_cache_add(UI_view2d_fromcontext(C), text_x, text_y, label_str, label_len, col);
|
||||
}
|
||||
|
||||
static void gizmo_retime_handle_draw(const bContext *C, wmGizmo *gz)
|
||||
{
|
||||
RetimeHandleMoveGizmo *gizmo = (RetimeHandleMoveGizmo *)gz;
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
|
||||
/* TODO: This is hard-coded behavior, same as pre-select gizmos in 3D view.
|
||||
* Better solution would be to check operator keymap and display this information in status bar
|
||||
* and tool-tip. */
|
||||
wmEvent *event = CTX_wm_window(C)->eventstate;
|
||||
gizmo->create_transition_operation = (event->modifier & KM_SHIFT) != 0;
|
||||
|
||||
wmOrtho2_region_pixelspace(CTX_wm_region(C));
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
|
||||
|
||||
Sequence *seq = active_seq_from_context(C);
|
||||
SEQ_retiming_data_ensure(seq);
|
||||
MutableSpan handles = SEQ_retiming_handles_get(seq);
|
||||
|
||||
for (const SeqRetimingHandle &handle : handles) {
|
||||
retime_speed_text_draw(C, seq, &handle);
|
||||
|
||||
if (&handle == handles.begin()) {
|
||||
continue; /* Ignore first handle. */
|
||||
}
|
||||
retime_handle_draw(C, gizmo, pos, seq, &handle);
|
||||
}
|
||||
|
||||
immUnbindProgram();
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
|
||||
UI_view2d_text_cache_draw(CTX_wm_region(C));
|
||||
UI_view2d_view_ortho(v2d); /* 'UI_view2d_text_cache_draw()' messes up current view. */
|
||||
}
|
||||
|
||||
static int gizmo_retime_handle_test_select(bContext *C, wmGizmo *gz, const int mval[2])
|
||||
{
|
||||
RetimeHandleMoveGizmo *gizmo = (RetimeHandleMoveGizmo *)gz;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
gizmo->mouse_over_seq = nullptr;
|
||||
|
||||
Sequence *seq = active_seq_from_context(C);
|
||||
SEQ_retiming_data_ensure(seq);
|
||||
const SeqRetimingHandle *handle = mouse_over_handle_get(
|
||||
scene, seq, UI_view2d_fromcontext(C), mval);
|
||||
const int handle_index = SEQ_retiming_handle_index_get(seq, handle);
|
||||
|
||||
if (handle == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle_x_get(scene, seq, handle) == SEQ_time_left_handle_frame_get(scene, seq) ||
|
||||
handle_index == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
rctf strip_box = strip_box_get(C, seq);
|
||||
BLI_rctf_resize_x(&strip_box, BLI_rctf_size_x(&strip_box) + 2 * remove_gizmo_height_get(v2d));
|
||||
if (!mouse_is_inside_box(&strip_box, mval)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gizmo->mouse_over_seq = seq;
|
||||
gizmo->mouse_over_handle_x = handle_x_get(scene, seq, handle);
|
||||
|
||||
wmGizmoOpElem *op_elem = WM_gizmo_operator_get(gz, 0);
|
||||
RNA_int_set(&op_elem->ptr, "handle_index", handle_index);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gizmo_retime_handle_cursor_get(wmGizmo *gz)
|
||||
{
|
||||
if (RNA_boolean_get(gz->ptr, "show_drag")) {
|
||||
return WM_CURSOR_EW_SCROLL;
|
||||
}
|
||||
return WM_CURSOR_DEFAULT;
|
||||
}
|
||||
|
||||
static void gizmo_retime_handle_setup(wmGizmo *gz)
|
||||
{
|
||||
gz->flag = WM_GIZMO_DRAW_MODAL;
|
||||
}
|
||||
|
||||
void GIZMO_GT_retime_handle(wmGizmoType *gzt)
|
||||
{
|
||||
/* Identifiers. */
|
||||
gzt->idname = "GIZMO_GT_retime_handle_move";
|
||||
|
||||
/* Api callbacks. */
|
||||
gzt->setup = gizmo_retime_handle_setup;
|
||||
gzt->draw = gizmo_retime_handle_draw;
|
||||
gzt->test_select = gizmo_retime_handle_test_select;
|
||||
gzt->cursor_get = gizmo_retime_handle_cursor_get;
|
||||
gzt->struct_size = sizeof(RetimeHandleMoveGizmo);
|
||||
|
||||
/* Currently only used for cursor display. */
|
||||
RNA_def_boolean(gzt->srna, "show_drag", true, "Show Drag", "");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Retiming Remove Handle Gizmo
|
||||
* \{ */
|
||||
|
||||
static void gizmo_retime_remove_draw(const bContext * /* C */, wmGizmo * /* gz */)
|
||||
{
|
||||
/* Pass. */
|
||||
}
|
||||
|
||||
static int gizmo_retime_remove_test_select(bContext *C, wmGizmo *gz, const int mval[2])
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Sequence *seq = active_seq_from_context(C);
|
||||
|
||||
SEQ_retiming_data_ensure(seq);
|
||||
const SeqRetimingHandle *handle = mouse_over_handle_get(
|
||||
scene, seq, UI_view2d_fromcontext(C), mval);
|
||||
const int handle_index = SEQ_retiming_handle_index_get(seq, handle);
|
||||
|
||||
if (handle == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle_x_get(scene, seq, handle) == SEQ_time_left_handle_frame_get(scene, seq) ||
|
||||
handle_index == 0)
|
||||
{
|
||||
return -1; /* Ignore first handle. */
|
||||
}
|
||||
|
||||
SeqRetimingHandle *last_handle = SEQ_retiming_last_handle_get(seq);
|
||||
if (handle == last_handle) {
|
||||
return -1; /* Last handle can not be removed. */
|
||||
}
|
||||
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
rctf box = remove_box_get(C, seq);
|
||||
BLI_rctf_resize_x(&box, BLI_rctf_size_x(&box) + 2 * remove_gizmo_height_get(v2d));
|
||||
if (!mouse_is_inside_box(&box, mval)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
wmGizmoOpElem *op_elem = WM_gizmo_operator_get(gz, 0);
|
||||
RNA_int_set(&op_elem->ptr, "handle_index", handle_index);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gizmo_retime_remove_cursor_get(wmGizmo *gz)
|
||||
{
|
||||
if (RNA_boolean_get(gz->ptr, "show_drag")) {
|
||||
return WM_CURSOR_ERASER;
|
||||
}
|
||||
return WM_CURSOR_DEFAULT;
|
||||
}
|
||||
|
||||
void GIZMO_GT_retime_remove(wmGizmoType *gzt)
|
||||
{
|
||||
/* Identifiers. */
|
||||
gzt->idname = "GIZMO_GT_retime_handle_remove";
|
||||
|
||||
/* Api callbacks. */
|
||||
gzt->draw = gizmo_retime_remove_draw;
|
||||
gzt->test_select = gizmo_retime_remove_test_select;
|
||||
gzt->cursor_get = gizmo_retime_remove_cursor_get;
|
||||
gzt->struct_size = sizeof(wmGizmo);
|
||||
|
||||
/* Currently only used for cursor display. */
|
||||
RNA_def_boolean(gzt->srna, "show_drag", true, "Show Drag", "");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -10,17 +10,11 @@
|
||||
#include "DNA_sequence_types.h"
|
||||
#include "RNA_access.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Internal exports only. */
|
||||
|
||||
struct ARegion;
|
||||
struct ARegionType;
|
||||
struct Depsgraph;
|
||||
struct wmGizmoGroupType;
|
||||
struct wmGizmoType;
|
||||
struct Main;
|
||||
struct Scene;
|
||||
struct SeqCollection;
|
||||
@@ -305,21 +299,3 @@ int sequencer_image_seq_get_minmax_frame(struct wmOperator *op,
|
||||
int *r_numdigits);
|
||||
void sequencer_image_seq_reserve_frames(
|
||||
struct wmOperator *op, struct StripElem *se, int len, int minframe, int numdigits);
|
||||
|
||||
/* sequencer_retiming.c */
|
||||
void SEQUENCER_OT_retiming_reset(struct wmOperatorType *ot);
|
||||
void SEQUENCER_OT_retiming_handle_move(struct wmOperatorType *ot);
|
||||
void SEQUENCER_OT_retiming_handle_add(struct wmOperatorType *ot);
|
||||
void SEQUENCER_OT_retiming_handle_remove(struct wmOperatorType *ot);
|
||||
|
||||
/* sequencer_gizmo_retime.c */
|
||||
void SEQUENCER_GGT_gizmo_retime(struct wmGizmoGroupType *gzgt);
|
||||
|
||||
/* sequencer_gizmo_retime_type.c */
|
||||
void GIZMO_GT_retime_handle_add(struct wmGizmoType *gzt);
|
||||
void GIZMO_GT_retime_handle(struct wmGizmoType *gzt);
|
||||
void GIZMO_GT_retime_remove(struct wmGizmoType *gzt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -68,12 +68,6 @@ void sequencer_operatortypes(void)
|
||||
WM_operatortype_append(SEQUENCER_OT_cursor_set);
|
||||
WM_operatortype_append(SEQUENCER_OT_scene_frame_range_update);
|
||||
|
||||
/* sequencer_retiming.c */
|
||||
WM_operatortype_append(SEQUENCER_OT_retiming_reset);
|
||||
WM_operatortype_append(SEQUENCER_OT_retiming_handle_move);
|
||||
WM_operatortype_append(SEQUENCER_OT_retiming_handle_add);
|
||||
WM_operatortype_append(SEQUENCER_OT_retiming_handle_remove);
|
||||
|
||||
/* sequencer_select.c */
|
||||
WM_operatortype_append(SEQUENCER_OT_select_all);
|
||||
WM_operatortype_append(SEQUENCER_OT_select);
|
||||
|
||||
@@ -1,442 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup spseq
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "SEQ_iterator.h"
|
||||
#include "SEQ_relations.h"
|
||||
#include "SEQ_retiming.h"
|
||||
#include "SEQ_retiming.hh"
|
||||
#include "SEQ_sequencer.h"
|
||||
#include "SEQ_time.h"
|
||||
#include "SEQ_transform.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
#include "RNA_define.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
||||
/* Own include. */
|
||||
#include "sequencer_intern.h"
|
||||
|
||||
using blender::MutableSpan;
|
||||
|
||||
static bool retiming_poll(bContext *C)
|
||||
{
|
||||
const Editing *ed = SEQ_editing_get(CTX_data_scene(C));
|
||||
if (ed == nullptr) {
|
||||
return false;
|
||||
}
|
||||
Sequence *seq = ed->act_seq;
|
||||
if (seq == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (!SEQ_retiming_is_allowed(seq)) {
|
||||
CTX_wm_operator_poll_msg_set(C, "This strip type can not be retimed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void retiming_handle_overlap(Scene *scene, Sequence *seq)
|
||||
{
|
||||
ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
|
||||
SeqCollection *strips = SEQ_collection_create(__func__);
|
||||
SEQ_collection_append_strip(seq, strips);
|
||||
SeqCollection *dependant = SEQ_collection_create(__func__);
|
||||
SEQ_collection_expand(scene, seqbase, strips, SEQ_query_strip_effect_chain);
|
||||
SEQ_collection_remove_strip(seq, dependant);
|
||||
SEQ_transform_handle_overlap(scene, seqbase, strips, dependant, true);
|
||||
SEQ_collection_free(strips);
|
||||
SEQ_collection_free(dependant);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------- */
|
||||
/** \name Retiming Reset
|
||||
* \{ */
|
||||
|
||||
static int sequencer_retiming_reset_exec(bContext *C, wmOperator * /* op */)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const Editing *ed = SEQ_editing_get(scene);
|
||||
Sequence *seq = ed->act_seq;
|
||||
|
||||
SEQ_retiming_data_clear(seq);
|
||||
|
||||
retiming_handle_overlap(scene, seq);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void SEQUENCER_OT_retiming_reset(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Reset Retiming";
|
||||
ot->description = "Reset strip retiming";
|
||||
ot->idname = "SEQUENCER_OT_retiming_reset";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = sequencer_retiming_reset_exec;
|
||||
ot->poll = retiming_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Retiming Move Handle
|
||||
* \{ */
|
||||
|
||||
static SeqRetimingHandle *closest_retiming_handle_get(const bContext *C,
|
||||
const Sequence *seq,
|
||||
const float mouse_x)
|
||||
{
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
int best_distance = INT_MAX;
|
||||
SeqRetimingHandle *closest_handle = nullptr;
|
||||
|
||||
const float distance_threshold = UI_view2d_region_to_view_x(v2d, 10);
|
||||
const float mouse_x_view = UI_view2d_region_to_view_x(v2d, mouse_x);
|
||||
|
||||
for (int i = 0; i < SEQ_retiming_handles_count(seq); i++) {
|
||||
SeqRetimingHandle *handle = seq->retiming_handles + i;
|
||||
const int distance = round_fl_to_int(
|
||||
fabsf(SEQ_retiming_handle_timeline_frame_get(scene, seq, handle) - mouse_x_view));
|
||||
|
||||
if (distance < distance_threshold && distance < best_distance) {
|
||||
best_distance = distance;
|
||||
closest_handle = handle;
|
||||
}
|
||||
}
|
||||
return closest_handle;
|
||||
}
|
||||
|
||||
static int sequencer_retiming_handle_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const Editing *ed = SEQ_editing_get(scene);
|
||||
Sequence *seq = ed->act_seq;
|
||||
|
||||
int handle_index = 0;
|
||||
if (RNA_struct_property_is_set(op->ptr, "handle_index")) {
|
||||
handle_index = RNA_int_get(op->ptr, "handle_index");
|
||||
}
|
||||
|
||||
/* Ensure retiming handle at left handle position. This way user gets more predictable result
|
||||
* when strips have offsets. */
|
||||
const int left_handle_frame = SEQ_time_left_handle_frame_get(scene, seq);
|
||||
if (SEQ_retiming_add_handle(scene, seq, left_handle_frame) != nullptr) {
|
||||
handle_index++; /* Advance index, because new handle was created. */
|
||||
}
|
||||
|
||||
MutableSpan handles = SEQ_retiming_handles_get(seq);
|
||||
SeqRetimingHandle *handle = nullptr;
|
||||
if (RNA_struct_property_is_set(op->ptr, "handle_index")) {
|
||||
BLI_assert(handle_index < handles.size());
|
||||
handle = &handles[handle_index];
|
||||
}
|
||||
else {
|
||||
handle = closest_retiming_handle_get(C, seq, event->mval[0]);
|
||||
}
|
||||
|
||||
if (handle == nullptr) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No handle available");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
RNA_int_set(op->ptr, "handle_index", SEQ_retiming_handle_index_get(seq, handle));
|
||||
|
||||
if ((event->modifier & KM_SHIFT) != 0) {
|
||||
op->customdata = (void *)1;
|
||||
}
|
||||
|
||||
WM_event_add_modal_handler(C, op);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int sequencer_retiming_handle_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const ARegion *region = CTX_wm_region(C);
|
||||
const View2D *v2d = ®ion->v2d;
|
||||
const Editing *ed = SEQ_editing_get(scene);
|
||||
Sequence *seq = ed->act_seq;
|
||||
|
||||
int handle_index = RNA_int_get(op->ptr, "handle_index");
|
||||
SeqRetimingHandle *handle = &SEQ_retiming_handles_get(seq)[handle_index];
|
||||
|
||||
switch (event->type) {
|
||||
case MOUSEMOVE: {
|
||||
float mouse_x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
|
||||
int offset = 0;
|
||||
|
||||
offset = mouse_x - SEQ_retiming_handle_timeline_frame_get(scene, seq, handle);
|
||||
|
||||
if (offset == 0) {
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
/* Add retiming gradient and move handle. */
|
||||
if (op->customdata) {
|
||||
SeqRetimingHandle *transition_handle = SEQ_retiming_add_transition(
|
||||
scene, seq, handle, abs(offset));
|
||||
/* New gradient handle was created - update operator properties. */
|
||||
if (transition_handle != nullptr) {
|
||||
if (offset < 0) {
|
||||
handle = transition_handle;
|
||||
}
|
||||
else {
|
||||
handle = transition_handle + 1;
|
||||
}
|
||||
RNA_int_set(op->ptr, "handle_index", SEQ_retiming_handle_index_get(seq, handle));
|
||||
}
|
||||
}
|
||||
|
||||
const bool handle_is_transition = SEQ_retiming_handle_is_transition_type(handle);
|
||||
const bool prev_handle_is_transition = SEQ_retiming_handle_is_transition_type(handle - 1);
|
||||
|
||||
/* When working with transition, change handles when moving past pivot point. */
|
||||
if (handle_is_transition || prev_handle_is_transition) {
|
||||
SeqRetimingHandle *transition_start, *transition_end;
|
||||
if (handle_is_transition) {
|
||||
transition_start = handle;
|
||||
transition_end = handle + 1;
|
||||
}
|
||||
else {
|
||||
transition_start = handle - 1;
|
||||
transition_end = handle;
|
||||
}
|
||||
const int offset_l = mouse_x -
|
||||
SEQ_retiming_handle_timeline_frame_get(scene, seq, transition_start);
|
||||
const int offset_r = mouse_x -
|
||||
SEQ_retiming_handle_timeline_frame_get(scene, seq, transition_end);
|
||||
|
||||
if (prev_handle_is_transition && offset_l < 0) {
|
||||
RNA_int_set(
|
||||
op->ptr, "handle_index", SEQ_retiming_handle_index_get(seq, transition_start));
|
||||
}
|
||||
if (handle_is_transition && offset_r > 0) {
|
||||
RNA_int_set(op->ptr, "handle_index", SEQ_retiming_handle_index_get(seq, transition_end));
|
||||
}
|
||||
}
|
||||
|
||||
SEQ_retiming_offset_handle(scene, seq, handle, offset);
|
||||
|
||||
SEQ_relations_invalidate_cache_raw(scene, seq);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
case LEFTMOUSE:
|
||||
case EVT_RETKEY:
|
||||
case EVT_SPACEKEY: {
|
||||
retiming_handle_overlap(scene, seq);
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
case EVT_ESCKEY:
|
||||
case RIGHTMOUSE: {
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
}
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
void SEQUENCER_OT_retiming_handle_move(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Move Retiming Handle";
|
||||
ot->description = "Move retiming handle";
|
||||
ot->idname = "SEQUENCER_OT_retiming_handle_move";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = sequencer_retiming_handle_move_invoke;
|
||||
ot->modal = sequencer_retiming_handle_move_modal;
|
||||
ot->poll = retiming_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
PropertyRNA *prop = RNA_def_int(ot->srna,
|
||||
"handle_index",
|
||||
0,
|
||||
0,
|
||||
INT_MAX,
|
||||
"Handle Index",
|
||||
"Index of handle to be moved",
|
||||
0,
|
||||
INT_MAX);
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Retiming Add Handle
|
||||
* \{ */
|
||||
|
||||
static int sequesequencer_retiming_handle_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const Editing *ed = SEQ_editing_get(scene);
|
||||
Sequence *seq = ed->act_seq;
|
||||
|
||||
SEQ_retiming_data_ensure(seq);
|
||||
|
||||
float timeline_frame;
|
||||
if (RNA_struct_property_is_set(op->ptr, "timeline_frame")) {
|
||||
timeline_frame = RNA_int_get(op->ptr, "timeline_frame");
|
||||
}
|
||||
else {
|
||||
timeline_frame = BKE_scene_frame_get(scene);
|
||||
}
|
||||
|
||||
const int frame_index = BKE_scene_frame_get(scene) - SEQ_time_start_frame_get(seq);
|
||||
const SeqRetimingHandle *handle = SEQ_retiming_find_segment_start_handle(seq, frame_index);
|
||||
|
||||
if (SEQ_retiming_handle_is_transition_type(handle)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Can not create handle inside of speed transition");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
bool inserted = false;
|
||||
const float end_frame = seq->start + SEQ_time_strip_length_get(scene, seq);
|
||||
if (seq->start < timeline_frame && end_frame > timeline_frame) {
|
||||
SEQ_retiming_add_handle(scene, seq, timeline_frame);
|
||||
inserted = true;
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
|
||||
|
||||
return inserted ? OPERATOR_FINISHED : OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
void SEQUENCER_OT_retiming_handle_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Add Retiming Handle";
|
||||
ot->description = "Add retiming Handle";
|
||||
ot->idname = "SEQUENCER_OT_retiming_handle_add";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = sequesequencer_retiming_handle_add_exec;
|
||||
ot->poll = retiming_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"timeline_frame",
|
||||
0,
|
||||
0,
|
||||
INT_MAX,
|
||||
"Timeline Frame",
|
||||
"Frame where handle will be added",
|
||||
0,
|
||||
INT_MAX);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Retiming Remove Handle
|
||||
* \{ */
|
||||
|
||||
static int sequencer_retiming_handle_remove_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const Editing *ed = SEQ_editing_get(scene);
|
||||
Sequence *seq = ed->act_seq;
|
||||
|
||||
SeqRetimingHandle *handle = (SeqRetimingHandle *)op->customdata;
|
||||
SEQ_retiming_remove_handle(scene, seq, handle);
|
||||
SEQ_relations_invalidate_cache_raw(scene, seq);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int sequencer_retiming_handle_remove_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *event)
|
||||
{
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const Editing *ed = SEQ_editing_get(scene);
|
||||
const Sequence *seq = ed->act_seq;
|
||||
|
||||
if (seq == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
MutableSpan handles = SEQ_retiming_handles_get(seq);
|
||||
SeqRetimingHandle *handle = nullptr;
|
||||
|
||||
if (RNA_struct_property_is_set(op->ptr, "handle_index")) {
|
||||
const int handle_index = RNA_int_get(op->ptr, "handle_index");
|
||||
BLI_assert(handle_index < handles.size());
|
||||
handle = &handles[handle_index];
|
||||
}
|
||||
else {
|
||||
handle = closest_retiming_handle_get(C, seq, event->mval[0]);
|
||||
}
|
||||
|
||||
if (handle == nullptr) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No handle available");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
op->customdata = handle;
|
||||
return sequencer_retiming_handle_remove_exec(C, op);
|
||||
}
|
||||
|
||||
void SEQUENCER_OT_retiming_handle_remove(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Remove Retiming Handle";
|
||||
ot->description = "Remove retiming handle";
|
||||
ot->idname = "SEQUENCER_OT_retiming_handle_remove";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = sequencer_retiming_handle_remove_invoke;
|
||||
ot->exec = sequencer_retiming_handle_remove_exec;
|
||||
ot->poll = retiming_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
PropertyRNA *prop = RNA_def_int(ot->srna,
|
||||
"handle_index",
|
||||
0,
|
||||
0,
|
||||
INT_MAX,
|
||||
"Handle Index",
|
||||
"Index of handle to be removed",
|
||||
0,
|
||||
INT_MAX);
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -426,15 +426,10 @@ static void sequencer_gizmos(void)
|
||||
wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(
|
||||
&(const struct wmGizmoMapType_Params){SPACE_SEQ, RGN_TYPE_PREVIEW});
|
||||
|
||||
WM_gizmotype_append(GIZMO_GT_retime_handle_add);
|
||||
WM_gizmotype_append(GIZMO_GT_retime_handle);
|
||||
WM_gizmotype_append(GIZMO_GT_retime_remove);
|
||||
|
||||
WM_gizmogrouptype_append(SEQUENCER_GGT_gizmo2d);
|
||||
WM_gizmogrouptype_append(SEQUENCER_GGT_gizmo2d_translate);
|
||||
WM_gizmogrouptype_append(SEQUENCER_GGT_gizmo2d_resize);
|
||||
WM_gizmogrouptype_append(SEQUENCER_GGT_gizmo2d_rotate);
|
||||
WM_gizmogrouptype_append(SEQUENCER_GGT_gizmo_retime);
|
||||
|
||||
WM_gizmogrouptype_append_and_link(gzmap_type, SEQUENCER_GGT_navigate);
|
||||
}
|
||||
@@ -589,7 +584,6 @@ static void sequencer_main_region_listener(const wmRegionListenerParams *params)
|
||||
case ND_SEQUENCER:
|
||||
case ND_RENDER_RESULT:
|
||||
ED_region_tag_redraw(region);
|
||||
WM_gizmomap_tag_refresh(region->gizmo_map);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -603,7 +597,6 @@ static void sequencer_main_region_listener(const wmRegionListenerParams *params)
|
||||
case NC_SPACE:
|
||||
if (wmn->data == ND_SPACE_SEQUENCER) {
|
||||
ED_region_tag_redraw(region);
|
||||
WM_gizmomap_tag_refresh(region->gizmo_map);
|
||||
}
|
||||
break;
|
||||
case NC_ID:
|
||||
@@ -614,7 +607,6 @@ static void sequencer_main_region_listener(const wmRegionListenerParams *params)
|
||||
case NC_SCREEN:
|
||||
if (ELEM(wmn->data, ND_ANIMPLAY)) {
|
||||
ED_region_tag_redraw(region);
|
||||
WM_gizmomap_tag_refresh(region->gizmo_map);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1031,6 +1023,7 @@ void ED_spacetype_sequencer(void)
|
||||
art->on_view2d_changed = sequencer_main_region_view2d_changed;
|
||||
art->listener = sequencer_main_region_listener;
|
||||
art->message_subscribe = sequencer_main_region_message_subscribe;
|
||||
/* NOTE: inclusion of #ED_KEYMAP_GIZMO is currently for scripts and isn't used by default. */
|
||||
art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES |
|
||||
ED_KEYMAP_ANIMATION;
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
||||
@@ -97,6 +97,8 @@ static eV3D_OpEvent view3d_navigate_event(ViewOpsData *vod, const wmEvent *event
|
||||
{
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
switch (event->val) {
|
||||
case VIEW_MODAL_CANCEL:
|
||||
return VIEW_CANCEL;
|
||||
case VIEW_MODAL_CONFIRM:
|
||||
return VIEW_CONFIRM;
|
||||
case VIEWROT_MODAL_AXIS_SNAP_ENABLE:
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "UI_resources.h"
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#include "transform.h"
|
||||
#include "transform_gizmo.h"
|
||||
@@ -896,13 +897,12 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
|
||||
}
|
||||
else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_ACTION)) {
|
||||
/* only scale y */
|
||||
rcti *mask = &t->region->v2d.mask;
|
||||
rctf *datamask = &t->region->v2d.cur;
|
||||
float xsize = BLI_rctf_size_x(datamask);
|
||||
float ysize = BLI_rctf_size_y(datamask);
|
||||
float xmask = BLI_rcti_size_x(mask);
|
||||
float ymask = BLI_rcti_size_y(mask);
|
||||
GPU_matrix_scale_2f(1.0f, (ysize / xsize) * (xmask / ymask));
|
||||
float xscale, yscale;
|
||||
UI_view2d_scale_get(&t->region->v2d, &xscale, &yscale);
|
||||
|
||||
const float fac_scale = xscale / yscale;
|
||||
GPU_matrix_scale_2f(1.0f, fac_scale);
|
||||
GPU_matrix_translate_2f(0.0f, (t->center_global[1] / fac_scale) - t->center_global[1]);
|
||||
}
|
||||
|
||||
eGPUDepthTest depth_test_enabled = GPU_depth_test_get();
|
||||
|
||||
@@ -588,6 +588,9 @@ static void handle_armature_parent_orientation(Object *ob, float r_mat[3][3])
|
||||
if (active_pchan && active_pchan->parent) {
|
||||
/* For child, show parent local regardless if "local location" is set for parent bone. */
|
||||
transform_orientations_create_from_axis(r_mat, UNPACK3(active_pchan->parent->pose_mat));
|
||||
float ob_orientations_mat[3][3];
|
||||
transform_orientations_create_from_axis(ob_orientations_mat, UNPACK3(ob->object_to_world));
|
||||
mul_m3_m3_pre(r_mat, ob_orientations_mat);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -236,9 +236,7 @@ static void snap_editmesh_minmax(SnapObjectContext *sctx,
|
||||
}
|
||||
}
|
||||
|
||||
static void snap_object_data_mesh_get(SnapObjectContext *sctx,
|
||||
Object *ob_eval,
|
||||
const Mesh *me_eval,
|
||||
static void snap_object_data_mesh_get(const Mesh *me_eval,
|
||||
bool use_hide,
|
||||
BVHTreeFromMesh *r_treedata)
|
||||
{
|
||||
@@ -246,11 +244,6 @@ static void snap_object_data_mesh_get(SnapObjectContext *sctx,
|
||||
const blender::OffsetIndices polys = me_eval->polys();
|
||||
const Span<int> corner_verts = me_eval->corner_verts();
|
||||
|
||||
if (ob_eval->type == OB_MESH) {
|
||||
/* Any existing #SnapData_EditMesh is now invalid. */
|
||||
sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval));
|
||||
}
|
||||
|
||||
/* The BVHTree from looptris is always required. */
|
||||
BKE_bvhtree_from_mesh_get(
|
||||
r_treedata, me_eval, use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI, 4);
|
||||
@@ -678,8 +671,7 @@ static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
|
||||
}
|
||||
}
|
||||
|
||||
static bool raycastMesh(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
static bool raycastMesh(const SnapObjectParams *params,
|
||||
const float ray_start[3],
|
||||
const float ray_dir[3],
|
||||
Object *ob_eval,
|
||||
@@ -747,7 +739,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
|
||||
}
|
||||
|
||||
BVHTreeFromMesh treedata;
|
||||
snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide, &treedata);
|
||||
snap_object_data_mesh_get(me_eval, use_hide, &treedata);
|
||||
|
||||
const blender::Span<int> looptri_polys = me_eval->looptri_polys();
|
||||
|
||||
@@ -1034,8 +1026,7 @@ static eSnapMode raycast_obj_fn(SnapObjectContext *sctx,
|
||||
}
|
||||
else {
|
||||
const Mesh *me_eval = (const Mesh *)ob_data;
|
||||
retval = raycastMesh(sctx,
|
||||
params,
|
||||
retval = raycastMesh(params,
|
||||
dt->ray_start,
|
||||
dt->ray_dir,
|
||||
ob_eval,
|
||||
@@ -1214,7 +1205,6 @@ static bool nearest_world_tree(SnapObjectContext * /*sctx*/,
|
||||
|
||||
static bool nearest_world_mesh(SnapObjectContext *sctx,
|
||||
const struct SnapObjectParams *params,
|
||||
Object *ob_eval,
|
||||
const Mesh *me_eval,
|
||||
const float (*obmat)[4],
|
||||
bool use_hide,
|
||||
@@ -1226,7 +1216,7 @@ static bool nearest_world_mesh(SnapObjectContext *sctx,
|
||||
int *r_index)
|
||||
{
|
||||
BVHTreeFromMesh treedata;
|
||||
snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide, &treedata);
|
||||
snap_object_data_mesh_get(me_eval, use_hide, &treedata);
|
||||
if (treedata.tree == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -1325,7 +1315,6 @@ static eSnapMode nearest_world_object_fn(SnapObjectContext *sctx,
|
||||
const Mesh *me_eval = (const Mesh *)ob_data;
|
||||
retval = nearest_world_mesh(sctx,
|
||||
params,
|
||||
ob_eval,
|
||||
me_eval,
|
||||
obmat,
|
||||
use_hide,
|
||||
@@ -2569,7 +2558,7 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
|
||||
}
|
||||
|
||||
BVHTreeFromMesh treedata, treedata_dummy;
|
||||
snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide, &treedata);
|
||||
snap_object_data_mesh_get(me_eval, use_hide, &treedata);
|
||||
|
||||
BVHTree *bvhtree[2] = {nullptr};
|
||||
bvhtree[0] = BKE_bvhtree_from_mesh_get(&treedata_dummy, me_eval, BVHTREE_FROM_LOOSEEDGES, 2);
|
||||
|
||||
@@ -1511,7 +1511,13 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
pack_island_params.scale_to_fit = RNA_boolean_get(op->ptr, "scale");
|
||||
pack_island_params.merge_overlap = RNA_boolean_get(op->ptr, "merge_overlap");
|
||||
pack_island_params.pin_method = eUVPackIsland_PinMethod(RNA_enum_get(op->ptr, "pin"));
|
||||
|
||||
if (RNA_boolean_get(op->ptr, "pin")) {
|
||||
pack_island_params.pin_method = eUVPackIsland_PinMethod(RNA_enum_get(op->ptr, "pin_method"));
|
||||
}
|
||||
else {
|
||||
pack_island_params.pin_method = ED_UVPACK_PIN_NONE;
|
||||
}
|
||||
|
||||
pack_island_params.margin_method = eUVPackIsland_MarginMethod(
|
||||
RNA_enum_get(op->ptr, "margin_method"));
|
||||
@@ -1591,17 +1597,21 @@ static const EnumPropertyItem pack_shape_method_items[] = {
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
/**
|
||||
* \note #ED_UVPACK_PIN_NONE is exposed as a boolean "pin".
|
||||
* \note #ED_UVPACK_PIN_IGNORE is intentionally not exposed as it is confusing from the UI level
|
||||
* (users can simply not select these islands).
|
||||
* The option is kept kept internally because it's used for live unwrap.
|
||||
*/
|
||||
static const EnumPropertyItem pinned_islands_method_items[] = {
|
||||
{ED_UVPACK_PIN_PACK, "PACK", 0, "Pack", "Pinned islands are packed normally"},
|
||||
{ED_UVPACK_PIN_LOCK_SCALE, "SCALE", 0, "Lock Scale", "Pinned islands won't rescale"},
|
||||
{ED_UVPACK_PIN_LOCK_ROTATION, "ROTATION", 0, "Lock Rotation", "Pinned islands won't rotate"},
|
||||
{ED_UVPACK_PIN_LOCK_SCALE, "SCALE", 0, "Scale", "Pinned islands won't rescale"},
|
||||
{ED_UVPACK_PIN_LOCK_ROTATION, "ROTATION", 0, "Rotation", "Pinned islands won't rotate"},
|
||||
{ED_UVPACK_PIN_LOCK_ROTATION_SCALE,
|
||||
"ROTATION_SCALE",
|
||||
0,
|
||||
"Lock Rotation and Scale",
|
||||
"Rotation and Scale",
|
||||
"Pinned islands will translate only"},
|
||||
{ED_UVPACK_PIN_LOCK_ALL, "LOCKED", 0, "Lock in Place", "Pinned islands are locked in place"},
|
||||
{ED_UVPACK_PIN_IGNORE, "IGNORE", 0, "Ignore", "Pinned islands are not packed"},
|
||||
{ED_UVPACK_PIN_LOCK_ALL, "LOCKED", 0, "All", "Pinned islands are locked in place"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
@@ -1612,15 +1622,23 @@ static void uv_pack_islands_ui(bContext * /*C*/, wmOperator *op)
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
uiItemR(layout, op->ptr, "shape_method", 0, nullptr, ICON_NONE);
|
||||
uiItemR(layout, op->ptr, "scale", 0, nullptr, ICON_NONE);
|
||||
uiItemR(layout, op->ptr, "rotate", 0, nullptr, ICON_NONE);
|
||||
uiLayout *sub = uiLayoutRow(layout, true);
|
||||
uiLayoutSetActive(sub, RNA_boolean_get(op->ptr, "rotate"));
|
||||
uiItemR(sub, op->ptr, "rotate_method", 0, nullptr, ICON_NONE);
|
||||
uiItemS(layout);
|
||||
{
|
||||
uiItemR(layout, op->ptr, "rotate", 0, nullptr, ICON_NONE);
|
||||
uiLayout *sub = uiLayoutRow(layout, true);
|
||||
uiLayoutSetActive(sub, RNA_boolean_get(op->ptr, "rotate"));
|
||||
uiItemR(sub, op->ptr, "rotate_method", 0, nullptr, ICON_NONE);
|
||||
uiItemS(layout);
|
||||
}
|
||||
uiItemR(layout, op->ptr, "margin_method", 0, nullptr, ICON_NONE);
|
||||
uiItemR(layout, op->ptr, "margin", 0, nullptr, ICON_NONE);
|
||||
uiItemS(layout);
|
||||
uiItemR(layout, op->ptr, "pin", 0, nullptr, ICON_NONE);
|
||||
{
|
||||
uiItemR(layout, op->ptr, "pin", 0, nullptr, ICON_NONE);
|
||||
uiLayout *sub = uiLayoutRow(layout, true);
|
||||
uiLayoutSetActive(sub, RNA_boolean_get(op->ptr, "pin"));
|
||||
uiItemR(sub, op->ptr, "pin_method", 0, IFACE_("Lock Method"), ICON_NONE);
|
||||
uiItemS(layout);
|
||||
}
|
||||
uiItemR(layout, op->ptr, "merge_overlap", 0, nullptr, ICON_NONE);
|
||||
uiItemR(layout, op->ptr, "udim_source", 0, nullptr, ICON_NONE);
|
||||
uiItemS(layout);
|
||||
@@ -1686,8 +1704,17 @@ void UV_OT_pack_islands(wmOperatorType *ot)
|
||||
"");
|
||||
RNA_def_float_factor(
|
||||
ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
|
||||
RNA_def_enum(
|
||||
ot->srna, "pin", pinned_islands_method_items, ED_UVPACK_PIN_PACK, "Pinned Islands", "");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"pin",
|
||||
false,
|
||||
"Lock Pinned Islands",
|
||||
"Constrain islands containing any pinned UV's");
|
||||
RNA_def_enum(ot->srna,
|
||||
"pin_method",
|
||||
pinned_islands_method_items,
|
||||
ED_UVPACK_PIN_LOCK_ALL,
|
||||
"Pin Method",
|
||||
"");
|
||||
RNA_def_enum(ot->srna,
|
||||
"shape_method",
|
||||
pack_shape_method_items,
|
||||
|
||||
@@ -47,12 +47,18 @@ enum eUVPackIsland_ShapeMethod {
|
||||
};
|
||||
|
||||
enum eUVPackIsland_PinMethod {
|
||||
ED_UVPACK_PIN_IGNORE = 0,
|
||||
ED_UVPACK_PIN_PACK,
|
||||
/** Pin has no impact on packing. */
|
||||
ED_UVPACK_PIN_NONE = 0,
|
||||
/**
|
||||
* Ignore islands containing any pinned UV's.
|
||||
* \note Not exposed in the UI, used only for live-unwrap.
|
||||
*/
|
||||
ED_UVPACK_PIN_IGNORE,
|
||||
ED_UVPACK_PIN_LOCK_ROTATION,
|
||||
ED_UVPACK_PIN_LOCK_ROTATION_SCALE,
|
||||
ED_UVPACK_PIN_LOCK_SCALE,
|
||||
ED_UVPACK_PIN_LOCK_ALL, /* Lock translation, rotation and scale. */
|
||||
/** Lock the island in-place (translation, rotation and scale). */
|
||||
ED_UVPACK_PIN_LOCK_ALL,
|
||||
};
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
@@ -1455,6 +1455,8 @@ static void customdata_weld(
|
||||
int src_i, dest_i;
|
||||
int j;
|
||||
|
||||
int vs_flag = 0;
|
||||
|
||||
/* interpolates a layer at a time */
|
||||
dest_i = 0;
|
||||
for (src_i = 0; src_i < source->totlayer; src_i++) {
|
||||
@@ -1475,7 +1477,21 @@ static void customdata_weld(
|
||||
/* if we found a matching layer, add the data */
|
||||
if (dest->layers[dest_i].type == type) {
|
||||
void *src_data = source->layers[src_i].data;
|
||||
if (CustomData_layer_has_interp(dest, dest_i)) {
|
||||
if (type == CD_MVERT_SKIN) {
|
||||
/* The `typeInfo->interp` of #CD_MVERT_SKIN does not include the flags, so #MVERT_SKIN_ROOT
|
||||
* and #MVERT_SKIN_LOOSE are lost after the interpolation.
|
||||
*
|
||||
* This behavior is not incorrect. Ideally, islands should be checked to avoid repeated
|
||||
* roots.
|
||||
*
|
||||
* However, for now, to prevent the loss of flags, they are simply re-added if any of the
|
||||
* merged vertices have them. */
|
||||
for (j = 0; j < count; j++) {
|
||||
MVertSkin *vs = &((MVertSkin *)src_data)[src_indices[j]];
|
||||
vs_flag |= vs->flag;
|
||||
}
|
||||
}
|
||||
else if (CustomData_layer_has_interp(dest, dest_i)) {
|
||||
/* Already calculated.
|
||||
* TODO: Optimize by exposing `typeInfo->interp`. */
|
||||
}
|
||||
@@ -1505,7 +1521,11 @@ static void customdata_weld(
|
||||
for (dest_i = 0; dest_i < dest->totlayer; dest_i++) {
|
||||
CustomDataLayer *layer_dst = &dest->layers[dest_i];
|
||||
const eCustomDataType type = eCustomDataType(layer_dst->type);
|
||||
if (CustomData_layer_has_interp(dest, dest_i)) {
|
||||
if (type == CD_MVERT_SKIN) {
|
||||
MVertSkin *vs = &((MVertSkin *)layer_dst->data)[dest_index];
|
||||
vs->flag = vs_flag;
|
||||
}
|
||||
else if (CustomData_layer_has_interp(dest, dest_i)) {
|
||||
/* Already calculated. */
|
||||
}
|
||||
else if (CustomData_layer_has_math(dest, dest_i)) {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_index_mask.hh"
|
||||
#include "BLI_index_mask_ops.hh"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_vector_set.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_attribute_math.hh"
|
||||
@@ -12,12 +15,6 @@
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
/* Naively checks if the first vertices and the second vertices are the same. */
|
||||
static inline bool naive_edges_equal(const int2 &edge1, const int2 &edge2)
|
||||
{
|
||||
return edge1 == edge2;
|
||||
}
|
||||
|
||||
static void add_new_vertices(Mesh &mesh, const Span<int> new_to_old_verts_map)
|
||||
{
|
||||
/* These types aren't supported for interpolation below. */
|
||||
@@ -153,70 +150,6 @@ static void add_new_edges(Mesh &mesh,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the new_edge into the original edge.
|
||||
*
|
||||
* NOTE: This function is very specific to the situation and makes a lot of assumptions.
|
||||
*/
|
||||
static void merge_edges(const int orig_edge_i,
|
||||
const int new_edge_i,
|
||||
MutableSpan<int> new_corner_edges,
|
||||
Vector<Vector<int>> &edge_to_loop_map,
|
||||
Vector<int2> &new_edges,
|
||||
Vector<int> &new_to_old_edges_map)
|
||||
{
|
||||
/* Merge back into the original edge by undoing the topology changes. */
|
||||
BLI_assert(edge_to_loop_map[new_edge_i].size() == 1);
|
||||
const int loop_i = edge_to_loop_map[new_edge_i][0];
|
||||
new_corner_edges[loop_i] = orig_edge_i;
|
||||
|
||||
/* We are putting the last edge in the location of new_edge in all the maps, to remove
|
||||
* new_edge efficiently. We have to update the topology information for this last edge
|
||||
* though. Essentially we are replacing every instance of last_edge_i with new_edge_i. */
|
||||
const int last_edge_i = new_edges.size() - 1;
|
||||
if (last_edge_i != new_edge_i) {
|
||||
BLI_assert(edge_to_loop_map[last_edge_i].size() == 1);
|
||||
const int last_edge_loop_i = edge_to_loop_map[last_edge_i][0];
|
||||
new_corner_edges[last_edge_loop_i] = new_edge_i;
|
||||
}
|
||||
|
||||
/* We can now safely swap-remove. */
|
||||
new_edges.remove_and_reorder(new_edge_i);
|
||||
edge_to_loop_map.remove_and_reorder(new_edge_i);
|
||||
new_to_old_edges_map.remove_and_reorder(new_edge_i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the vertex of an edge with a new one, and update the connected loops.
|
||||
*
|
||||
* NOTE: This only updates the loops containing the edge and the old vertex. It should therefore
|
||||
* also be called on the adjacent edge.
|
||||
*/
|
||||
static void swap_vertex_of_edge(int2 &edge,
|
||||
const int old_vert,
|
||||
const int new_vert,
|
||||
MutableSpan<int> corner_verts,
|
||||
const Span<int> connected_loops)
|
||||
{
|
||||
if (edge[0] == old_vert) {
|
||||
edge[0] = new_vert;
|
||||
}
|
||||
else if (edge[1] == old_vert) {
|
||||
edge[1] = new_vert;
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
for (const int loop_i : connected_loops) {
|
||||
if (corner_verts[loop_i] == old_vert) {
|
||||
corner_verts[loop_i] = new_vert;
|
||||
}
|
||||
/* The old vertex is on the loop containing the adjacent edge. Since this function is also
|
||||
* called on the adjacent edge, we don't replace it here. */
|
||||
}
|
||||
}
|
||||
|
||||
/** Split the vertex into duplicates so that each fan has a different vertex. */
|
||||
static void split_vertex_per_fan(const int vertex,
|
||||
const int start_offset,
|
||||
@@ -224,7 +157,6 @@ static void split_vertex_per_fan(const int vertex,
|
||||
const Span<int> fans,
|
||||
const Span<int> fan_sizes,
|
||||
const Span<Vector<int>> edge_to_loop_map,
|
||||
MutableSpan<int2> new_edges,
|
||||
MutableSpan<int> corner_verts,
|
||||
MutableSpan<int> new_to_old_verts_map)
|
||||
{
|
||||
@@ -236,8 +168,13 @@ static void split_vertex_per_fan(const int vertex,
|
||||
new_to_old_verts_map[new_vert_i - orig_verts_num] = vertex;
|
||||
|
||||
for (const int edge_i : fans.slice(fan_start, fan_sizes[i])) {
|
||||
swap_vertex_of_edge(
|
||||
new_edges[edge_i], vertex, new_vert_i, corner_verts, edge_to_loop_map[edge_i]);
|
||||
for (const int loop_i : edge_to_loop_map[edge_i]) {
|
||||
if (corner_verts[loop_i] == vertex) {
|
||||
corner_verts[loop_i] = new_vert_i;
|
||||
}
|
||||
/* The old vertex is on the loop containing the adjacent edge. Since this function is also
|
||||
* called on the adjacent edge, we don't replace it here. */
|
||||
}
|
||||
}
|
||||
fan_start += fan_sizes[i];
|
||||
}
|
||||
@@ -266,7 +203,7 @@ static int adjacent_edge(const Span<int> corner_verts,
|
||||
* be used to retrieve the fans from connected_edges.
|
||||
*/
|
||||
static void calc_vertex_fans(const int vertex,
|
||||
const Span<int> new_corner_verts,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int> new_corner_edges,
|
||||
const OffsetIndices<int> polys,
|
||||
const Span<Vector<int>> edge_to_loop_map,
|
||||
@@ -297,7 +234,7 @@ static void calc_vertex_fans(const int vertex,
|
||||
/* Add adjacent edges to search stack. */
|
||||
for (const int loop_i : edge_to_loop_map[curr_edge_i]) {
|
||||
const int adjacent_edge_i = adjacent_edge(
|
||||
new_corner_verts, new_corner_edges, loop_i, polys[loop_to_poly_map[loop_i]], vertex);
|
||||
corner_verts, new_corner_edges, loop_i, polys[loop_to_poly_map[loop_i]], vertex);
|
||||
|
||||
/* Find out if this edge was visited already. */
|
||||
int i = curr_i + 1;
|
||||
@@ -339,18 +276,13 @@ static void calc_vertex_fans(const int vertex,
|
||||
static void split_edge_per_poly(const int edge_i,
|
||||
const int new_edge_start,
|
||||
MutableSpan<Vector<int>> edge_to_loop_map,
|
||||
MutableSpan<int> corner_edges,
|
||||
MutableSpan<int2> new_edges,
|
||||
MutableSpan<int> new_to_old_edges_map)
|
||||
MutableSpan<int> corner_edges)
|
||||
{
|
||||
if (edge_to_loop_map[edge_i].size() <= 1) {
|
||||
return;
|
||||
}
|
||||
int new_edge_index = new_edge_start;
|
||||
for (const int loop_i : edge_to_loop_map[edge_i].as_span().drop_front(1)) {
|
||||
const int2 &new_edge(new_edges[edge_i]);
|
||||
new_edges[new_edge_index] = new_edge;
|
||||
new_to_old_edges_map[new_edge_index] = edge_i;
|
||||
edge_to_loop_map[new_edge_index].append({loop_i});
|
||||
corner_edges[loop_i] = new_edge_index;
|
||||
new_edge_index++;
|
||||
@@ -393,30 +325,35 @@ void split_edges(Mesh &mesh,
|
||||
}
|
||||
|
||||
const OffsetIndices polys = mesh.polys();
|
||||
|
||||
MutableSpan<int> corner_verts = mesh.corner_verts_for_write();
|
||||
MutableSpan<int> corner_edges = mesh.corner_edges_for_write();
|
||||
Vector<int2> new_edges(new_edges_size);
|
||||
new_edges.as_mutable_span().take_front(edges.size()).copy_from(edges);
|
||||
const Array<int> orig_corner_edges = mesh.corner_edges();
|
||||
Vector<int64_t> memory;
|
||||
const bke::LooseEdgeCache loose_edges_cache = mesh.loose_edges();
|
||||
IndexMask loose_edges;
|
||||
if (loose_edges_cache.count > 0) {
|
||||
loose_edges = index_mask_ops::find_indices_based_on_predicate(
|
||||
edges.index_range(), 4096, memory, [&](const int64_t i) {
|
||||
return loose_edges_cache.is_loose_bits[i];
|
||||
});
|
||||
}
|
||||
|
||||
edge_to_loop_map.resize(new_edges_size);
|
||||
|
||||
/* Used for transferring attributes. */
|
||||
Vector<int> new_to_old_edges_map(IndexRange(new_edges.size()).as_span());
|
||||
MutableSpan<int> corner_edges = mesh.corner_edges_for_write();
|
||||
|
||||
/* Step 1: Split the edges. */
|
||||
threading::parallel_for(mask.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int mask_i : range) {
|
||||
const int edge_i = mask[mask_i];
|
||||
split_edge_per_poly(edge_i,
|
||||
edge_offsets[edge_i],
|
||||
edge_to_loop_map,
|
||||
corner_edges,
|
||||
new_edges,
|
||||
new_to_old_edges_map);
|
||||
split_edge_per_poly(edge_i, edge_offsets[edge_i], edge_to_loop_map, corner_edges);
|
||||
}
|
||||
});
|
||||
|
||||
/* Step 1: Split the edges. */
|
||||
|
||||
mask.foreach_index([&](const int edge_i) {
|
||||
split_edge_per_poly(edge_i, edge_offsets[edge_i], edge_to_loop_map, corner_edges);
|
||||
});
|
||||
|
||||
/* Step 1.5: Update topology information (can't parallelize). */
|
||||
for (const int edge_i : mask) {
|
||||
const int2 &edge = edges[edge_i];
|
||||
@@ -426,6 +363,8 @@ void split_edges(Mesh &mesh,
|
||||
}
|
||||
}
|
||||
|
||||
MutableSpan<int> corner_verts = mesh.corner_verts_for_write();
|
||||
|
||||
/* Step 2: Calculate vertex fans. */
|
||||
Array<Vector<int>> vertex_fan_sizes(mesh.totvert);
|
||||
threading::parallel_for(IndexRange(mesh.totvert), 512, [&](IndexRange range) {
|
||||
@@ -471,39 +410,43 @@ void split_edges(Mesh &mesh,
|
||||
vert_to_edge_map[vert],
|
||||
vertex_fan_sizes[vert],
|
||||
edge_to_loop_map,
|
||||
new_edges,
|
||||
corner_verts,
|
||||
new_to_old_verts_map);
|
||||
}
|
||||
});
|
||||
|
||||
/* Step 4: Deduplicate edges. We loop backwards so we can use remove_and_reorder. Although this
|
||||
* does look bad (3 nested loops), in practice the inner loops are very small. For most meshes,
|
||||
* there are at most 2 polygons connected to each edge, and hence you'll only get at most 1
|
||||
* duplicate per edge. */
|
||||
for (int mask_i = mask.size() - 1; mask_i >= 0; mask_i--) {
|
||||
const int edge = mask[mask_i];
|
||||
int start_of_duplicates = edge_offsets[edge];
|
||||
int end_of_duplicates = start_of_duplicates + num_edge_duplicates[edge] - 1;
|
||||
for (int duplicate = end_of_duplicates; duplicate >= start_of_duplicates; duplicate--) {
|
||||
if (naive_edges_equal(new_edges[edge], new_edges[duplicate])) {
|
||||
merge_edges(
|
||||
edge, duplicate, corner_edges, edge_to_loop_map, new_edges, new_to_old_edges_map);
|
||||
break;
|
||||
}
|
||||
for (int other = start_of_duplicates; other < duplicate; other++) {
|
||||
if (naive_edges_equal(new_edges[other], new_edges[duplicate])) {
|
||||
merge_edges(
|
||||
other, duplicate, corner_edges, edge_to_loop_map, new_edges, new_to_old_edges_map);
|
||||
break;
|
||||
}
|
||||
}
|
||||
VectorSet<OrderedEdge> new_edges;
|
||||
new_edges.reserve(new_edges_size + loose_edges.size());
|
||||
for (const int i : polys.index_range()) {
|
||||
const IndexRange poly = polys[i];
|
||||
for (const int corner : poly) {
|
||||
const int vert_1 = corner_verts[corner];
|
||||
const int vert_2 = corner_verts[bke::mesh::poly_corner_next(poly, corner)];
|
||||
corner_edges[corner] = new_edges.index_of_or_add_as(OrderedEdge(vert_1, vert_2));
|
||||
}
|
||||
}
|
||||
loose_edges.foreach_index([&](const int64_t i) { new_edges.add(OrderedEdge(edges[i])); });
|
||||
|
||||
Array<int> new_to_old_edges_map(new_edges.size());
|
||||
auto index_mask_to_indices = [&](const IndexMask &mask, MutableSpan<int> indices) {
|
||||
for (const int i : mask.index_range()) {
|
||||
indices[i] = mask[i];
|
||||
}
|
||||
};
|
||||
index_mask_to_indices(loose_edges,
|
||||
new_to_old_edges_map.as_mutable_span().take_back(loose_edges.size()));
|
||||
for (const int i : polys.index_range()) {
|
||||
const IndexRange poly = polys[i];
|
||||
for (const int corner : poly) {
|
||||
const int new_edge_i = corner_edges[corner];
|
||||
const int old_edge_i = orig_corner_edges[corner];
|
||||
new_to_old_edges_map[new_edge_i] = old_edge_i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 5: Resize the mesh to add the new vertices and rebuild the edges. */
|
||||
add_new_vertices(mesh, new_to_old_verts_map);
|
||||
add_new_edges(mesh, new_edges, new_to_old_edges_map, propagation_info);
|
||||
add_new_edges(mesh, new_edges.as_span().cast<int2>(), new_to_old_edges_map, propagation_info);
|
||||
|
||||
BKE_mesh_tag_edges_split(&mesh);
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ UVPackIsland_Params::UVPackIsland_Params()
|
||||
only_selected_faces = false;
|
||||
use_seams = false;
|
||||
correct_aspect = false;
|
||||
pin_method = ED_UVPACK_PIN_PACK;
|
||||
pin_method = ED_UVPACK_PIN_NONE;
|
||||
pin_unselected = false;
|
||||
merge_overlap = false;
|
||||
margin = 0.001f;
|
||||
|
||||
@@ -751,7 +751,8 @@ inline size_t to_bytesize(eGPUTextureFormat tex_format, eGPUDataFormat data_form
|
||||
* Standard component len calculation does not apply, as the texture formats contain multiple
|
||||
* channels, but associated data format contains several compacted components. */
|
||||
if ((tex_format == GPU_R11F_G11F_B10F && data_format == GPU_DATA_10_11_11_REV) ||
|
||||
(tex_format == GPU_RGB10_A2 && data_format == GPU_DATA_2_10_10_10_REV))
|
||||
((tex_format == GPU_RGB10_A2 || tex_format == GPU_RGB10_A2UI) &&
|
||||
data_format == GPU_DATA_2_10_10_10_REV))
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
@@ -107,6 +107,11 @@ class MTLUniformBuf;
|
||||
/* MTLBuffer allocation wrapper. */
|
||||
class MTLBuffer {
|
||||
|
||||
public:
|
||||
/* NOTE: ListBase API is not used due to cutsom destructor operation required to release
|
||||
* Metal objective C buffer resource. */
|
||||
gpu::MTLBuffer *next, *prev;
|
||||
|
||||
private:
|
||||
/* Metal resource. */
|
||||
id<MTLBuffer> metal_buffer_;
|
||||
@@ -177,6 +182,8 @@ class MTLBuffer {
|
||||
|
||||
/* Safety check to ensure buffers are not used after free. */
|
||||
void debug_ensure_used();
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("MTLBuffer");
|
||||
};
|
||||
|
||||
/* View into part of an MTLBuffer. */
|
||||
@@ -333,6 +340,8 @@ class MTLSafeFreeList {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("MTLSafeFreeList");
|
||||
};
|
||||
|
||||
/* MTLBuffer pools. */
|
||||
@@ -362,7 +371,7 @@ class MTLBufferPool {
|
||||
#endif
|
||||
|
||||
/* Metal resources. */
|
||||
bool ensure_initialised_ = false;
|
||||
bool initialized_ = false;
|
||||
id<MTLDevice> device_ = nil;
|
||||
|
||||
/* The buffer selection aims to pick a buffer which meets the minimum size requirements.
|
||||
@@ -389,7 +398,10 @@ class MTLBufferPool {
|
||||
|
||||
std::mutex buffer_pool_lock_;
|
||||
blender::Map<MTLBufferResourceOptions, MTLBufferPoolOrderedList *> buffer_pools_;
|
||||
blender::Vector<gpu::MTLBuffer *> allocations_;
|
||||
|
||||
/* Linked list to track all existing allocations. Prioritizing fast insert/deletion. */
|
||||
gpu::MTLBuffer *allocations_list_base_;
|
||||
uint allocations_list_size_;
|
||||
|
||||
/* Maintain a queue of all MTLSafeFreeList's that have been released
|
||||
* by the GPU and are ready to have their buffers re-inserted into the
|
||||
@@ -432,6 +444,11 @@ class MTLBufferPool {
|
||||
void ensure_buffer_pool(MTLResourceOptions options);
|
||||
void insert_buffer_into_pool(MTLResourceOptions options, gpu::MTLBuffer *buffer);
|
||||
void free();
|
||||
|
||||
/* Allocations list. */
|
||||
void allocations_list_insert(gpu::MTLBuffer *buffer);
|
||||
void allocations_list_delete(gpu::MTLBuffer *buffer);
|
||||
void allocations_list_delete_all();
|
||||
};
|
||||
|
||||
/* Scratch buffers are circular-buffers used for temporary data within the current frame.
|
||||
@@ -492,6 +509,8 @@ class MTLScratchBufferManager {
|
||||
* This call will perform a partial flush of the buffer starting from
|
||||
* the last offset the data was flushed from, to the current offset. */
|
||||
void flush_active_scratch_buffer();
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("MTLBufferPool");
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user