UI: Asset Shelf (Experimental Feature) #104831

Closed
Julian Eisel wants to merge 399 commits from asset-shelf into main

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

View File

@ -8,7 +8,7 @@
# It also supports non-standard names for the library components.
#
# To use a custom IlmBase:
# - Set the variable ILMBASE_CUSTOM to True
# - Set the variable ILMBASE_CUSTOM to TRUE
# - Set the variable ILMBASE_CUSTOM_LIBRARIES to a list of the libraries to
# use, e.g. "SpiImath SpiHalf SpiIlmThread SpiIex"
# - Optionally set the variable ILMBASE_CUSTOM_INCLUDE_DIR to any
@ -20,7 +20,7 @@
#
# ILMBASE_INCLUDE_DIR - where to find half.h, IlmBaseConfig.h, etc.
# ILMBASE_LIBRARIES - list of libraries to link against when using IlmBase.
# ILMBASE_FOUND - True if IlmBase was found.
# ILMBASE_FOUND - TRUE if IlmBase was found.
# Other standard issue macros
include(FindPackageHandleStandardArgs)

View File

@ -8,7 +8,7 @@
# It also supports non-standard names for the library components.
#
# To use a custom OpenEXR
# - Set the variable OPENEXR_CUSTOM to True
# - Set the variable OPENEXR_CUSTOM to TRUE
# - Set the variable OPENEXR_CUSTOM_LIBRARY to the name of the library to
# use, e.g. "SpiIlmImf"
# - Optionally set the variable OPENEXR_CUSTOM_INCLUDE_DIR to any
@ -22,7 +22,7 @@
# OPENEXR_LIBRARIES - list of libraries to link against when using OpenEXR.
# This list does NOT include the IlmBase libraries.
# These are defined by the FindIlmBase module.
# OPENEXR_FOUND - True if OpenEXR was found.
# OPENEXR_FOUND - TRUE if OpenEXR was found.
# Other standard issue macros
include(SelectLibraryConfigurations)

View File

@ -20,14 +20,14 @@ else()
# Choose the best suitable libraries.
if(EXISTS ${LIBDIR_NATIVE_ABI})
set(LIBDIR ${LIBDIR_NATIVE_ABI})
set(WITH_LIBC_MALLOC_HOOK_WORKAROUND True)
set(WITH_LIBC_MALLOC_HOOK_WORKAROUND TRUE)
elseif(EXISTS ${LIBDIR_GLIBC228_ABI})
set(LIBDIR ${LIBDIR_GLIBC228_ABI})
if(WITH_MEM_JEMALLOC)
# jemalloc provides malloc hooks.
set(WITH_LIBC_MALLOC_HOOK_WORKAROUND False)
set(WITH_LIBC_MALLOC_HOOK_WORKAROUND FALSE)
else()
set(WITH_LIBC_MALLOC_HOOK_WORKAROUND True)
set(WITH_LIBC_MALLOC_HOOK_WORKAROUND TRUE)
endif()
endif()

View File

@ -1034,7 +1034,7 @@ endif()
if(WITH_VULKAN_BACKEND)
if(EXISTS ${LIBDIR}/vulkan)
set(VULKAN_FOUND On)
set(VULKAN_FOUND ON)
set(VULKAN_ROOT_DIR ${LIBDIR}/vulkan)
set(VULKAN_INCLUDE_DIR ${VULKAN_ROOT_DIR}/include)
set(VULKAN_INCLUDE_DIRS ${VULKAN_INCLUDE_DIR})
@ -1048,7 +1048,7 @@ endif()
if(WITH_VULKAN_BACKEND)
if(EXISTS ${LIBDIR}/shaderc)
set(SHADERC_FOUND On)
set(SHADERC_FOUND ON)
set(SHADERC_ROOT_DIR ${LIBDIR}/shaderc)
set(SHADERC_INCLUDE_DIR ${SHADERC_ROOT_DIR}/include)
set(SHADERC_INCLUDE_DIRS ${SHADERC_INCLUDE_DIR})

View File

@ -8,3 +8,5 @@ Local modifications:
* Added special definitions of HAVE_SNPRINTF and HAVE_LIB_GFLAGS
in Windows' specific config.h.
* Silenced syscall deprecation warnings on macOS >= 10.12.
* Usage of syscall() is not allowed and use getthrid() to
retreive the thread ID on OpenBSD

View File

@ -2,6 +2,8 @@
#include "config_mac.h"
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include "config_freebsd.h"
#elif defined(__OpenBSD__)
#include "config_openbsd.h"
#elif defined(__MINGW32__)
#include "windows/config.h"
#elif defined(__linux__)

192
extern/glog/src/config_openbsd.h vendored Normal file
View File

@ -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. */
/* #undef 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. */
/* #undef 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

View File

@ -59,7 +59,8 @@
# include <unistd.h>
#endif
#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && (!(defined OS_MACOSX))
#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && \
(!(defined OS_MACOSX) && !(defined OS_OPENBSD))
# define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)
#else
// Not so safe, but what can you do?

View File

@ -282,6 +282,8 @@ pid_t GetTID() {
return getpid(); // Linux: getpid returns thread ID when gettid is absent
#elif defined OS_WINDOWS && !defined OS_CYGWIN
return GetCurrentThreadId();
#elif defined OS_OPENBSD
return getthrid();
#else
// If none of the techniques above worked, we use pthread_self().
return (pid_t)(uintptr_t)pthread_self();

View File

@ -67,7 +67,7 @@ if(UNIX AND NOT APPLE)
add_subdirectory(libc_compat)
endif()
if (WITH_RENDERDOC)
if(WITH_RENDERDOC)
add_subdirectory(renderdoc_dynload)
endif()

View File

@ -262,6 +262,11 @@ string OneapiDevice::oneapi_error_message()
return string(oneapi_error_string_);
}
int OneapiDevice::scene_max_shaders()
{
return scene_max_shaders_;
}
void *OneapiDevice::kernel_globals_device_pointer()
{
return kg_memory_device_;
@ -436,6 +441,9 @@ void OneapiDevice::const_copy_to(const char *name, void *host, size_t size)
/* Update scene handle(since it is different for each device on multi devices) */
KernelData *const data = (KernelData *)host;
data->device_bvh = embree_scene;
/* We need this number later for proper local memory allocation. */
scene_max_shaders_ = data->max_shaders;
}
# endif

View File

@ -37,6 +37,7 @@ class OneapiDevice : public Device {
std::string oneapi_error_string_;
bool use_hardware_raytracing = false;
unsigned int kernel_features = 0;
int scene_max_shaders_ = 0;
public:
virtual BVHLayoutMask get_bvh_layout_mask(uint kernel_features) const override;
@ -61,6 +62,8 @@ class OneapiDevice : public Device {
string oneapi_error_message();
int scene_max_shaders();
void *kernel_globals_device_pointer();
void mem_alloc(device_memory &mem) override;

View File

@ -59,7 +59,7 @@ void OneapiDeviceQueue::init_execution()
void *kg_dptr = (void *)oneapi_device_->kernel_globals_device_pointer();
assert(device_queue);
assert(kg_dptr);
kernel_context_ = new KernelContext{device_queue, kg_dptr};
kernel_context_ = new KernelContext{device_queue, kg_dptr, 0};
debug_init_execution();
}
@ -78,12 +78,13 @@ bool OneapiDeviceQueue::enqueue(DeviceKernel kernel,
assert(signed_kernel_work_size >= 0);
size_t kernel_work_size = (size_t)signed_kernel_work_size;
assert(kernel_context_);
kernel_context_->scene_max_shaders = oneapi_device_->scene_max_shaders();
size_t kernel_local_size = oneapi_kernel_preferred_local_size(
kernel_context_->queue, (::DeviceKernel)kernel, kernel_work_size);
size_t uniformed_kernel_work_size = round_up(kernel_work_size, kernel_local_size);
assert(kernel_context_);
/* Call the oneAPI kernel DLL to launch the requested kernel. */
bool is_finished_ok = oneapi_device_->enqueue_kernel(
kernel_context_, kernel, uniformed_kernel_work_size, args);

View File

@ -39,6 +39,11 @@ class OneapiDeviceQueue : public DeviceQueue {
virtual void copy_to_device(device_memory &mem) override;
virtual void copy_from_device(device_memory &mem) override;
virtual bool supports_local_atomic_sort() const
{
return true;
}
protected:
OneapiDevice *oneapi_device_;
KernelContext *kernel_context_;

View File

@ -385,11 +385,17 @@ void PathTraceWorkGPU::enqueue_reset()
queue_->enqueue(DEVICE_KERNEL_INTEGRATOR_RESET, max_num_paths_, args);
queue_->zero_to_device(integrator_queue_counter_);
queue_->zero_to_device(integrator_shader_sort_counter_);
if (device_scene_->data.kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) {
if (integrator_shader_sort_counter_.size() != 0) {
queue_->zero_to_device(integrator_shader_sort_counter_);
}
if (device_scene_->data.kernel_features & KERNEL_FEATURE_NODE_RAYTRACE &&
integrator_shader_raytrace_sort_counter_.size() != 0)
{
queue_->zero_to_device(integrator_shader_raytrace_sort_counter_);
}
if (device_scene_->data.kernel_features & KERNEL_FEATURE_MNEE) {
if (device_scene_->data.kernel_features & KERNEL_FEATURE_MNEE &&
integrator_shader_mnee_sort_counter_.size() != 0)
{
queue_->zero_to_device(integrator_shader_mnee_sort_counter_);
}

View File

@ -847,6 +847,7 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
-DWITH_ONEAPI
-ffast-math
-O2
-D__KERNEL_LOCAL_ATOMIC_SORT__
-o"${cycles_kernel_oneapi_lib}"
-I"${CMAKE_CURRENT_SOURCE_DIR}/.."
${SYCL_CPP_FLAGS}

View File

@ -432,6 +432,17 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)
}
ccl_gpu_kernel_postfix
/* oneAPI verion needs the local_mem accessor in the arguments. */
#ifdef __KERNEL_ONEAPI__
ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
ccl_gpu_kernel_signature(integrator_sort_bucket_pass,
int num_states,
int partition_size,
int num_states_limit,
ccl_global int *indices,
int kernel_index,
sycl::local_accessor<int> &local_mem)
#else
ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
ccl_gpu_kernel_signature(integrator_sort_bucket_pass,
int num_states,
@ -439,9 +450,9 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
int num_states_limit,
ccl_global int *indices,
int kernel_index)
#endif
{
#if defined(__KERNEL_LOCAL_ATOMIC_SORT__)
int max_shaders = context.launch_params_metal.data.max_shaders;
ccl_global ushort *d_queued_kernel = (ccl_global ushort *)
kernel_integrator_state.path.queued_kernel;
ccl_global uint *d_shader_sort_key = (ccl_global uint *)
@ -449,6 +460,20 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
ccl_global int *key_offsets = (ccl_global int *)
kernel_integrator_state.sort_partition_key_offsets;
# ifdef __KERNEL_METAL__
int max_shaders = context.launch_params_metal.data.max_shaders;
# endif
# ifdef __KERNEL_ONEAPI__
/* Metal backend doesn't have these particular ccl_gpu_* defines and current kernel code
* uses metal_*, we need the below to be compatible with these kernels. */
int max_shaders = ((ONEAPIKernelContext *)kg)->__data->max_shaders;
int metal_local_id = ccl_gpu_thread_idx_x;
int metal_local_size = ccl_gpu_block_dim_x;
int metal_grid_id = ccl_gpu_block_idx_x;
ccl_gpu_shared int *threadgroup_array = local_mem.get_pointer();
# endif
gpu_parallel_sort_bucket_pass(num_states,
partition_size,
max_shaders,
@ -456,7 +481,7 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
d_queued_kernel,
d_shader_sort_key,
key_offsets,
(threadgroup int *)threadgroup_array,
(ccl_gpu_shared int *)threadgroup_array,
metal_local_id,
metal_local_size,
metal_grid_id);
@ -464,6 +489,17 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
}
ccl_gpu_kernel_postfix
/* oneAPI verion needs the local_mem accessor in the arguments. */
#ifdef __KERNEL_ONEAPI__
ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
ccl_gpu_kernel_signature(integrator_sort_write_pass,
int num_states,
int partition_size,
int num_states_limit,
ccl_global int *indices,
int kernel_index,
sycl::local_accessor<int> &local_mem)
#else
ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
ccl_gpu_kernel_signature(integrator_sort_write_pass,
int num_states,
@ -471,9 +507,10 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
int num_states_limit,
ccl_global int *indices,
int kernel_index)
#endif
{
#if defined(__KERNEL_LOCAL_ATOMIC_SORT__)
int max_shaders = context.launch_params_metal.data.max_shaders;
ccl_global ushort *d_queued_kernel = (ccl_global ushort *)
kernel_integrator_state.path.queued_kernel;
ccl_global uint *d_shader_sort_key = (ccl_global uint *)
@ -481,6 +518,20 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
ccl_global int *key_offsets = (ccl_global int *)
kernel_integrator_state.sort_partition_key_offsets;
# ifdef __KERNEL_METAL__
int max_shaders = context.launch_params_metal.data.max_shaders;
# endif
# ifdef __KERNEL_ONEAPI__
/* Metal backend doesn't have these particular ccl_gpu_* defines and current kernel code
* uses metal_*, we need the below to be compatible with these kernels. */
int max_shaders = ((ONEAPIKernelContext *)kg)->__data->max_shaders;
int metal_local_id = ccl_gpu_thread_idx_x;
int metal_local_size = ccl_gpu_block_dim_x;
int metal_grid_id = ccl_gpu_block_idx_x;
ccl_gpu_shared int *threadgroup_array = local_mem.get_pointer();
# endif
gpu_parallel_sort_write_pass(num_states,
partition_size,
max_shaders,
@ -490,7 +541,7 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
d_queued_kernel,
d_shader_sort_key,
key_offsets,
(threadgroup int *)threadgroup_array,
(ccl_gpu_shared int *)threadgroup_array,
metal_local_id,
metal_local_size,
metal_grid_id);

View File

@ -23,11 +23,6 @@ CCL_NAMESPACE_BEGIN
#if defined(__KERNEL_LOCAL_ATOMIC_SORT__)
# define atomic_store_local(p, x) \
atomic_store_explicit((threadgroup atomic_int *)p, x, memory_order_relaxed)
# define atomic_load_local(p) \
atomic_load_explicit((threadgroup atomic_int *)p, memory_order_relaxed)
ccl_device_inline void gpu_parallel_sort_bucket_pass(const uint num_states,
const uint partition_size,
const uint max_shaders,
@ -45,7 +40,13 @@ ccl_device_inline void gpu_parallel_sort_bucket_pass(const uint num_states,
atomic_store_local(&buckets[local_id], 0);
}
# ifdef __KERNEL_ONEAPI__
/* NOTE(@nsirgien): For us here only local memory writing (buckets) is important,
* so faster local barriers can be used. */
ccl_gpu_local_syncthreads();
# else
ccl_gpu_syncthreads();
# endif
/* Determine bucket sizes within the partitions. */
@ -58,11 +59,17 @@ ccl_device_inline void gpu_parallel_sort_bucket_pass(const uint num_states,
ushort kernel_index = d_queued_kernel[state_index];
if (kernel_index == queued_kernel) {
uint key = d_shader_sort_key[state_index] % max_shaders;
atomic_fetch_and_add_uint32(&buckets[key], 1);
atomic_fetch_and_add_uint32_shared(&buckets[key], 1);
}
}
# ifdef __KERNEL_ONEAPI__
/* NOTE(@nsirgien): For us here only local memory writing (buckets) is important,
* so faster local barriers can be used. */
ccl_gpu_local_syncthreads();
# else
ccl_gpu_syncthreads();
# endif
/* Calculate the partition's local offsets from the prefix sum of bucket sizes. */
@ -106,7 +113,13 @@ ccl_device_inline void gpu_parallel_sort_write_pass(const uint num_states,
atomic_store_local(&local_offset[local_id], key_offsets[local_id] + partition_offset);
}
# ifdef __KERNEL_ONEAPI__
/* NOTE(@nsirgien): For us here only local memory writing (local_offset) is important,
* so faster local barriers can be used. */
ccl_gpu_local_syncthreads();
# else
ccl_gpu_syncthreads();
# endif
/* Write the sorted active indices. */
@ -121,7 +134,7 @@ ccl_device_inline void gpu_parallel_sort_write_pass(const uint num_states,
ushort kernel_index = d_queued_kernel[state_index];
if (kernel_index == queued_kernel) {
uint key = d_shader_sort_key[state_index] % max_shaders;
int index = atomic_fetch_and_add_uint32(&local_offset[key], 1);
int index = atomic_fetch_and_add_uint32_shared(&local_offset[key], 1);
if (index < num_states_limit) {
indices[index] = state_index;
}

View File

@ -48,6 +48,7 @@
#define ccl_loop_no_unroll
#define ccl_optional_struct_init
#define ccl_private
#define ccl_gpu_shared
#define ATTR_FALLTHROUGH __attribute__((fallthrough))
#define ccl_constant const
#define ccl_try_align(...) __attribute__((aligned(__VA_ARGS__)))

View File

@ -2,8 +2,40 @@
* Copyright 2021-2022 Intel Corporation */
#ifdef WITH_NANOVDB
/* Data type to replace `double` used in the NanoVDB headers. Cycles don't need doubles, and is
* safer and more portable to never use double datatype on GPU.
* Use a special structure, so that the following is true:
* - No unnoticed implicit cast or mathematical operations used on scalar 64bit type
* (which rules out trick like using `uint64_t` as a drop-in replacement for double).
* - Padding rules are matching exactly `double`
* (which rules out array of `uint8_t`). */
typedef struct ccl_vdb_double_t {
union ccl_vdb_helper_t {
double d;
uint64_t i;
};
uint64_t i;
ccl_vdb_double_t(double value)
{
ccl_vdb_helper_t helper;
helper.d = value;
i = helper.i;
}
/* We intentionally allow conversion to float in order to workaround compilation errors
* for defined math functions that take doubles. */
operator float() const
{
ccl_vdb_helper_t helper;
helper.i = i;
return (float)helper.d;
}
} ccl_vdb_double_t;
# define double ccl_vdb_double_t
# include <nanovdb/NanoVDB.h>
# include <nanovdb/util/SampleFromVoxels.h>
# undef double
#endif
/* clang-format off */

View File

@ -109,7 +109,10 @@ size_t oneapi_kernel_preferred_local_size(SyclQueue *queue,
assert(queue);
(void)kernel_global_size;
const static size_t preferred_work_group_size_intersect_shading = 32;
const static size_t preferred_work_group_size_technical = 1024;
/* Shader evalutation kernels seems to use some amount of shared memory, so better
* to avoid usage of maximum work group sizes for them. */
const static size_t preferred_work_group_size_shader_evaluation = 256;
const static size_t preferred_work_group_size_default = 1024;
size_t preferred_work_group_size = 0;
switch (kernel) {
@ -133,19 +136,36 @@ size_t oneapi_kernel_preferred_local_size(SyclQueue *queue,
case DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY:
case DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY:
case DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY:
case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY:
case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY:
case DEVICE_KERNEL_INTEGRATOR_COMPACT_STATES:
case DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY:
case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY:
case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY:
preferred_work_group_size = GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE;
break;
case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY:
case DEVICE_KERNEL_INTEGRATOR_COMPACT_STATES:
case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_STATES:
case DEVICE_KERNEL_INTEGRATOR_RESET:
case DEVICE_KERNEL_INTEGRATOR_SHADOW_CATCHER_COUNT_POSSIBLE_SPLITS:
preferred_work_group_size = preferred_work_group_size_technical;
preferred_work_group_size = GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE;
break;
case DEVICE_KERNEL_INTEGRATOR_SORT_BUCKET_PASS:
case DEVICE_KERNEL_INTEGRATOR_SORT_WRITE_PASS:
preferred_work_group_size = GPU_PARALLEL_SORT_BLOCK_SIZE;
break;
case DEVICE_KERNEL_PREFIX_SUM:
preferred_work_group_size = GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE;
break;
case DEVICE_KERNEL_SHADER_EVAL_DISPLACE:
case DEVICE_KERNEL_SHADER_EVAL_BACKGROUND:
case DEVICE_KERNEL_SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY:
preferred_work_group_size = preferred_work_group_size_shader_evaluation;
break;
default:
preferred_work_group_size = 512;
preferred_work_group_size = preferred_work_group_size_default;
break;
}
const size_t limit_work_group_size = reinterpret_cast<sycl::queue *>(queue)
@ -316,12 +336,6 @@ bool oneapi_enqueue_kernel(KernelContext *kernel_context,
kernel_context->queue, device_kernel, global_size);
assert(global_size % local_size == 0);
/* Local size for DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY needs to be enforced so we
* overwrite it outside of oneapi_kernel_preferred_local_size. */
if (device_kernel == DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY) {
local_size = GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE;
}
/* Kernels listed below need a specific number of work groups. */
if (device_kernel == DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY ||
device_kernel == DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY ||
@ -353,6 +367,14 @@ bool oneapi_enqueue_kernel(KernelContext *kernel_context,
# pragma GCC diagnostic error "-Wswitch"
# endif
int max_shaders = 0;
if (device_kernel == DEVICE_KERNEL_INTEGRATOR_SORT_BUCKET_PASS ||
device_kernel == DEVICE_KERNEL_INTEGRATOR_SORT_WRITE_PASS)
{
max_shaders = (kernel_context->scene_max_shaders);
}
try {
queue->submit([&](sycl::handler &cgh) {
# ifdef WITH_EMBREE_GPU
@ -495,13 +517,31 @@ bool oneapi_enqueue_kernel(KernelContext *kernel_context,
break;
}
case DEVICE_KERNEL_INTEGRATOR_SORT_BUCKET_PASS: {
oneapi_call(
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_sort_bucket_pass);
sycl::local_accessor<int> local_mem(max_shaders, cgh);
oneapi_kernel_integrator_sort_bucket_pass(kg,
global_size,
local_size,
cgh,
*(int *)(args[0]),
*(int *)(args[1]),
*(int *)(args[2]),
*(int **)(args[3]),
*(int *)(args[4]),
local_mem);
break;
}
case DEVICE_KERNEL_INTEGRATOR_SORT_WRITE_PASS: {
oneapi_call(
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_sort_write_pass);
sycl::local_accessor<int> local_mem(max_shaders, cgh);
oneapi_kernel_integrator_sort_write_pass(kg,
global_size,
local_size,
cgh,
*(int *)(args[0]),
*(int *)(args[1]),
*(int *)(args[2]),
*(int **)(args[3]),
*(int *)(args[4]),
local_mem);
break;
}
case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY: {

View File

@ -32,6 +32,8 @@ struct KernelContext {
SyclQueue *queue;
/* Pointer to USM device memory with all global/constant allocation on this device */
void *kernel_globals;
/* We needs this additional data for some kernels. */
int scene_max_shaders;
};
/* Use extern C linking so that the symbols can be easily load from the dynamic library at runtime.

View File

@ -21,6 +21,10 @@
#else /* __KERNEL_GPU__ */
# ifndef __KERNEL_ONEAPI__
# define atomic_fetch_and_add_uint32_shared atomic_fetch_and_add_uint32
# endif
# if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
# define atomic_add_and_fetch_float(p, x) (atomicAdd((float *)(p), (float)(x)) + (float)(x))
@ -140,6 +144,11 @@ ccl_device_inline float atomic_compare_and_swap_float(volatile ccl_global float
# define atomic_store(p, x) atomic_store_explicit(p, x, memory_order_relaxed)
# define atomic_fetch(p) atomic_load_explicit(p, memory_order_relaxed)
# define atomic_store_local(p, x) \
atomic_store_explicit((ccl_gpu_shared atomic_int *)p, x, memory_order_relaxed)
# define atomic_load_local(p) \
atomic_load_explicit((ccl_gpu_shared atomic_int *)p, memory_order_relaxed)
# define CCL_LOCAL_MEM_FENCE mem_flags::mem_threadgroup
# define ccl_barrier(flags) threadgroup_barrier(flags)
@ -191,6 +200,16 @@ ccl_device_inline int atomic_fetch_and_add_uint32(ccl_global int *p, int x)
return atomic.fetch_add(x);
}
ccl_device_inline int atomic_fetch_and_add_uint32_shared(int *p, int x)
{
sycl::atomic_ref<int,
sycl::memory_order::relaxed,
sycl::memory_scope::device,
sycl::access::address_space::local_space>
atomic(*p);
return atomic.fetch_add(x);
}
ccl_device_inline unsigned int atomic_fetch_and_sub_uint32(ccl_global unsigned int *p,
unsigned int x)
{
@ -253,6 +272,26 @@ ccl_device_inline int atomic_fetch_and_or_uint32(ccl_global int *p, int x)
return atomic.fetch_or(x);
}
ccl_device_inline void atomic_store_local(int *p, int x)
{
sycl::atomic_ref<int,
sycl::memory_order::relaxed,
sycl::memory_scope::device,
sycl::access::address_space::local_space>
atomic(*p);
atomic.store(x);
}
ccl_device_inline int atomic_load_local(int *p)
{
sycl::atomic_ref<int,
sycl::memory_order::relaxed,
sycl::memory_scope::device,
sycl::access::address_space::local_space>
atomic(*p);
return atomic.load();
}
# endif /* __KERNEL_ONEAPI__ */
#endif /* __KERNEL_GPU__ */

View File

@ -134,6 +134,21 @@ ccl_device_inline float len(const float2 a)
return sqrtf(dot(a, a));
}
ccl_device_inline float reduce_min(const float2 a)
{
return min(a.x, a.y);
}
ccl_device_inline float reduce_max(const float2 a)
{
return max(a.x, a.y);
}
ccl_device_inline float reduce_add(const float2 a)
{
return a.x + a.y;
}
ccl_device_inline float len_squared(const float2 a)
{
return dot(a, a);

View File

@ -9,9 +9,9 @@ set(INC_SYS
)
set(SRC
intern/renderdoc_api.cc
intern/renderdoc_api.cc
include/renderdoc_api.hh
include/renderdoc_api.hh
)
blender_add_lib(bf_intern_renderdoc_dynload "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

Binary file not shown.

View File

@ -204,7 +204,7 @@ def dump_rna_messages(msgs, reports, settings, verbose=False):
def class_blacklist():
blacklist_rna_class = {getattr(bpy.types, cls_id) for cls_id in (
# core classes
"Context", "Event", "Function", "UILayout", "UnknownType", "Property", "Struct",
"Context", "Event", "Function", "UILayout", "UnknownType", "Struct",
# registerable classes
"Panel", "Menu", "Header", "RenderEngine", "Operator", "OperatorMacro", "Macro", "KeyingSetInfo",
)

View File

@ -256,6 +256,25 @@ PYGETTEXT_KEYWORDS = (() +
tuple(("{}\\((?:[^,]+,){{2}}\\s*" + _msg_re + r"\s*(?:\)|,)").format(it)
for it in ("modifier_subpanel_register", "gpencil_modifier_subpanel_register")) +
# Node socket declarations: contextless names
tuple((r"\.{}<decl::.*?>\(\s*" + _msg_re + r"(?:,[^),]+)*\s*\)").format(it)
for it in ("add_input", "add_output")) +
# Node socket declarations: names with contexts
tuple((r"\.{}<decl::.*?>\(\s*" + _msg_re + r"[^;]*\.translation_context\(\s*" + _ctxt_re + r"\s*\)").format(it)
for it in ("add_input", "add_output")) +
# Node socket declarations: description and error messages
tuple((r"\.{}\(\s*" + _msg_re + r"\s*\)").format(it)
for it in ("description", "error_message_add")) +
# Node socket labels
tuple((r"{}\(\s*[^,]+,\s*" + _msg_re + r"\s*\)").format(it)
for it in ("node_sock_label",)) +
# Geometry Nodes field inputs
((r"FieldInput\(CPPType::get<.*?>\(\),\s*" + _msg_re + r"\s*\)"),) +
# bUnitDef unit names.
# NOTE: regex is a bit more complex than it would need too. Since the actual
# identifier (`B_UNIT_DEF_`) is at the end, if it's simpler/too general it

View File

@ -9,7 +9,10 @@ from bpy.props import (
FloatProperty,
IntProperty,
)
from bpy.app.translations import pgettext_tip as tip_
from bpy.app.translations import (
pgettext_tip as tip_,
pgettext_data as data_,
)
def object_ensure_material(obj, mat_name):
@ -119,7 +122,7 @@ class QuickFur(ObjectModeOperator, Operator):
noise_group = bpy.data.node_groups["Hair Curves Noise"] if self.use_noise else None
frizz_group = bpy.data.node_groups["Frizz Hair Curves"] if self.use_frizz else None
material = bpy.data.materials.new("Fur Material")
material = bpy.data.materials.new(data_("Fur Material"))
mesh_with_zero_area = False
mesh_missing_uv_map = False
@ -146,7 +149,7 @@ class QuickFur(ObjectModeOperator, Operator):
else:
density = count / area
generate_modifier = curves_object.modifiers.new(name="Generate", type='NODES')
generate_modifier = curves_object.modifiers.new(name=data_("Generate"), type='NODES')
generate_modifier.node_group = generate_group
generate_modifier["Input_2"] = mesh_object
generate_modifier["Input_18_attribute_name"] = curves.surface_uv_map
@ -155,11 +158,11 @@ class QuickFur(ObjectModeOperator, Operator):
generate_modifier["Input_22"] = material
generate_modifier["Input_15"] = density * 0.01
radius_modifier = curves_object.modifiers.new(name="Set Hair Curve Profile", type='NODES')
radius_modifier = curves_object.modifiers.new(name=data_("Set Hair Curve Profile"), type='NODES')
radius_modifier.node_group = radius_group
radius_modifier["Input_3"] = self.radius
interpolate_modifier = curves_object.modifiers.new(name="Interpolate Hair Curves", type='NODES')
interpolate_modifier = curves_object.modifiers.new(name=data_("Interpolate Hair Curves"), type='NODES')
interpolate_modifier.node_group = interpolate_group
interpolate_modifier["Input_2"] = mesh_object
interpolate_modifier["Input_18_attribute_name"] = curves.surface_uv_map
@ -169,11 +172,11 @@ class QuickFur(ObjectModeOperator, Operator):
interpolate_modifier["Input_24"] = True
if noise_group:
noise_modifier = curves_object.modifiers.new(name="Hair Curves Noise", type='NODES')
noise_modifier = curves_object.modifiers.new(name=data_("Hair Curves Noise"), type='NODES')
noise_modifier.node_group = noise_group
if frizz_group:
frizz_modifier = curves_object.modifiers.new(name="Frizz Hair Curves", type='NODES')
frizz_modifier = curves_object.modifiers.new(name=data_("Frizz Hair Curves"), type='NODES')
frizz_modifier.node_group = frizz_group
if self.apply_hair_guides:

View File

@ -613,6 +613,7 @@ class NODE_MT_category_GEO_VOLUME(Menu):
layout.separator()
node_add_menu.add_node_type(layout, "GeometryNodeMeanFilterSDFVolume")
node_add_menu.add_node_type(layout, "GeometryNodeOffsetSDFVolume")
node_add_menu.add_node_type(layout, "GeometryNodeSampleVolume")
node_add_menu.add_node_type(layout, "GeometryNodeSDFVolumeSphere")
node_add_menu.add_node_type(layout, "GeometryNodeInputSignedDistance")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)

View File

@ -148,7 +148,7 @@ class BONE_PT_curved(BoneButtonsPanel, Panel):
col = topcol.column(align=True)
col.prop(bbone, "bbone_rollin", text="Roll In")
col.prop(bbone, "bbone_rollout", text="Out")
col.prop(bbone, "bbone_rollout", text="Out", text_ctxt=i18n_contexts.id_armature)
col.prop(bone, "use_endroll_as_inroll")
col = topcol.column(align=True)

View File

@ -810,7 +810,7 @@ class ASSETBROWSER_UL_metadata_tags(UIList):
row = layout.row(align=True)
# Non-editable entries would show grayed-out, which is bad in this specific case, so switch to mere label.
if tag.is_property_readonly("name"):
row.label(text=tag.name, icon_value=icon)
row.label(text=tag.name, icon_value=icon, translate=False)
else:
row.prop(tag, "name", text="", emboss=False, icon_value=icon)

View File

@ -886,7 +886,8 @@ class NodeTreeInterfacePanel(Panel):
props = property_row.operator_menu_enum(
"node.tree_socket_change_type",
"socket_type",
text=active_socket.bl_label if active_socket.bl_label else active_socket.bl_idname,
text=(iface_(active_socket.bl_label) if active_socket.bl_label
else iface_(active_socket.bl_idname)),
)
props.in_out = in_out
@ -904,10 +905,8 @@ class NodeTreeInterfacePanel(Panel):
props = property_row.operator_menu_enum(
"node.tree_socket_change_subtype",
"socket_subtype",
text=(
active_socket.bl_subtype_label if active_socket.bl_subtype_label else
active_socket.bl_idname
),
text=(iface_(active_socket.bl_subtype_label) if active_socket.bl_subtype_label
else iface_(active_socket.bl_idname)),
)
layout.use_property_split = True

View File

@ -500,23 +500,21 @@ class _defs_view3d_add:
# Layout tweaks here would be good to avoid,
# this shows limits in layout engine, as buttons are using a lot of space.
@staticmethod
def draw_settings_interactive_add(layout, tool, extra):
def draw_settings_interactive_add(layout, tool_settings, tool, extra):
show_extra = False
props = tool.operator_properties("view3d.interactive_add")
if not extra:
row = layout.row()
row.label(text="Depth:")
row = layout.row()
row.prop(props, "plane_depth", text="")
row.prop(tool_settings, "plane_depth", text="")
row = layout.row()
row.label(text="Orientation:")
row = layout.row()
row.prop(props, "plane_orientation", text="")
row.prop(tool_settings, "plane_orientation", text="")
row = layout.row()
row.prop(props, "snap_target")
row.prop(tool_settings, "snap_elements_tool")
region_is_header = bpy.context.region.type == 'TOOL_HEADER'
if region_is_header:
# Don't draw the "extra" popover here as we might have other settings & this should be last.
show_extra = True
@ -524,9 +522,10 @@ class _defs_view3d_add:
extra = True
if extra:
props = tool.operator_properties("view3d.interactive_add")
layout.use_property_split = True
layout.row().prop(props, "plane_axis", expand=True)
layout.row().prop(props, "plane_axis_auto")
layout.row().prop(tool_settings, "plane_axis", expand=True)
layout.row().prop(tool_settings, "plane_axis_auto")
layout.label(text="Base")
layout.row().prop(props, "plane_origin_base", expand=True)
@ -538,8 +537,8 @@ class _defs_view3d_add:
@ToolDef.from_fn
def cube_add():
def draw_settings(_context, layout, tool, *, extra=False):
show_extra = _defs_view3d_add.draw_settings_interactive_add(layout, tool, extra)
def draw_settings(context, layout, tool, *, extra=False):
show_extra = _defs_view3d_add.draw_settings_interactive_add(layout, context.tool_settings, tool, extra)
if show_extra:
layout.popover("TOPBAR_PT_tool_settings_extra", text="...")
@ -557,8 +556,8 @@ class _defs_view3d_add:
@ToolDef.from_fn
def cone_add():
def draw_settings(_context, layout, tool, *, extra=False):
show_extra = _defs_view3d_add.draw_settings_interactive_add(layout, tool, extra)
def draw_settings(context, layout, tool, *, extra=False):
show_extra = _defs_view3d_add.draw_settings_interactive_add(layout, context.tool_settings, tool, extra)
if extra:
return
@ -583,8 +582,8 @@ class _defs_view3d_add:
@ToolDef.from_fn
def cylinder_add():
def draw_settings(_context, layout, tool, *, extra=False):
show_extra = _defs_view3d_add.draw_settings_interactive_add(layout, tool, extra)
def draw_settings(context, layout, tool, *, extra=False):
show_extra = _defs_view3d_add.draw_settings_interactive_add(layout, context.tool_settings, tool, extra)
if extra:
return
@ -608,8 +607,8 @@ class _defs_view3d_add:
@ToolDef.from_fn
def uv_sphere_add():
def draw_settings(_context, layout, tool, *, extra=False):
show_extra = _defs_view3d_add.draw_settings_interactive_add(layout, tool, extra)
def draw_settings(context, layout, tool, *, extra=False):
show_extra = _defs_view3d_add.draw_settings_interactive_add(layout, context.tool_settings, tool, extra)
if extra:
return
@ -633,8 +632,8 @@ class _defs_view3d_add:
@ToolDef.from_fn
def ico_sphere_add():
def draw_settings(_context, layout, tool, *, extra=False):
show_extra = _defs_view3d_add.draw_settings_interactive_add(layout, tool, extra)
def draw_settings(context, layout, tool, *, extra=False):
show_extra = _defs_view3d_add.draw_settings_interactive_add(layout, context.tool_settings, tool, extra)
if extra:
return

View File

@ -61,8 +61,8 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_pointcache_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_pointcloud_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_rigidbody_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_scene_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_scene_enums.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_scene_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_screen_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sdna_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sequence_types.h

View File

@ -840,12 +840,12 @@ bool AssetCatalogDefinitionFile::write_to_disk(const CatalogFilePath &dest_file_
return false;
}
if (BLI_exists(dest_file_path.c_str())) {
if (BLI_rename(dest_file_path.c_str(), backup_path.c_str())) {
if (BLI_rename_overwrite(dest_file_path.c_str(), backup_path.c_str())) {
/* TODO: communicate what went wrong. */
return false;
}
}
if (BLI_rename(writable_path.c_str(), dest_file_path.c_str())) {
if (BLI_rename_overwrite(writable_path.c_str(), dest_file_path.c_str())) {
/* TODO: communicate what went wrong. */
return false;
}

View File

@ -25,7 +25,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 10
#define BLENDER_FILE_SUBVERSION 11
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@ -111,12 +111,12 @@ typedef struct LibraryIDLinkCallbackData {
* 'Real' ID, the one that might be in bmain, only differs from self_id when the later is an
* embedded one.
*/
struct ID *id_owner;
struct ID *owner_id;
/**
* ID from which the current ID pointer is being processed. It may be an embedded ID like master
* collection or root node tree.
*/
struct ID *id_self;
struct ID *self_id;
struct ID **id_pointer;
int cb_flag;
} LibraryIDLinkCallbackData;
@ -259,17 +259,17 @@ void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, int c
int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used);
/**
* Say whether given \a id_owner may use (in any way) a data-block of \a id_type_used.
* Say whether given \a owner_id may use (in any way) a data-block of \a id_type_used.
*
* This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above,
* quite useful to reduce useless iterations in some cases.
*/
bool BKE_library_id_can_use_idtype(struct ID *id_owner, short id_type_used);
bool BKE_library_id_can_use_idtype(struct ID *owner_id, short id_type_used);
/**
* Given the id_owner return the type of id_types it can use as a filter_id.
* Given the owner_id return the type of id_types it can use as a filter_id.
*/
uint64_t BKE_library_id_can_use_filter_id(const struct ID *id_owner, const bool include_ui);
uint64_t BKE_library_id_can_use_filter_id(const struct ID *owner_id, const bool include_ui);
/**
* Check whether given ID is used locally (i.e. by another non-linked ID).

View File

@ -120,7 +120,18 @@ enum {
typedef struct Main {
struct Main *next, *prev;
/** The file-path of this blend file, an empty string indicates an unsaved file. */
/**
* The file-path of this blend file, an empty string indicates an unsaved file.
*
* \note For the current loaded blend file this path should be absolute & normalized
* to prevent redundant leading slashes or current-working-directory relative paths
* from causing problems with absolute/relative patch conversion that relies on this being
* an absolute path. See #BLI_path_canonicalize_native.
*
* This rule is not strictly enforced as in some cases loading a #Main is performed
* to read data temporarily (preferences & startup) for e.g.
* where the `filepath` is not persistent or used as a basis for other paths.
*/
char filepath[1024]; /* 1024 = FILE_MAX */
short versionfile, subversionfile; /* see BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION */
short minversionfile, minsubversionfile;

View File

@ -1304,6 +1304,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define GEO_NODE_SIMULATION_INPUT 2100
#define GEO_NODE_SIMULATION_OUTPUT 2101
#define GEO_NODE_INPUT_SIGNED_DISTANCE 2102
#define GEO_NODE_SAMPLE_VOLUME 2103
/** \} */

View File

@ -39,8 +39,6 @@ bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree);
void ntreeFreeLocalNode(bNodeTree *ntree, bNode *node);
bNode *ntreeFindType(bNodeTree *ntree, int type);
void ntreeUpdateAllNew(Main *main);
void ntreeNodeFlagSet(const bNodeTree *ntree, int flag, bool enable);
@ -215,44 +213,38 @@ void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userd
* A dangling reroute node is a reroute node that does *not* have a "data source", i.e. no
* non-reroute node is connected to its input.
*/
bool nodeIsDanglingReroute(const struct bNodeTree *ntree, const struct bNode *node);
bool nodeIsDanglingReroute(const bNodeTree *ntree, const bNode *node);
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
const struct bNodeSocket *from,
const struct bNodeSocket *to);
struct bNode *nodeGetActivePaintCanvas(struct bNodeTree *ntree);
bNode *nodeGetActivePaintCanvas(bNodeTree *ntree);
/**
* \brief Does the given node supports the sub active flag.
*
* \param sub_active: The active flag to check. #NODE_ACTIVE_TEXTURE / #NODE_ACTIVE_PAINT_CANVAS.
*/
bool nodeSupportsActiveFlag(const struct bNode *node, int sub_active);
bool nodeSupportsActiveFlag(const bNode *node, int sub_active);
void nodeSetSocketAvailability(struct bNodeTree *ntree,
struct bNodeSocket *sock,
bool is_available);
void nodeSetSocketAvailability(bNodeTree *ntree, bNodeSocket *sock, bool is_available);
/**
* If the node implements a `declare` function, this function makes sure that `node->declaration`
* is up to date. It is expected that the sockets of the node are up to date already.
*/
bool nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node);
bool nodeDeclarationEnsure(bNodeTree *ntree, bNode *node);
/**
* Just update `node->declaration` if necessary. This can also be called on nodes that may not be
* up to date (e.g. because the need versioning or are dynamic).
*/
bool nodeDeclarationEnsureOnOutdatedNode(struct bNodeTree *ntree, struct bNode *node);
bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *ntree, bNode *node);
/**
* Update `socket->declaration` for all sockets in the node. This assumes that the node declaration
* and sockets are up to date already.
*/
void nodeSocketDeclarationsUpdate(struct bNode *node);
void nodeSocketDeclarationsUpdate(bNode *node);
typedef GHashIterator bNodeInstanceHashIterator;
using bNodeInstanceHashIterator = GHashIterator;
BLI_INLINE bNodeInstanceHashIterator *node_instance_hash_iterator_new(bNodeInstanceHash *hash)
{
@ -316,6 +308,7 @@ void node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, bool re
/* -------------------------------------------------------------------- */
/** \name Node Type Access
* \{ */
void nodeLabel(const bNodeTree *ntree, const bNode *node, char *label, int maxlen);
/**
@ -347,7 +340,7 @@ void node_type_size_preset(bNodeType *ntype, eNodeSizePreset size);
/** \name Node Generic Functions
* \{ */
bool node_is_connected_to_output(const struct bNodeTree *ntree, const struct bNode *node);
bool node_is_connected_to_output(const bNodeTree *ntree, const bNode *node);
bNodeSocket *node_find_enabled_socket(bNode &node, eNodeSocketInOut in_out, StringRef name);

View File

@ -154,6 +154,8 @@ 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,

View File

@ -443,6 +443,7 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
BKE_node.hh
BKE_node_runtime.hh
BKE_node_tree_update.h
BKE_node_tree_zones.hh

View File

@ -897,8 +897,7 @@ void BKE_appdir_program_path_init(const char *argv0)
* Otherwise other methods of detecting the binary that override this argument
* which must point to the Python module for data-files to be detected. */
STRNCPY(g_app.program_filepath, argv0);
BLI_path_abs_from_cwd(g_app.program_filepath, sizeof(g_app.program_filepath));
BLI_path_normalize_native(g_app.program_filepath);
BLI_path_canonicalize_native(g_app.program_filepath, sizeof(g_app.program_filepath));
if (g_app.program_dirname[0] == '\0') {
/* First time initializing, the file binary path isn't valid from a Python module.

View File

@ -952,7 +952,7 @@ static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_d
* meshes for shape keys e.g.), or this is an unsupported case (two shape-keys depending on
* each-other need to be also 'linked' in by their respective meshes, independent shape-keys
* are not allowed). ref #96048. */
if (id != cb_data->id_self && BKE_idtype_idcode_is_linkable(GS(cb_data->id_self->name))) {
if (id != cb_data->self_id && BKE_idtype_idcode_is_linkable(GS(cb_data->self_id->name))) {
BKE_library_foreach_ID_link(
cb_data->bmain, id, foreach_libblock_link_append_callback, data, IDWALK_NOP);
}
@ -972,7 +972,7 @@ static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_d
const bool do_recursive = (data->lapp_context->params->flag & BLO_LIBLINK_APPEND_RECURSIVE) !=
0 ||
do_link;
if (!do_recursive && cb_data->id_owner->lib != id->lib) {
if (!do_recursive && cb_data->owner_id->lib != id->lib) {
return IDWALK_RET_NOP;
}

View File

@ -513,7 +513,14 @@ static bool relative_convert_foreach_path_cb(BPathForeachPathData *bpath_data,
data->count_changed++;
}
else {
BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made relative", path_src);
const char *type_name = BKE_idtype_get_info_from_id(bpath_data->owner_id)->name;
const char *id_name = bpath_data->owner_id->name + 2;
BKE_reportf(data->reports,
RPT_WARNING,
"Path '%s' cannot be made relative for %s '%s'",
path_src,
type_name,
id_name);
data->count_failed++;
}
return true;
@ -537,7 +544,14 @@ static bool absolute_convert_foreach_path_cb(BPathForeachPathData *bpath_data,
data->count_changed++;
}
else {
BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
const char *type_name = BKE_idtype_get_info_from_id(bpath_data->owner_id)->name;
const char *id_name = bpath_data->owner_id->name + 2;
BKE_reportf(data->reports,
RPT_WARNING,
"Path '%s' cannot be made absolute for %s '%s'",
path_src,
type_name,
id_name);
data->count_failed++;
}
return true;

View File

@ -1733,7 +1733,8 @@ static void sizelimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *U
float obsize[3], size[3];
mat4_to_size(size, cob->matrix);
mat4_to_size(obsize, cob->matrix);
copy_v3_v3(obsize, size);
if (data->flag & LIMIT_XMIN) {
if (size[0] < data->xmin) {

View File

@ -173,7 +173,7 @@ static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData *
/* Even though the ID itself remain the same after being made local, from depsgraph point of
* view this is a different ID. Hence we need to tag all of its users for COW update. */
DEG_id_tag_update_ex(
cb_data->bmain, cb_data->id_owner, ID_RECALC_TAG_FOR_UNDO | ID_RECALC_COPY_ON_WRITE);
cb_data->bmain, cb_data->owner_id, ID_RECALC_TAG_FOR_UNDO | ID_RECALC_COPY_ON_WRITE);
return IDWALK_RET_STOP_ITER;
}
return IDWALK_RET_NOP;
@ -396,7 +396,7 @@ void BKE_id_newptr_and_tag_clear(ID *id)
static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
{
Main *bmain = cb_data->bmain;
ID *id_self = cb_data->id_self;
ID *self_id = cb_data->self_id;
ID **id_pointer = cb_data->id_pointer;
int const cb_flag = cb_data->cb_flag;
const int flags = POINTER_AS_INT(cb_data->user_data);
@ -412,7 +412,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
* local directly), its embedded IDs should also have already been duplicated, and hence be
* fully local here already. */
if (*id_pointer != NULL && ID_IS_LINKED(*id_pointer)) {
BLI_assert(*id_pointer != id_self);
BLI_assert(*id_pointer != self_id);
BKE_lib_id_clear_library_data(bmain, *id_pointer, flags);
}
@ -423,7 +423,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
* (through drivers)...
* Just skip it, shape key can only be either indirectly linked, or fully local, period.
* And let's curse one more time that stupid useless shape-key ID type! */
if (*id_pointer && *id_pointer != id_self &&
if (*id_pointer && *id_pointer != self_id &&
BKE_idtype_idcode_is_linkable(GS((*id_pointer)->name)))
{
id_lib_extern(*id_pointer);
@ -583,14 +583,14 @@ static int id_copy_libmanagement_cb(LibraryIDLinkCallbackData *cb_data)
/* Remap self-references to new copied ID. */
if (id == data->id_src) {
/* We cannot use id_self here, it is not *always* id_dst (thanks to $£!+@#&/? nodetrees). */
/* We cannot use self_id here, it is not *always* id_dst (thanks to $£!+@#&/? nodetrees). */
id = *id_pointer = data->id_dst;
}
/* Increase used IDs refcount if needed and required. */
if ((data->flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0 && (cb_flag & IDWALK_CB_USER)) {
if ((data->flag & LIB_ID_CREATE_NO_MAIN) != 0) {
BLI_assert(cb_data->id_self->tag & LIB_TAG_NO_MAIN);
BLI_assert(cb_data->self_id->tag & LIB_TAG_NO_MAIN);
id_us_plus_no_lib(id);
}
else {

View File

@ -373,7 +373,7 @@ bool BKE_lib_override_library_property_is_animated(const ID *id,
static int foreachid_is_hierarchy_leaf_fn(LibraryIDLinkCallbackData *cb_data)
{
ID *id_owner = cb_data->id_owner;
ID *id_owner = cb_data->owner_id;
ID *id = *cb_data->id_pointer;
bool *is_leaf = static_cast<bool *>(cb_data->user_data);
@ -3194,7 +3194,7 @@ static int lib_override_sort_libraries_func(LibraryIDLinkCallbackData *cb_data)
if (cb_data->cb_flag & IDWALK_CB_LOOPBACK) {
return IDWALK_RET_NOP;
}
ID *id_owner = cb_data->id_owner;
ID *id_owner = cb_data->owner_id;
ID *id = *cb_data->id_pointer;
if (id != nullptr && ID_IS_LINKED(id) && id->lib != id_owner->lib) {
const int owner_library_indirect_level = ID_IS_LINKED(id_owner) ? id_owner->lib->temp_index :

View File

@ -87,8 +87,8 @@ void BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int
const int callback_return = data->callback(
&(struct LibraryIDLinkCallbackData){.user_data = data->user_data,
.bmain = data->bmain,
.id_owner = data->owner_id,
.id_self = data->self_id,
.owner_id = data->owner_id,
.self_id = data->self_id,
.id_pointer = id_pp,
.cb_flag = cb_flag});
if (flag & IDWALK_READONLY) {
@ -126,7 +126,7 @@ int BKE_lib_query_foreachid_process_callback_flag_override(LibraryForeachIDData
}
static bool library_foreach_ID_link(Main *bmain,
ID *id_owner,
ID *owner_id,
ID *id,
LibraryIDLinkCallback callback,
void *user_data,
@ -192,7 +192,7 @@ static void library_foreach_ID_data_cleanup(LibraryForeachIDData *data)
/** \return false in case iteration over ID pointers must be stopped, true otherwise. */
static bool library_foreach_ID_link(Main *bmain,
ID *id_owner,
ID *owner_id,
ID *id,
LibraryIDLinkCallback callback,
void *user_data,
@ -259,7 +259,7 @@ static bool library_foreach_ID_link(Main *bmain,
* knowledge of the owner ID then.
* While not great, and that should be probably sanitized at some point, we cal live with it
* for now. */
data.owner_id = ((id->flag & LIB_EMBEDDED_DATA) != 0 && id_owner != NULL) ? id_owner :
data.owner_id = ((id->flag & LIB_EMBEDDED_DATA) != 0 && owner_id != NULL) ? owner_id :
data.self_id;
/* inherit_data is non-NULL when this function is called for some sub-data ID
@ -374,13 +374,13 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
}
}
uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner, const bool include_ui)
uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id, const bool include_ui)
{
/* any type of ID can be used in custom props. */
if (id_owner->properties) {
if (owner_id->properties) {
return FILTER_ID_ALL;
}
const short id_type_owner = GS(id_owner->name);
const short id_type_owner = GS(owner_id->name);
/* IDProps of armature bones and nodes, and bNode->id can use virtually any type of ID. */
if (ELEM(id_type_owner, ID_NT, ID_AR)) {
@ -395,16 +395,16 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner, const bool include
/* Casting to non const.
* TODO(jbakker): We should introduce a ntree_id_has_tree function as we are actually not
* interested in the result. */
if (ntreeFromID((ID *)id_owner)) {
if (ntreeFromID((ID *)owner_id)) {
return FILTER_ID_ALL;
}
if (BKE_animdata_from_id(id_owner)) {
if (BKE_animdata_from_id(owner_id)) {
/* AnimationData can use virtually any kind of data-blocks, through drivers especially. */
return FILTER_ID_ALL;
}
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_owner)) {
if (ID_IS_OVERRIDE_LIBRARY_REAL(owner_id)) {
/* LibOverride data 'hierarchy root' can virtually point back to any type of ID. */
return FILTER_ID_ALL;
}
@ -496,14 +496,14 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner, const bool include
return 0;
}
bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
bool BKE_library_id_can_use_idtype(ID *owner_id, const short id_type_used)
{
/* any type of ID can be used in custom props. */
if (id_owner->properties) {
if (owner_id->properties) {
return true;
}
const short id_type_owner = GS(id_owner->name);
const short id_type_owner = GS(owner_id->name);
/* Exception for ID_LI as they don't exist as a filter. */
if (id_type_used == ID_LI) {
return id_type_owner == ID_LI;
@ -520,7 +520,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
}
const uint64_t filter_id_type_used = BKE_idtype_idcode_to_idfilter(id_type_used);
const uint64_t can_be_used = BKE_library_id_can_use_filter_id(id_owner, false);
const uint64_t can_be_used = BKE_library_id_can_use_filter_id(owner_id, false);
return (can_be_used & filter_id_type_used) != 0;
}
@ -866,7 +866,7 @@ void BKE_lib_query_unused_ids_tag(Main *bmain,
static int foreach_libblock_used_linked_data_tag_clear_cb(LibraryIDLinkCallbackData *cb_data)
{
ID *self_id = cb_data->id_self;
ID *self_id = cb_data->self_id;
ID **id_p = cb_data->id_pointer;
const int cb_flag = cb_data->cb_flag;
bool *is_changed = cb_data->user_data;

View File

@ -177,8 +177,8 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
ID *id_owner = cb_data->id_owner;
ID *id_self = cb_data->id_self;
ID *id_owner = cb_data->owner_id;
ID *id_self = cb_data->self_id;
ID **id_p = cb_data->id_pointer;
IDRemap *id_remap_data = cb_data->user_data;

View File

@ -230,22 +230,22 @@ void BKE_main_unlock(struct Main *bmain)
static int main_relations_create_idlink_cb(LibraryIDLinkCallbackData *cb_data)
{
MainIDRelations *bmain_relations = cb_data->user_data;
ID *id_self = cb_data->id_self;
ID *self_id = cb_data->self_id;
ID **id_pointer = cb_data->id_pointer;
const int cb_flag = cb_data->cb_flag;
if (*id_pointer) {
MainIDRelationsEntry **entry_p;
/* Add `id_pointer` as child of `id_self`. */
/* Add `id_pointer` as child of `self_id`. */
{
if (!BLI_ghash_ensure_p(
bmain_relations->relations_from_pointers, id_self, (void ***)&entry_p)) {
bmain_relations->relations_from_pointers, self_id, (void ***)&entry_p)) {
*entry_p = MEM_callocN(sizeof(**entry_p), __func__);
(*entry_p)->session_uuid = id_self->session_uuid;
(*entry_p)->session_uuid = self_id->session_uuid;
}
else {
BLI_assert((*entry_p)->session_uuid == id_self->session_uuid);
BLI_assert((*entry_p)->session_uuid == self_id->session_uuid);
}
MainIDRelationsEntryItem *to_id_entry = BLI_mempool_alloc(bmain_relations->entry_items_pool);
to_id_entry->next = (*entry_p)->to_ids;
@ -256,7 +256,7 @@ static int main_relations_create_idlink_cb(LibraryIDLinkCallbackData *cb_data)
(*entry_p)->to_ids = to_id_entry;
}
/* Add `id_self` as parent of `id_pointer`. */
/* Add `self_id` as parent of `id_pointer`. */
if (*id_pointer != NULL) {
if (!BLI_ghash_ensure_p(
bmain_relations->relations_from_pointers, *id_pointer, (void ***)&entry_p)) {
@ -269,8 +269,8 @@ static int main_relations_create_idlink_cb(LibraryIDLinkCallbackData *cb_data)
MainIDRelationsEntryItem *from_id_entry = BLI_mempool_alloc(
bmain_relations->entry_items_pool);
from_id_entry->next = (*entry_p)->from_ids;
from_id_entry->id_pointer.from = id_self;
from_id_entry->session_uuid = id_self->session_uuid;
from_id_entry->id_pointer.from = self_id;
from_id_entry->session_uuid = self_id->session_uuid;
from_id_entry->usage_flag = cb_flag;
(*entry_p)->from_ids = from_id_entry;
}

File diff suppressed because it is too large Load Diff

View File

@ -335,7 +335,7 @@ int BKE_packedfile_write_to_file(ReportList *reports,
if (remove_tmp) {
if (ret_value == RET_ERROR) {
if (BLI_rename(filepath_temp, filepath) != 0) {
if (BLI_rename_overwrite(filepath_temp, filepath) != 0) {
BKE_reportf(reports,
RPT_ERROR,
"Error restoring temp file (check files '%s' '%s')",

View File

@ -3531,7 +3531,7 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
if (frame != -1) {
BLI_path_join(old_path_full, sizeof(old_path_full), path, de->d_name);
ptcache_filepath(pid, new_path_full, frame, true, true);
BLI_rename(old_path_full, new_path_full);
BLI_rename_overwrite(old_path_full, new_path_full);
}
}
}

View File

@ -819,6 +819,11 @@ 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,
@ -1379,6 +1384,12 @@ 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),

View File

@ -39,10 +39,29 @@ extern "C" {
*/
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_copy(const char *file, const char *to) ATTR_NONNULL();
/**
* Rename a file or directory.
*
* \return zero on success (matching 'rename' behavior).
*/
int BLI_rename(const char *from, const char *to) ATTR_NONNULL();
int BLI_rename(const char *from, const char *to);
/**
* Rename a file or directory.
*
* \warning It's up to the caller to ensure `from` & `to` don't point to the same file
* as this will result in `to` being deleted to make room for `from`
* (which will then also be deleted).
*
* See #BLI_path_move to move directories.
*
* \param from: The path to rename from (return failure if it does not exist).
* \param to: The destination path.
* This will be deleted if it already exists, unless it's a directory which will fail.
* \return zero on success (matching 'rename' behavior).
*/
int BLI_rename_overwrite(const char *from, const char *to) ATTR_NONNULL();
/**
* Deletes the specified file or directory (depending on dir), optionally
* doing recursive delete of directory contents.

View File

@ -242,6 +242,15 @@ MINLINE uint64_t ceil_to_multiple_ul(uint64_t a, uint64_t b);
*/
MINLINE int mod_i(int i, int n);
/**
* Modulo that returns a positive result, regardless of the sign of \a f.
*
* For example, mod_f_positive(-0.1, 1.0) => 0.9.
*
* \returns a float in the interval [0, n).
*/
MINLINE float mod_f_positive(float f, float n);
/**
* Round to closest even number, halfway cases are rounded away from zero.
*/

View File

@ -41,6 +41,9 @@ bool BLI_path_name_at_index(const char *__restrict path,
*/
bool BLI_path_is_unc(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
bool BLI_path_is_win32_drive(const char *path);
bool BLI_path_is_win32_drive_with_slash(const char *path);
/** \} */
/* -------------------------------------------------------------------- */
@ -153,22 +156,27 @@ void BLI_path_to_display_name(char *display_name, int display_name_maxncpy, cons
* such as `//../parent` or `../parent`.
*
* \param path: The path to a file or directory which can be absolute or relative.
* \return the length of `path`.
*/
void BLI_path_normalize(char *path) ATTR_NONNULL(1);
int BLI_path_normalize(char *path) ATTR_NONNULL(1);
/**
* A version of #BLI_path_normalize without special handling of `//` blend file relative prefix.
*
* \note On UNIX `//path` is a valid path which gets normalized to `/path`.
*
* \return the length of `path`.
*/
void BLI_path_normalize_native(char *path) ATTR_NONNULL(1);
int BLI_path_normalize_native(char *path) ATTR_NONNULL(1);
/**
* Cleanup file-path ensuring a trailing slash.
*
* \note Same as #BLI_path_normalize but adds a trailing slash.
*
* \return the length of `dir`.
*/
void BLI_path_normalize_dir(char *dir, size_t dir_maxncpy) ATTR_NONNULL(1);
int BLI_path_normalize_dir(char *dir, size_t dir_maxncpy) ATTR_NONNULL(1);
#if defined(WIN32)
void BLI_path_normalize_unc_16(wchar_t *path_16);
@ -177,6 +185,28 @@ void BLI_path_normalize_unc(char *path, int path_maxncpy);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Path Canonicalize
* \{ */
/**
* Convert `path` to a canonical representation.
* This is intended for system paths (passed in as command-line arguments of via scripts)
* which are valid in that they resolve to a file/directory and but could be `CWD` relative or
* contain redundant slashes that cause absolute/relative conversion to fail.
* (specifically the "//" prefix used by Blender).
*
* Perform the following operations:
*
* - Make absolute (relative to the current working directory).
* - Convert slash direction (WIN32 only, as other systems may use back-slashes in filenames).
* - Normalize redundant slashes.
* - Strip trailing slashes.
*/
int BLI_path_canonicalize_native(char *path, int path_maxncpy);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Path FileName Manipulation
* \{ */
@ -219,7 +249,14 @@ const char *BLI_path_slash_find(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUS
const char *BLI_path_slash_rfind(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Appends a slash to path if there isn't one there already.
* Returns the new length of the path.
* \param path_len: The length of `path`.
* \return the new length of the path.
*/
int BLI_path_slash_ensure_ex(char *path, size_t path_maxncpy, const size_t path_len)
ATTR_NONNULL(1);
/**
* Appends a slash to path if there isn't one there already.
* \return the new length of the path.
*/
int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1);
/**

View File

@ -624,7 +624,11 @@ int BLI_string_find_split_words(const char *str,
*/
void BLI_string_debug_size_after_nil(char *str, size_t str_maxncpy);
#else
# define BLI_string_debug_size(str, str_maxncpy) (void)(0 ? ((str) + (str_maxncpy)) : 0)
# define BLI_string_debug_size(str, str_maxncpy) \
if (0) { \
(void)str, (void)str_maxncpy; \
} \
((void)0)
# define BLI_string_debug_size_after_nil(str, str_maxncpy) BLI_string_debug_size(str, str_maxncpy)
#endif /* !WITH_STRSIZE_DEBUG */

View File

@ -379,6 +379,43 @@ bool BLI_file_ensure_parent_dir_exists(const char *filepath)
return BLI_dir_create_recursive(di);
}
int BLI_rename(const char *from, const char *to)
{
#ifdef WIN32
return urename(from, to);
#else
return rename(from, to);
#endif
}
int BLI_rename_overwrite(const char *from, const char *to)
{
if (!BLI_exists(from)) {
return 1;
}
/* NOTE(@ideasman42): there are no checks that `from` & `to` *aren't* the same file.
* It's up to the caller to ensure this. In practice these paths are often generated
* and known to be different rather than arbitrary user input.
* In the case of arbitrary paths (renaming a file in the file-selector for example),
* the caller must ensure file renaming doesn't cause user data loss.
*
* Support for checking the files aren't the same could be added, however path comparison
* alone is *not* a guarantee the files are different (given the possibility of accessing
* the same file through different paths via symbolic-links), we could instead support a
* verizon of Python's * `os.path.samefile(..)` which compares the I-node & device.
* In this particular case we would not want to follow symbolic-links as well.
* Since this functionality isn't required at the moment, leave this as-is.
* Noting it as a potential improvement. */
if (BLI_exists(to)) {
if (BLI_delete(to, false, false)) {
return 1;
}
}
return BLI_rename(from, to);
}
#ifdef WIN32
static void callLocalErrorCallBack(const char *err)
@ -691,23 +728,6 @@ int BLI_create_symlink(const char *file, const char *to)
}
# endif
/** \return true on success (i.e. given path now exists on FS), false otherwise. */
int BLI_rename(const char *from, const char *to)
{
if (!BLI_exists(from)) {
return 0;
}
/* Make sure `from` & `to` are different (case insensitive) before removing. */
if (BLI_exists(to) && BLI_strcasecmp(from, to)) {
if (BLI_delete(to, false, false)) {
return 1;
}
}
return urename(from, to);
}
#else /* The UNIX world */
/* results from recursive_operation and its callbacks */
@ -1323,19 +1343,4 @@ int BLI_create_symlink(const char *file, const char *to)
}
# endif
int BLI_rename(const char *from, const char *to)
{
if (!BLI_exists(from)) {
return 1;
}
if (BLI_exists(to)) {
if (BLI_delete(to, false, false)) {
return 1;
}
}
return rename(from, to);
}
#endif

View File

@ -387,6 +387,16 @@ MINLINE int mod_i(int i, int n)
return (i % n + n) % n;
}
MINLINE float mod_f_positive(const float f, const float n)
{
const float modulo = fmodf(f, n);
if (modulo < 0) {
/* fmodf returns a value in the interval (-n, n). */
return modulo + n;
}
return modulo;
}
MINLINE float fractf(float a)
{
return a - floorf(a);

View File

@ -43,6 +43,7 @@ static int BLI_path_unc_prefix_len(const char *path);
#ifdef WIN32
static bool BLI_path_is_abs_win32(const char *path);
static int BLI_path_win32_prefix_len(const char *path);
#endif /* WIN32 */
/**
@ -135,7 +136,11 @@ void BLI_path_sequence_encode(char *path,
BLI_snprintf(path, path_maxncpy, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
}
static void path_normalize_impl(char *path, bool check_blend_relative_prefix)
/**
* Implementation for #BLI_path_normalize & #BLI_path_normalize_native.
* \return The path length.
*/
static int path_normalize_impl(char *path, bool check_blend_relative_prefix)
{
const char *path_orig = path;
int path_len = strlen(path);
@ -173,7 +178,7 @@ static void path_normalize_impl(char *path, bool check_blend_relative_prefix)
path += path_unc_len;
path_len -= path_unc_len;
}
else if (isalpha(path[0]) && (path[1] == ':')) {
else if (BLI_path_is_win32_drive(path)) { /* Check for `C:` (2 characters only). */
path += 2;
path_len -= 2;
}
@ -355,27 +360,52 @@ static void path_normalize_impl(char *path, bool check_blend_relative_prefix)
BLI_assert(strlen(path) == path_len);
#undef IS_PARENT_DIR
return (path - path_orig) + path_len;
}
void BLI_path_normalize(char *path)
int BLI_path_normalize(char *path)
{
path_normalize_impl(path, true);
return path_normalize_impl(path, true);
}
void BLI_path_normalize_native(char *path)
int BLI_path_normalize_native(char *path)
{
path_normalize_impl(path, false);
return path_normalize_impl(path, false);
}
void BLI_path_normalize_dir(char *dir, size_t dir_maxncpy)
int BLI_path_normalize_dir(char *dir, size_t dir_maxncpy)
{
/* Would just create an unexpected "/" path, just early exit entirely. */
if (dir[0] == '\0') {
return;
return 0;
}
BLI_path_normalize(dir);
BLI_path_slash_ensure(dir, dir_maxncpy);
int dir_len = BLI_path_normalize(dir);
return BLI_path_slash_ensure_ex(dir, dir_maxncpy, dir_len);
}
int BLI_path_canonicalize_native(char *path, int path_maxncpy)
{
BLI_path_abs_from_cwd(path, path_maxncpy);
/* As these are system level paths, only convert slashes
* if the alternate direction is accepted as a slash. */
if (BLI_path_slash_is_native_compat(ALTSEP)) {
BLI_path_slash_native(path);
}
int path_len = BLI_path_normalize_native(path);
/* Strip trailing slash but don't strip `/` away to nothing. */
if (path_len > 1 && path[path_len - 1] == SEP) {
#ifdef WIN32
/* Don't strip `C:\` -> `C:` as this is no longer a valid directory. */
if (BLI_path_win32_prefix_len(path) + 1 < path_len)
#endif
{
path_len -= 1;
path[path_len] = '\0';
}
}
return path_len;
}
bool BLI_path_make_safe_filename_ex(char *fname, bool allow_tokens)
@ -523,6 +553,26 @@ static int BLI_path_unc_prefix_len(const char *path)
return 0;
}
#ifdef WIN32
static int BLI_path_win32_prefix_len(const char *path)
{
if (BLI_path_is_win32_drive(path)) {
return 2;
}
return BLI_path_unc_prefix_len(path);
}
#endif
bool BLI_path_is_win32_drive(const char *path)
{
return isalpha(path[0]) && (path[1] == ':');
}
bool BLI_path_is_win32_drive_with_slash(const char *path)
{
return isalpha(path[0]) && (path[1] == ':') && ELEM(path[2], '\\', '/');
}
#if defined(WIN32)
/**
@ -535,7 +585,7 @@ static int BLI_path_unc_prefix_len(const char *path)
*/
static bool BLI_path_is_abs_win32(const char *path)
{
return (path[1] == ':' && ELEM(path[2], '\\', '/')) || BLI_path_is_unc(path);
return BLI_path_is_win32_drive_with_slash(path) || BLI_path_is_unc(path);
}
static wchar_t *next_slash(wchar_t *path)
@ -1082,7 +1132,7 @@ bool BLI_path_abs(char path[FILE_MAX], const char *basepath)
* Add a `/` prefix and lowercase the drive-letter, remove the `:`.
* `C:\foo.JPG` -> `/c/foo.JPG` */
if (isalpha(tmp[0]) && (tmp[1] == ':') && ELEM(tmp[2], '\\', '/')) {
if (BLI_path_is_win32_drive_with_slash(tmp)) {
tmp[1] = tolower(tmp[0]); /* Replace `:` with drive-letter. */
tmp[0] = '/';
/* `\` the slash will be converted later. */
@ -1602,35 +1652,20 @@ const char *BLI_path_extension(const char *filepath)
size_t BLI_path_append(char *__restrict dst, const size_t dst_maxncpy, const char *__restrict file)
{
BLI_string_debug_size_after_nil(dst, dst_maxncpy);
size_t dirlen = BLI_strnlen(dst, dst_maxncpy);
/* Inline #BLI_path_slash_ensure. */
if ((dirlen > 0) && !BLI_path_slash_is_native_compat(dst[dirlen - 1])) {
dst[dirlen++] = SEP;
dst[dirlen] = '\0';
/* Slash ensure uses #BLI_string_debug_size */
int dst_len = BLI_path_slash_ensure(dst, dst_maxncpy);
if (dst_len + 1 < dst_maxncpy) {
dst_len += BLI_strncpy_rlen(dst + dst_len, file, dst_maxncpy - dst_len);
}
if (dirlen >= dst_maxncpy) {
return dirlen; /* Fills the path. */
}
return dirlen + BLI_strncpy_rlen(dst + dirlen, file, dst_maxncpy - dirlen);
return dst_len;
}
size_t BLI_path_append_dir(char *__restrict dst,
const size_t dst_maxncpy,
const char *__restrict dir)
{
size_t dirlen = BLI_path_append(dst, dst_maxncpy, dir);
if (dirlen + 1 < dst_maxncpy) {
/* Inline #BLI_path_slash_ensure. */
if ((dirlen > 0) && !BLI_path_slash_is_native_compat(dst[dirlen - 1])) {
dst[dirlen++] = SEP;
dst[dirlen] = '\0';
}
}
return dirlen;
size_t dst_len = BLI_path_append(dst, dst_maxncpy, dir);
return BLI_path_slash_ensure_ex(dst, dst_maxncpy, dst_len);
}
size_t BLI_path_join_array(char *__restrict dst,
@ -1885,21 +1920,24 @@ const char *BLI_path_slash_rfind(const char *path)
return (lfslash > lbslash) ? lfslash : lbslash;
}
int BLI_path_slash_ensure(char *path, size_t path_maxncpy)
int BLI_path_slash_ensure_ex(char *path, size_t path_maxncpy, size_t path_len)
{
BLI_string_debug_size_after_nil(path, path_maxncpy);
int len = strlen(path);
BLI_assert(len < path_maxncpy);
if (len == 0 || !BLI_path_slash_is_native_compat(path[len - 1])) {
BLI_assert(strlen(path) == path_len);
BLI_assert(path_len < path_maxncpy);
if (path_len == 0 || !BLI_path_slash_is_native_compat(path[path_len - 1])) {
/* Avoid unlikely buffer overflow. */
if (len + 1 < path_maxncpy) {
path[len] = SEP;
path[len + 1] = '\0';
return len + 1;
if (path_len + 1 < path_maxncpy) {
path[path_len++] = SEP;
path[path_len] = '\0';
}
}
return len;
return path_len;
}
int BLI_path_slash_ensure(char *path, size_t path_maxncpy)
{
return BLI_path_slash_ensure_ex(path, path_maxncpy, strlen(path));
}
void BLI_path_slash_rstrip(char *path)
@ -1947,6 +1985,10 @@ int BLI_path_cmp_normalized(const char *p1, const char *p2)
BLI_path_slash_native(norm_p1);
BLI_path_slash_native(norm_p2);
/* One of the paths ending with a slash does not make them different, strip both. */
BLI_path_slash_rstrip(norm_p1);
BLI_path_slash_rstrip(norm_p2);
BLI_path_normalize(norm_p1);
BLI_path_normalize(norm_p2);

View File

@ -602,30 +602,12 @@ void BLI_file_free_lines(LinkNode *lines)
bool BLI_file_older(const char *file1, const char *file2)
{
#ifdef WIN32
struct _stat st1, st2;
UTF16_ENCODE(file1);
UTF16_ENCODE(file2);
if (_wstat(file1_16, &st1)) {
BLI_stat_t st1, st2;
if (BLI_stat(file1, &st1)) {
return false;
}
if (_wstat(file2_16, &st2)) {
if (BLI_stat(file2, &st2)) {
return false;
}
UTF16_UN_ENCODE(file2);
UTF16_UN_ENCODE(file1);
#else
struct stat st1, st2;
if (stat(file1, &st1)) {
return false;
}
if (stat(file2, &st2)) {
return false;
}
#endif
return (st1.st_mtime < st2.st_mtime);
}

View File

@ -156,4 +156,11 @@ TEST(math_base, InterpolateInt)
EXPECT_EQ(math::interpolate(100, 200, 0.4f), 140);
}
TEST(math_base, ModFPositive)
{
EXPECT_FLOAT_EQ(mod_f_positive(3.27f, 1.57f), 0.12999988f);
EXPECT_FLOAT_EQ(mod_f_positive(327.f, 47.f), 45.f);
EXPECT_FLOAT_EQ(mod_f_positive(-0.1f, 1.0f), 0.9f);
}
} // namespace blender::tests

View File

@ -48,11 +48,12 @@ static char *str_replace_char_strdup(const char *str, char src, char dst)
if (SEP == '\\') { \
str_replace_char_with_relative_exception(path, '/', '\\'); \
} \
BLI_path_normalize(path); \
const int path_len_test = BLI_path_normalize(path); \
if (SEP == '\\') { \
BLI_str_replace_char(path, '\\', '/'); \
} \
EXPECT_STREQ(path, output_expect); \
EXPECT_EQ(path_len_test, strlen(path)); \
} \
((void)0)
@ -155,6 +156,26 @@ TEST(path_util, Normalize_UnbalancedRelativeTrailing)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Tests for: #BLI_path_cmp_normalized
*
* \note #BLI_path_normalize tests handle most of the corner cases.
* \{ */
TEST(path_util, CompareNormalized)
{
/* Trailing slash should not matter. */
EXPECT_EQ(BLI_path_cmp_normalized("/tmp/", "/tmp"), 0);
/* Slash direction should not matter. */
EXPECT_EQ(BLI_path_cmp_normalized("c:\\tmp\\", "c:/tmp/"), 0);
/* Empty paths should be supported. */
EXPECT_EQ(BLI_path_cmp_normalized("", ""), 0);
EXPECT_NE(BLI_path_cmp_normalized("A", "B"), 0);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Tests for: #BLI_path_parent_dir
* \{ */
@ -560,6 +581,47 @@ TEST(path_util, JoinRelativePrefix)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Tests for: #BLI_path_append
* \{ */
/* For systems with `/` path separator (non WIN32). */
#define APPEND(str_expect, size, path, filename) \
{ \
const char *expect = str_expect; \
char result[(size) + 1024] = path; \
char filename_native[] = filename; \
/* Check we don't write past the last byte. */ \
if (SEP == '\\') { \
BLI_str_replace_char(filename_native, '/', '\\'); \
BLI_str_replace_char(result, '/', '\\'); \
} \
BLI_path_append(result, size, filename_native); \
if (SEP == '\\') { \
BLI_str_replace_char(result, '\\', '/'); \
} \
EXPECT_STREQ(result, expect); \
} \
((void)0)
TEST(path_util, AppendFile)
{
APPEND("a/b", 100, "a", "b");
APPEND("a/b", 100, "a/", "b");
}
TEST(path_util, AppendFile_Truncate)
{
APPEND("/A", 3, "/", "ABC");
APPEND("/", 2, "/", "test");
APPEND("X", 2, "X", "ABC");
APPEND("X/", 3, "X/", "ABC");
}
#undef APPEND
/** \} */
/* -------------------------------------------------------------------- */
/** \name Tests for: #BLI_path_frame
* \{ */

View File

@ -4391,6 +4391,14 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 306, 10)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
/* Set default values for new members. */
scene->toolsettings->snap_mode_tools = SCE_SNAP_MODE_GEOM;
scene->toolsettings->plane_axis = 2;
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 306, 11)) {
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {

View File

@ -103,7 +103,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_action.simulated_frames);
}
if (!USER_VERSION_ATLEAST(306, 10)) {
if (!USER_VERSION_ATLEAST(306, 11)) {
FROM_DEFAULT_V4_UCHAR(space_view3d.asset_shelf.back);
FROM_DEFAULT_V4_UCHAR(space_view3d.asset_shelf.header_back);
}

View File

@ -1165,17 +1165,17 @@ static void id_buffer_init_from_id(BLO_Write_IDBuffer *id_buffer, ID *id, const
* linked data is tagged accordingly. */
static int write_id_direct_linked_data_process_cb(LibraryIDLinkCallbackData *cb_data)
{
ID *id_self = cb_data->id_self;
ID *self_id = cb_data->self_id;
ID *id = *cb_data->id_pointer;
const int cb_flag = cb_data->cb_flag;
if (id == nullptr || !ID_IS_LINKED(id)) {
return IDWALK_RET_NOP;
}
BLI_assert(!ID_IS_LINKED(id_self));
BLI_assert(!ID_IS_LINKED(self_id));
BLI_assert((cb_flag & IDWALK_CB_INDIRECT_USAGE) == 0);
if (id_self->tag & LIB_TAG_RUNTIME) {
if (self_id->tag & LIB_TAG_RUNTIME) {
return IDWALK_RET_NOP;
}
@ -1383,7 +1383,7 @@ static bool do_history(const char *name, ReportList *reports)
if (BLI_exists(tempname1)) {
SNPRINTF(tempname2, "%s%d", name, hisnr);
if (BLI_rename(tempname1, tempname2)) {
if (BLI_rename_overwrite(tempname1, tempname2)) {
BKE_report(reports, RPT_ERROR, "Unable to make version backup");
return true;
}
@ -1395,7 +1395,7 @@ static bool do_history(const char *name, ReportList *reports)
if (BLI_exists(name)) {
SNPRINTF(tempname1, "%s%d", name, hisnr);
if (BLI_rename(name, tempname1)) {
if (BLI_rename_overwrite(name, tempname1)) {
BKE_report(reports, RPT_ERROR, "Unable to make version backup");
return true;
}
@ -1562,7 +1562,7 @@ bool BLO_write_file(Main *mainvar,
}
}
if (BLI_rename(tempname, filepath) != 0) {
if (BLI_rename_overwrite(tempname, filepath) != 0) {
BKE_report(reports, RPT_ERROR, "Cannot change old file (file saved with @)");
return false;
}

View File

@ -462,7 +462,7 @@ static int foreach_id_cow_detect_need_for_update_callback(LibraryIDLinkCallbackD
}
DepsgraphNodeBuilder *builder = static_cast<DepsgraphNodeBuilder *>(cb_data->user_data);
ID *id_cow_self = cb_data->id_self;
ID *id_cow_self = cb_data->self_id;
return builder->foreach_id_cow_detect_need_for_update_callback(id_cow_self, id);
}

View File

@ -180,6 +180,7 @@ set(SRC
engines/workbench/workbench_state.cc
engines/workbench/workbench_transparent.c
engines/workbench/workbench_volume.c
engines/workbench/workbench_volume_next.cc
engines/external/external_engine.c
engines/gpencil/gpencil_antialiasing.c
engines/gpencil/gpencil_cache_utils.c
@ -272,6 +273,7 @@ set(SRC
engines/eevee_next/eevee_depth_of_field.hh
engines/eevee_next/eevee_engine.h
engines/eevee_next/eevee_film.hh
engines/eevee_next/eevee_gbuffer.hh
engines/eevee_next/eevee_hizbuffer.hh
engines/eevee_next/eevee_instance.hh
engines/eevee_next/eevee_irradiance_cache.hh

View File

@ -57,6 +57,25 @@ bNodeTree *DefaultWorldNodeTree::nodetree_get(::World *wo)
*
* \{ */
World::~World()
{
if (default_world_ != nullptr) {
BKE_id_free(nullptr, default_world_);
}
}
::World *World::default_world_get()
{
if (default_world_ == nullptr) {
default_world_ = static_cast<::World *>(BKE_id_new_nomain(ID_WO, "EEVEEE default world"));
copy_v3_fl(&default_world_->horr, 0.0f);
default_world_->use_nodes = 0;
default_world_->nodetree = nullptr;
BLI_listbase_clear(&default_world_->gpumaterial);
}
return default_world_;
}
void World::sync()
{
// if (inst_.lookdev.sync_world()) {
@ -65,8 +84,7 @@ void World::sync()
::World *bl_world = inst_.scene->world;
if (bl_world == nullptr) {
// bl_world = BKE_world_default();
return;
bl_world = default_world_get();
}
WorldHandle &wo_handle = inst_.sync.sync_world(bl_world);

View File

@ -53,8 +53,13 @@ class World {
/* Used to detect if world change. */
::World *prev_original_world = nullptr;
/* Used when the scene doesn't have a world. */
::World *default_world_ = nullptr;
::World *default_world_get();
public:
World(Instance &inst) : inst_(inst){};
~World();
void sync();
};

View File

@ -6,7 +6,7 @@
/** \name Volume shader base
* \{ */
GPU_SHADER_CREATE_INFO(workbench_volume)
GPU_SHADER_CREATE_INFO(workbench_volume_common)
.vertex_in(0, Type::VEC3, "pos")
.fragment_out(0, Type::VEC4, "fragColor")
.sampler(0, ImageType::DEPTH_2D, "depthBuffer")
@ -16,27 +16,44 @@ GPU_SHADER_CREATE_INFO(workbench_volume)
.push_constant(Type::FLOAT, "stepLength")
.push_constant(Type::FLOAT, "densityScale")
.vertex_source("workbench_volume_vert.glsl")
.fragment_source("workbench_volume_frag.glsl")
.additional_info("draw_object_infos");
.fragment_source("workbench_volume_frag.glsl");
GPU_SHADER_CREATE_INFO(workbench_volume)
.additional_info("workbench_volume_common", "draw_object_infos");
GPU_SHADER_CREATE_INFO(workbench_next_volume)
.define("WORKBENCH_NEXT")
.additional_info("workbench_volume_common", "draw_object_infos_new", "draw_view");
/** \} */
/* -------------------------------------------------------------------- */
/** \name Smoke variation
* \{ */
GPU_SHADER_CREATE_INFO(workbench_volume_smoke)
GPU_SHADER_CREATE_INFO(workbench_volume_smoke_common)
.define("VOLUME_SMOKE")
.sampler(2, ImageType::FLOAT_3D, "flameTexture")
.sampler(3, ImageType::FLOAT_1D, "flameColorTexture")
.additional_info("draw_mesh", "draw_resource_id_varying");
.additional_info("draw_resource_id_varying");
GPU_SHADER_CREATE_INFO(workbench_volume_object)
GPU_SHADER_CREATE_INFO(workbench_volume_object_common)
.define("VOLUME_OBJECT")
.push_constant(Type::MAT4, "volumeTextureToObject")
/* FIXME(fclem): This overflow the push_constant limit. */
.push_constant(Type::MAT4, "volumeObjectToTexture")
.additional_info("draw_volume", "draw_resource_id_varying");
.additional_info("draw_resource_id_varying");
GPU_SHADER_CREATE_INFO(workbench_volume_smoke)
.additional_info("workbench_volume_smoke_common", "draw_mesh");
GPU_SHADER_CREATE_INFO(workbench_volume_object)
.additional_info("workbench_volume_object_common", "draw_volume");
GPU_SHADER_CREATE_INFO(workbench_next_volume_smoke)
.additional_info("workbench_volume_smoke_common", "draw_modelmat_new");
GPU_SHADER_CREATE_INFO(workbench_next_volume_object)
.additional_info("workbench_volume_object_common", "draw_volume_new");
/** \} */
@ -111,4 +128,10 @@ GPU_SHADER_CREATE_INFO(workbench_volume_slice)
WORKBENCH_VOLUME_SMOKE_VARIATIONS(workbench_volume, "workbench_volume")
#define WORKBENCH_NEXT_VOLUME_SMOKE_VARIATIONS(prefix, ...) \
WORKBENCH_VOLUME_INTERP_VARIATIONS(prefix##_smoke, "workbench_next_volume_smoke", __VA_ARGS__) \
WORKBENCH_VOLUME_INTERP_VARIATIONS(prefix##_object, "workbench_next_volume_object", __VA_ARGS__)
WORKBENCH_NEXT_VOLUME_SMOKE_VARIATIONS(workbench_next_volume, "workbench_next_volume")
/** \} */

View File

@ -209,6 +209,12 @@ vec4 volume_integration(vec3 ray_ori, vec3 ray_dir, float ray_inc, float ray_max
/* accumulate and also take into account the transmittance from previous steps */
final_scattering += final_transmittance * Lscat;
final_transmittance *= Tr;
if (final_transmittance <= 0.01) {
/* Early out */
final_transmittance = 0.0;
break;
}
}
return vec4(final_scattering, final_transmittance);

View File

@ -34,6 +34,7 @@ class Instance {
TransparentDepthPass transparent_depth_ps;
ShadowPass shadow_ps;
VolumePass volume_ps;
OutlinePass outline_ps;
DofPass dof_ps;
AntiAliasingPass anti_aliasing_ps;
@ -75,6 +76,7 @@ class Instance {
transparent_depth_ps.sync(scene_state, resources);
shadow_ps.sync();
volume_ps.sync(resources);
outline_ps.sync(resources);
dof_ps.sync(resources);
anti_aliasing_ps.sync(resources, scene_state.resolution);
@ -85,6 +87,26 @@ class Instance {
resources.material_buf.push_update();
}
Material get_material(ObjectRef ob_ref, eV3DShadingColorType color_type, int slot = 0)
{
switch (color_type) {
case V3D_SHADING_OBJECT_COLOR:
return Material(*ob_ref.object);
case V3D_SHADING_RANDOM_COLOR:
return Material(*ob_ref.object, true);
case V3D_SHADING_SINGLE_COLOR:
return scene_state.material_override;
case V3D_SHADING_VERTEX_COLOR:
return scene_state.material_attribute_color;
case V3D_SHADING_MATERIAL_COLOR:
if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, slot + 1)) {
return Material(*_mat);
}
default:
return Material(*BKE_material_default_empty());
}
}
void object_sync(Manager &manager, ObjectRef &ob_ref)
{
if (scene_state.render_finished) {
@ -138,9 +160,8 @@ class Instance {
if (md && BKE_modifier_is_enabled(scene_state.scene, md, eModifierMode_Realtime)) {
FluidModifierData *fmd = (FluidModifierData *)md;
if (fmd->domain) {
#if 0 /* TODO(@pragma37): */
workbench_volume_cache_populate(vedata, wpd->scene, ob, md, V3D_SHADING_SINGLE_COLOR);
#endif
volume_ps.object_sync_modifier(manager, resources, scene_state, ob_ref, md);
if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
return; /* Do not draw solid in this case. */
}
@ -163,14 +184,16 @@ class Instance {
#if 0 /* TODO(@pragma37): */
DRWShadingGroup *grp = workbench_material_hair_setup(
wpd, ob, CURVES_MATERIAL_NR, object_state.color_type);
DRW_shgroup_curves_create_sub(ob, grp, NULL);
DRW_shgroup_curves_create_sub(ob, grp, nullptr);
#endif
}
else if (ob->type == OB_VOLUME) {
if (scene_state.shading.type != OB_WIRE) {
#if 0 /* TODO(@pragma37): */
workbench_volume_cache_populate(vedata, wpd->scene, ob, NULL, object_state.color_type);
#endif
volume_ps.object_sync_volume(manager,
resources,
scene_state,
ob_ref,
get_material(ob_ref, object_state.color_type).base_color);
}
}
}
@ -204,15 +227,7 @@ class Instance {
continue;
}
Material mat;
if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, i + 1)) {
mat = Material(*_mat);
}
else {
mat = Material(*BKE_material_default_empty());
}
Material mat = get_material(ob_ref, object_state.color_type, i);
has_transparent_material = has_transparent_material || mat.is_transparent();
::Image *image = nullptr;
@ -244,24 +259,7 @@ class Instance {
}
if (batch) {
Material mat;
if (object_state.color_type == V3D_SHADING_OBJECT_COLOR) {
mat = Material(*ob_ref.object);
}
else if (object_state.color_type == V3D_SHADING_RANDOM_COLOR) {
mat = Material(*ob_ref.object, true);
}
else if (object_state.color_type == V3D_SHADING_SINGLE_COLOR) {
mat = scene_state.material_override;
}
else if (object_state.color_type == V3D_SHADING_VERTEX_COLOR) {
mat = scene_state.material_attribute_color;
}
else {
mat = Material(*BKE_material_default_empty());
}
Material mat = get_material(ob_ref, object_state.color_type);
has_transparent_material = has_transparent_material || mat.is_transparent();
draw_mesh(ob_ref,
@ -370,8 +368,7 @@ class Instance {
transparent_ps.draw(manager, view, resources, resolution);
transparent_depth_ps.draw(manager, view, resources);
// volume_ps.draw_prepass(manager, view, resources.depth_tx);
volume_ps.draw(manager, view, resources);
outline_ps.draw(manager, resources);
dof_ps.draw(manager, view, resources, resolution);
anti_aliasing_ps.draw(manager, view, resources, resolution, depth_tx, color_tx);

View File

@ -324,6 +324,52 @@ class ShadowPass {
bool force_fail_method);
};
class VolumePass {
bool active_ = true;
PassMain ps_ = {"Volume"};
Framebuffer fb_ = {"Volume"};
Texture dummy_shadow_tx_ = {"Volume.Dummy Shadow Tx"};
Texture dummy_volume_tx_ = {"Volume.Dummy Volume Tx"};
Texture dummy_coba_tx_ = {"Volume.Dummy Coba Tx"};
GPUShader *shaders_[2 /*slice*/][2 /*coba*/][3 /*interpolation*/][2 /*smoke*/];
public:
void sync(SceneResources &resources);
void object_sync_volume(Manager &manager,
SceneResources &resources,
const SceneState &scene_state,
ObjectRef &ob_ref,
float3 color);
void object_sync_modifier(Manager &manager,
SceneResources &resources,
const SceneState &scene_state,
ObjectRef &ob_ref,
ModifierData *md);
void draw(Manager &manager, View &view, SceneResources &resources);
private:
GPUShader *get_shader(bool slice, bool coba, int interpolation, bool smoke);
void draw_slice_ps(Manager &manager,
PassMain::Sub &ps,
ObjectRef &ob_ref,
int slice_axis_enum,
float slice_depth);
void draw_volume_ps(Manager &manager,
PassMain::Sub &ps,
ObjectRef &ob_ref,
int taa_sample,
float3 slice_count,
float3 world_size);
};
class OutlinePass {
private:
bool enabled_ = false;

View File

@ -0,0 +1,256 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "workbench_private.hh"
#include "BKE_volume.h"
#include "BKE_volume_render.h"
#include "BLI_rand.h"
#include "DNA_fluid_types.h"
#include "DNA_modifier_types.h"
namespace blender::workbench {
void VolumePass::sync(SceneResources &resources)
{
active_ = false;
ps_.init();
ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf);
dummy_shadow_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(1));
dummy_volume_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(0));
dummy_coba_tx_.ensure_1d(GPU_RGBA8, 1, GPU_TEXTURE_USAGE_SHADER_READ, float4(0));
}
void VolumePass::object_sync_volume(Manager &manager,
SceneResources &resources,
const SceneState &scene_state,
ObjectRef &ob_ref,
float3 color)
{
Object *ob = ob_ref.object;
/* Create 3D textures. */
Volume *volume = static_cast<Volume *>(ob->data);
BKE_volume_load(volume, G.main);
const VolumeGrid *volume_grid = BKE_volume_grid_active_get_for_read(volume);
if (volume_grid == nullptr) {
return;
}
DRWVolumeGrid *grid = DRW_volume_batch_cache_get_grid(volume, volume_grid);
if (grid == nullptr) {
return;
}
active_ = true;
PassMain::Sub &sub_ps = ps_.sub(ob->id.name);
const bool use_slice = (volume->display.axis_slice_method == AXIS_SLICE_SINGLE);
sub_ps.shader_set(get_shader(use_slice, false, volume->display.interpolation_method, false));
const float density_scale = volume->display.density *
BKE_volume_density_scale(volume, ob->object_to_world);
sub_ps.bind_texture("depthBuffer", &resources.depth_tx);
sub_ps.bind_texture("densityTexture", grid->texture);
/* TODO: implement shadow texture, see manta_smoke_calc_transparency. */
sub_ps.bind_texture("shadowTexture", dummy_shadow_tx_);
sub_ps.push_constant("activeColor", color);
sub_ps.push_constant("densityScale", density_scale);
sub_ps.push_constant("volumeObjectToTexture", float4x4(grid->object_to_texture));
sub_ps.push_constant("volumeTextureToObject", float4x4(grid->texture_to_object));
if (use_slice) {
draw_slice_ps(
manager, sub_ps, ob_ref, volume->display.slice_axis, volume->display.slice_depth);
}
else {
float3 world_size;
float4x4 texture_to_world = float4x4(ob->object_to_world) * float4x4(grid->texture_to_object);
math::normalize_and_get_size(float3x3(texture_to_world), world_size);
int3 resolution;
GPU_texture_get_mipmap_size(grid->texture, 0, resolution);
float3 slice_count = float3(resolution) * 5.0f;
draw_volume_ps(manager, sub_ps, ob_ref, scene_state.sample, slice_count, world_size);
}
}
void VolumePass::object_sync_modifier(Manager &manager,
SceneResources &resources,
const SceneState &scene_state,
ObjectRef &ob_ref,
ModifierData *md)
{
Object *ob = ob_ref.object;
FluidModifierData *modifier = reinterpret_cast<FluidModifierData *>(md);
FluidDomainSettings &settings = *modifier->domain;
if (!settings.fluid) {
return;
}
bool can_load = false;
if (settings.use_coba) {
DRW_smoke_ensure_coba_field(modifier);
can_load = settings.tex_field != nullptr;
}
else if (settings.type == FLUID_DOMAIN_TYPE_GAS) {
DRW_smoke_ensure(modifier, settings.flags & FLUID_DOMAIN_USE_NOISE);
can_load = settings.tex_density != nullptr || settings.tex_color != nullptr;
}
if (!can_load) {
return;
}
active_ = true;
PassMain::Sub &sub_ps = ps_.sub(ob->id.name);
const bool use_slice = settings.axis_slice_method == AXIS_SLICE_SINGLE;
sub_ps.shader_set(get_shader(use_slice, settings.use_coba, settings.interp_method, true));
if (settings.use_coba) {
const bool show_flags = settings.coba_field == FLUID_DOMAIN_FIELD_FLAGS;
const bool show_pressure = settings.coba_field == FLUID_DOMAIN_FIELD_PRESSURE;
const bool show_phi = ELEM(settings.coba_field,
FLUID_DOMAIN_FIELD_PHI,
FLUID_DOMAIN_FIELD_PHI_IN,
FLUID_DOMAIN_FIELD_PHI_OUT,
FLUID_DOMAIN_FIELD_PHI_OBSTACLE);
sub_ps.push_constant("showFlags", show_flags);
sub_ps.push_constant("showPressure", show_pressure);
sub_ps.push_constant("showPhi", show_phi);
sub_ps.push_constant("gridScale", settings.grid_scale);
if (show_flags) {
sub_ps.bind_texture("flagTexture", settings.tex_field);
}
else {
sub_ps.bind_texture("densityTexture", settings.tex_field);
}
if (!show_flags && !show_pressure && !show_phi) {
sub_ps.bind_texture("transferTexture", settings.tex_coba);
}
}
else {
bool use_constant_color = ((settings.active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
(settings.active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0);
sub_ps.push_constant("activeColor",
use_constant_color ? float3(settings.active_color) : float3(1));
sub_ps.bind_texture("densityTexture",
settings.tex_color ? settings.tex_color : settings.tex_density);
sub_ps.bind_texture("flameTexture",
settings.tex_flame ? settings.tex_flame : dummy_volume_tx_);
sub_ps.bind_texture("flameColorTexture",
settings.tex_flame ? settings.tex_flame_coba : dummy_coba_tx_);
sub_ps.bind_texture("shadowTexture", settings.tex_shadow);
}
sub_ps.push_constant("densityScale", 10.0f * settings.display_thickness);
sub_ps.bind_texture("depthBuffer", &resources.depth_tx);
if (use_slice) {
draw_slice_ps(manager, sub_ps, ob_ref, settings.slice_axis, settings.slice_depth);
}
else {
float3 world_size;
BKE_object_dimensions_get(ob, world_size);
float3 slice_count = float3(settings.res) * std::max(0.001f, settings.slice_per_voxel);
draw_volume_ps(manager, sub_ps, ob_ref, scene_state.sample, slice_count, world_size);
}
}
void VolumePass::draw(Manager &manager, View &view, SceneResources &resources)
{
if (!active_) {
return;
}
fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(resources.color_tx));
fb_.bind();
manager.submit(ps_, view);
}
GPUShader *VolumePass::get_shader(bool slice, bool coba, int interpolation, bool smoke)
{
GPUShader *&shader = shaders_[slice][coba][interpolation][smoke];
if (shader == nullptr) {
std::string create_info_name = "workbench_next_volume";
create_info_name += (smoke) ? "_smoke" : "_object";
switch (interpolation) {
case VOLUME_DISPLAY_INTERP_LINEAR:
create_info_name += "_linear";
break;
case VOLUME_DISPLAY_INTERP_CUBIC:
create_info_name += "_cubic";
break;
case VOLUME_DISPLAY_INTERP_CLOSEST:
create_info_name += "_closest";
break;
default:
BLI_assert_unreachable();
}
create_info_name += (coba) ? "_coba" : "_no_coba";
create_info_name += (slice) ? "_slice" : "_no_slice";
shader = GPU_shader_create_from_info_name(create_info_name.c_str());
}
return shader;
}
void VolumePass::draw_slice_ps(
Manager &manager, PassMain::Sub &ps, ObjectRef &ob_ref, int slice_axis_enum, float slice_depth)
{
float4x4 view_mat_inv;
DRW_view_viewmat_get(nullptr, view_mat_inv.ptr(), true);
const int axis = (slice_axis_enum == SLICE_AXIS_AUTO) ?
axis_dominant_v3_single(view_mat_inv[2]) :
slice_axis_enum - 1;
float3 dimensions;
BKE_object_dimensions_get(ob_ref.object, dimensions);
/* 0.05f to achieve somewhat the same opacity as the full view. */
float step_length = std::max(1e-16f, dimensions[axis] * 0.05f);
ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL);
ps.push_constant("slicePosition", slice_depth);
ps.push_constant("sliceAxis", axis);
ps.push_constant("stepLength", step_length);
ps.draw(DRW_cache_quad_get(), manager.resource_handle(ob_ref));
}
void VolumePass::draw_volume_ps(Manager &manager,
PassMain::Sub &ps,
ObjectRef &ob_ref,
int taa_sample,
float3 slice_count,
float3 world_size)
{
double noise_offset;
BLI_halton_1d(3, 0.0, taa_sample, &noise_offset);
int max_slice = std::max({UNPACK3(slice_count)});
float step_length = math::length((1.0f / slice_count) * world_size);
ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT);
ps.push_constant("samplesLen", max_slice);
ps.push_constant("stepLength", step_length);
ps.push_constant("noiseOfs", float(noise_offset));
ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref));
}
} // namespace blender::workbench

View File

@ -126,6 +126,9 @@ GPU_SHADER_CREATE_INFO(draw_pointcloud)
GPU_SHADER_CREATE_INFO(draw_volume).additional_info("draw_modelmat", "draw_resource_id_uniform");
GPU_SHADER_CREATE_INFO(draw_volume_new)
.additional_info("draw_modelmat_new", "draw_resource_handle_new");
GPU_SHADER_CREATE_INFO(draw_gpencil)
.typedef_source("gpencil_shader_shared.h")
.define("DRW_GPENCIL_INFO")

View File

@ -2360,13 +2360,14 @@ void ANIM_OT_keyframe_clear_v3d(wmOperatorType *ot)
ot->idname = "ANIM_OT_keyframe_clear_v3d";
/* callbacks */
ot->invoke = WM_operator_confirm;
ot->invoke = WM_operator_confirm_or_exec;
ot->exec = clear_anim_v3d_exec;
ot->poll = ED_operator_areaactive;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
}
static int delete_key_v3d_without_keying_set(bContext *C, wmOperator *op)
@ -2501,13 +2502,14 @@ void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot)
ot->idname = "ANIM_OT_keyframe_delete_v3d";
/* callbacks */
ot->invoke = WM_operator_confirm;
ot->invoke = WM_operator_confirm_or_exec;
ot->exec = delete_key_v3d_exec;
ot->poll = ED_operator_areaactive;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
}
/* Insert Key Button Operator ------------------------ */

View File

@ -1290,12 +1290,13 @@ void ARMATURE_OT_delete(wmOperatorType *ot)
ot->description = "Remove selected bones from the armature";
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->invoke = WM_operator_confirm_or_exec;
ot->exec = armature_delete_selected_exec;
ot->poll = ED_operator_editarmature;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
}
static bool armature_dissolve_ebone_cb(const char *bone_name, void *arm_p)

View File

@ -709,12 +709,13 @@ void ARMATURE_OT_separate(wmOperatorType *ot)
ot->description = "Isolate selected bones into a separate armature";
/* callbacks */
ot->invoke = WM_operator_confirm;
ot->invoke = WM_operator_confirm_or_exec;
ot->exec = separate_armature_exec;
ot->poll = ED_operator_editarmature;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
}
/** \} */

View File

@ -218,9 +218,10 @@ void AssetList::ensurePreviewsJob(const bContext *C)
int numfiles = filelist_files_ensure(files);
filelist_cache_previews_set(files, true);
filelist_file_cache_slidingwindow_set(files, 128);
/* TODO fetch all previews for now. */
filelist_file_cache_block(files, numfiles / 2);
/* Add one extra entry to ensure nothing is lost because of integer division. */
filelist_file_cache_slidingwindow_set(files, numfiles / 2 + 1);
filelist_file_cache_block(files, 0);
filelist_cache_previews_update(files);
{

View File

@ -462,7 +462,7 @@ static int asset_catalog_new_exec(bContext *C, wmOperator *op)
char *parent_path = RNA_string_get_alloc(op->ptr, "parent_path", nullptr, 0, nullptr);
blender::asset_system::AssetCatalog *new_catalog = ED_asset_catalog_add(
asset_library, "Catalog", parent_path);
asset_library, DATA_("Catalog"), parent_path);
if (sfile) {
ED_fileselect_activate_asset_catalog(sfile, new_catalog->catalog_id);

View File

@ -1446,12 +1446,13 @@ void CURVE_OT_separate(wmOperatorType *ot)
ot->description = "Separate selected points from connected unselected points into a new object";
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->invoke = WM_operator_confirm_or_exec;
ot->exec = separate_exec;
ot->poll = ED_operator_editsurfcurve;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
}
/** \} */

View File

@ -11,6 +11,8 @@
#include "BKE_node.hh"
#include "BKE_node_runtime.hh"
#include "BLT_translation.h"
#include "ED_curves.h"
#include "ED_node.h"
#include "ED_object.h"
@ -63,9 +65,9 @@ void ensure_surface_deformation_node_exists(bContext &C, Object &curves_ob)
Scene *scene = CTX_data_scene(&C);
ModifierData *md = ED_object_modifier_add(
nullptr, bmain, scene, &curves_ob, "Surface Deform", eModifierType_Nodes);
nullptr, bmain, scene, &curves_ob, DATA_("Surface Deform"), eModifierType_Nodes);
NodesModifierData &nmd = *reinterpret_cast<NodesModifierData *>(md);
nmd.node_group = ntreeAddTree(bmain, "Surface Deform", "GeometryNodeTree");
nmd.node_group = ntreeAddTree(bmain, DATA_("Surface Deform"), "GeometryNodeTree");
bNodeTree *ntree = nmd.node_group;
ntreeAddSocketInterface(ntree, SOCK_IN, "NodeSocketGeometry", "Geometry");

View File

@ -120,21 +120,6 @@ static V3DSnapCursorState *gizmo_snap_state_from_rna_get(struct PointerRNA *ptr)
return ED_view3d_cursor_snap_state_active_get();
}
static int gizmo_snap_rna_snap_elements_force_get_fn(struct PointerRNA *ptr,
struct PropertyRNA *UNUSED(prop))
{
V3DSnapCursorState *snap_state = gizmo_snap_state_from_rna_get(ptr);
return snap_state->snap_elem_force;
}
static void gizmo_snap_rna_snap_elements_force_set_fn(struct PointerRNA *ptr,
struct PropertyRNA *UNUSED(prop),
int value)
{
V3DSnapCursorState *snap_state = gizmo_snap_state_from_rna_get(ptr);
snap_state->snap_elem_force = (short)value;
}
static void gizmo_snap_rna_prevpoint_get_fn(struct PointerRNA *ptr,
struct PropertyRNA *UNUSED(prop),
float *values)
@ -336,17 +321,6 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
/* Setup. */
PropertyRNA *prop;
prop = RNA_def_enum_flag(gzt->srna,
"snap_elements_force",
rna_enum_snap_element_items,
SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST,
"Snap Elements",
"");
RNA_def_property_enum_funcs_runtime(prop,
gizmo_snap_rna_snap_elements_force_get_fn,
gizmo_snap_rna_snap_elements_force_set_fn,
NULL);
prop = RNA_def_float_array(gzt->srna,
"prev_point",
3,

View File

@ -290,17 +290,6 @@ typedef enum {
V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE = 1 << 4,
} eV3DSnapCursor;
typedef enum {
V3D_PLACE_DEPTH_SURFACE = 0,
V3D_PLACE_DEPTH_CURSOR_PLANE = 1,
V3D_PLACE_DEPTH_CURSOR_VIEW = 2,
} eV3DPlaceDepth;
typedef enum {
V3D_PLACE_ORIENT_SURFACE = 0,
V3D_PLACE_ORIENT_DEFAULT = 1,
} eV3DPlaceOrient;
typedef struct V3DSnapCursorData {
eSnapMode snap_elem;
float loc[3];
@ -317,16 +306,11 @@ typedef struct V3DSnapCursorData {
typedef struct V3DSnapCursorState {
/* Setup. */
eV3DSnapCursor flag;
eV3DPlaceDepth plane_depth;
eV3DPlaceOrient plane_orient;
uchar color_line[4];
uchar color_point[4];
uchar color_box[4];
float *prevpoint;
float box_dimensions[3];
eSnapMode snap_elem_force; /* If SCE_SNAP_MODE_NONE, use scene settings. */
short plane_axis;
bool use_plane_axis_auto;
bool draw_point;
bool draw_plane;
bool draw_box;

View File

@ -191,8 +191,15 @@ static void ui_popup_menu_create_block(bContext *C,
if (!pup->but) {
pup->block->flag |= UI_BLOCK_NO_FLIP;
}
/* A title is only provided when a Menu has a label, this is not alwas the case, see e.g.
* `VIEW3D_MT_edit_mesh_context_menu` -- this specifies its own label inside the draw function
* depending on vertex/edge/face mode. We still want to flag the uiBlock (but only insert into
* the puphash if we have a title provided). Choosing an entry in a menu will still handle
* puphash later (see `button_activate_exit`) though multiple menus without a label might fight
* for the same storage of the menu memory. Using idname instead (or in combination with the
* label) for the hash could be looked at to solve this. */
pup->block->flag |= UI_BLOCK_POPUP_MEMORY;
if (title && title[0]) {
pup->block->flag |= UI_BLOCK_POPUP_MEMORY;
pup->block->puphash = ui_popup_menu_hash(title);
}
pup->layout = UI_block_layout(

View File

@ -1228,6 +1228,7 @@ static uiBut *template_id_def_new_but(uiBlock *block,
BLT_I18NCONTEXT_ID_POINTCLOUD,
BLT_I18NCONTEXT_ID_VOLUME,
BLT_I18NCONTEXT_ID_SIMULATION, );
BLT_I18N_MSGID_MULTI_CTXT("New", BLT_I18NCONTEXT_ID_PAINTCURVE, );
/* NOTE: BLT_I18N_MSGID_MULTI_CTXT takes a maximum number of parameters,
* check the definition to see if a new call must be added when the limit
* is exceeded. */

View File

@ -1505,12 +1505,13 @@ void MASK_OT_delete(wmOperatorType *ot)
ot->idname = "MASK_OT_delete";
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->invoke = WM_operator_confirm_or_exec;
ot->exec = delete_exec;
ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
}
/* *** switch direction *** */

View File

@ -631,12 +631,13 @@ void MBALL_OT_delete_metaelems(wmOperatorType *ot)
ot->idname = "MBALL_OT_delete_metaelems";
/* callback functions */
ot->invoke = WM_operator_confirm;
ot->invoke = WM_operator_confirm_or_exec;
ot->exec = delete_metaelems_exec;
ot->poll = ED_operator_editmball;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
}
/** \} */

View File

@ -306,12 +306,13 @@ void OBJECT_OT_vertex_parent_set(wmOperatorType *ot)
ot->idname = "OBJECT_OT_vertex_parent_set";
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->invoke = WM_operator_confirm_or_exec;
ot->poll = vertex_parent_set_poll;
ot->exec = vertex_parent_set_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
}
/** \} */
@ -1125,12 +1126,13 @@ void OBJECT_OT_parent_no_inverse_set(wmOperatorType *ot)
ot->idname = "OBJECT_OT_parent_no_inverse_set";
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->invoke = WM_operator_confirm_or_exec;
ot->exec = parent_noinv_set_exec;
ot->poll = ED_operator_object_active_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
RNA_def_boolean(ot->srna,
"keep_transform",

View File

@ -200,6 +200,7 @@ void DPAINT_OT_type_toggle(wmOperatorType *ot)
MOD_DYNAMICPAINT_TYPE_CANVAS,
"Type",
"");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_SIMULATION);
ot->prop = prop;
}

View File

@ -584,11 +584,11 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
}
ID *id = *id_p;
ID *id_self = cb_data->id_self;
ID *self_id = cb_data->self_id;
const int cb_flag = cb_data->cb_flag;
if (cb_flag == IDWALK_CB_LOOPBACK || id == id_self) {
if (cb_flag == IDWALK_CB_LOOPBACK || id == self_id) {
/* IDs may end up referencing themselves one way or the other, and those
* (the id_self ones) have always already been processed. */
* (the self_id ones) have always already been processed. */
return IDWALK_RET_STOP_RECURSION;
}

View File

@ -17,6 +17,8 @@
#include "BLI_math_vector.h"
#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_paint.h"
@ -147,7 +149,7 @@ static int paintcurve_new_exec(bContext *C, wmOperator * /*op*/)
Main *bmain = CTX_data_main(C);
if (p && p->brush) {
p->brush->paint_curve = BKE_paint_curve_add(bmain, "PaintCurve");
p->brush->paint_curve = BKE_paint_curve_add(bmain, DATA_("PaintCurve"));
}
WM_event_add_notifier(C, NC_PAINTCURVE | NA_ADDED, nullptr);
@ -181,7 +183,7 @@ static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
PaintCurve *pc = br->paint_curve;
if (!pc) {
br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve");
br->paint_curve = pc = BKE_paint_curve_add(bmain, DATA_("PaintCurve"));
}
ED_paintcurve_undo_push_begin(op->type->name);

View File

@ -64,6 +64,7 @@
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
#include "BKE_node.hh"
#include "BKE_node_runtime.hh"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@ -6636,7 +6637,9 @@ static void default_paint_slot_color_get(int layer_type, Material *ma, float col
case LAYER_ROUGHNESS:
case LAYER_METALLIC: {
bNodeTree *ntree = nullptr;
bNode *in_node = ma ? blender::bke::ntreeFindType(ma->nodetree, SH_NODE_BSDF_PRINCIPLED) : nullptr;
ma->nodetree->ensure_topology_cache();
const blender::Span<bNode *> nodes = ma->nodetree->nodes_by_type("ShaderNodeBsdfPrincipled");
bNode *in_node = nodes.is_empty() ? nullptr : nodes.first();
if (!in_node) {
/* An existing material or Principled BSDF node could not be found.
* Copy default color values from a default Principled BSDF instead. */
@ -6740,7 +6743,9 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
nodeSetActive(ntree, new_node);
/* Connect to first available principled BSDF node. */
bNode *in_node = blender::bke::ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
ntree->ensure_topology_cache();
const blender::Span<bNode *> bsdf_nodes = ntree->nodes_by_type("ShaderNodeBsdfPrincipled");
bNode *in_node = bsdf_nodes.is_empty() ? nullptr : bsdf_nodes.first();
bNode *out_node = new_node;
if (in_node != nullptr) {
@ -6776,7 +6781,9 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
}
else if (type == LAYER_DISPLACEMENT) {
/* Connect to the displacement output socket */
in_node = blender::bke::ntreeFindType(ntree, SH_NODE_OUTPUT_MATERIAL);
const blender::Span<bNode *> output_nodes = ntree->nodes_by_type(
"ShaderNodeOutputMaterial");
in_node = output_nodes.is_empty() ? nullptr : output_nodes.first();
if (in_node != nullptr) {
in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);

View File

@ -532,12 +532,13 @@ void CLIP_OT_graph_delete_curve(wmOperatorType *ot)
ot->idname = "CLIP_OT_graph_delete_curve";
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->invoke = WM_operator_confirm_or_exec;
ot->exec = delete_curve_exec;
ot->poll = clip_graph_knots_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
}
/******************** delete knot operator ********************/

View File

@ -250,12 +250,13 @@ void CLIP_OT_delete_track(wmOperatorType *ot)
ot->description = "Delete selected tracks";
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->invoke = WM_operator_confirm_or_exec;
ot->exec = delete_track_exec;
ot->poll = ED_space_clip_tracking_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
}
/** \} */
@ -315,12 +316,13 @@ void CLIP_OT_delete_marker(wmOperatorType *ot)
ot->description = "Delete marker for current frame from selected tracks";
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->invoke = WM_operator_confirm_or_exec;
ot->exec = delete_marker_exec;
ot->poll = ED_space_clip_tracking_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
}
/** \} */

View File

@ -17,6 +17,7 @@ set(INC
../../windowmanager
../../../../intern/atomic
../../../../intern/guardedalloc
../../../../extern/fmtlib/include
# dna_type_offsets.h
${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern

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