diff options
370 files changed, 13681 insertions, 5268 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 40671071921..fb74675088e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,7 +195,7 @@ endif() # Options # First platform specific non-cached vars -if(UNIX AND NOT APPLE) +if(UNIX AND NOT (APPLE OR HAIKU)) set(WITH_X11 ON) endif() @@ -729,7 +729,7 @@ if(WITH_INTERNATIONAL) endif() if(WITH_PYTHON) - # While we have this as an '#error' in bpy_util.h, + # While we have this as an '#error' in 'bpy_capi_utils.h', # upgrading Python tends to cause confusion for users who build. # Give the error message early to make this more obvious. # diff --git a/build_files/cmake/Modules/FindSDL2.cmake b/build_files/cmake/Modules/FindSDL2.cmake index 7c40a6ef6f3..e84c6845156 100644 --- a/build_files/cmake/Modules/FindSDL2.cmake +++ b/build_files/cmake/Modules/FindSDL2.cmake @@ -42,7 +42,7 @@ FIND_PATH(SDL2_INCLUDE_DIR HINTS ${_sdl2_SEARCH_DIRS} PATH_SUFFIXES - include/SDL2 include + include/SDL2 include SDL2 ) FIND_LIBRARY(SDL2_LIBRARY diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 25785dd8ba1..ff696a4352b 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -1520,6 +1520,7 @@ function(find_python_package PATH_SUFFIXES site-packages dist-packages + vendor-packages NO_DEFAULT_PATH ) @@ -1530,6 +1531,8 @@ function(find_python_package "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/site-packages/${package}', " "'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/dist-packages/${package}', " "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/dist-packages/${package}', " + "'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/vendor-packages/${package}', " + "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/vendor-packages/${package}', " "\n" "The 'WITH_PYTHON_INSTALL_${_upper_package}' option will be ignored when installing Python.\n" "The build will be usable, only add-ons that depend on this package won't be functional." diff --git a/build_files/cmake/packaging.cmake b/build_files/cmake/packaging.cmake index 5b894d96f95..2408e4eaff9 100644 --- a/build_files/cmake/packaging.cmake +++ b/build_files/cmake/packaging.cmake @@ -25,7 +25,7 @@ set(MY_WC_HASH "unknown") if(EXISTS ${CMAKE_SOURCE_DIR}/.git/) find_package(Git) if(GIT_FOUND) - message(STATUS "Found Git: ${GIT_EXECUTABLE}") + # message(STATUS "Found Git: ${GIT_EXECUTABLE}") execute_process(COMMAND git rev-parse --short HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE MY_WC_HASH diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 3581fe64341..d5e29164696 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -358,7 +358,11 @@ if(WITH_OPENSUBDIV OR WITH_CYCLES_OPENSUBDIV) endif() # OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed -list(APPEND PLATFORM_LINKLIBS -lutil -lc -lm) +if(HAIKU) + list(APPEND PLATFORM_LINKLIBS -lnetwork) +else() + list(APPEND PLATFORM_LINKLIBS -lutil -lc -lm) +endif() find_package(Threads REQUIRED) list(APPEND PLATFORM_LINKLIBS ${CMAKE_THREAD_LIBS_INIT}) diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index 5cc5fb8c7d6..d1a19784365 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -142,10 +142,8 @@ if(NOT DEFINED LIBDIR) message(STATUS "32 bit compiler detected.") set(LIBDIR_BASE "windows") endif() - if(MSVC_VERSION EQUAL 1911) - message(STATUS "Visual Studio 2017 detected.") - set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14) - elseif(MSVC_VERSION EQUAL 1910) + # Can be 1910..1912 + if(MSVC_VERSION GREATER_EQUAL 1910) message(STATUS "Visual Studio 2017 detected.") set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14) elseif(MSVC_VERSION EQUAL 1900) diff --git a/extern/audaspace/src/fx/DynamicMusic.cpp b/extern/audaspace/src/fx/DynamicMusic.cpp index b77cd749576..2b0acc06fbc 100644 --- a/extern/audaspace/src/fx/DynamicMusic.cpp +++ b/extern/audaspace/src/fx/DynamicMusic.cpp @@ -25,7 +25,7 @@ AUD_NAMESPACE_BEGIN DynamicMusic::DynamicMusic(std::shared_ptr<IDevice> device) : -m_device(device), m_fadeTime(1.0f) +m_fadeTime(1.0f), m_device(device) { m_id = 0; m_transitioning = false; diff --git a/extern/audaspace/src/fx/PlaybackCategory.cpp b/extern/audaspace/src/fx/PlaybackCategory.cpp index e09a74c4017..1891be96d16 100644 --- a/extern/audaspace/src/fx/PlaybackCategory.cpp +++ b/extern/audaspace/src/fx/PlaybackCategory.cpp @@ -25,7 +25,7 @@ struct HandleData { }; PlaybackCategory::PlaybackCategory(std::shared_ptr<IDevice> device) : - m_device(device), m_volumeStorage(std::make_shared<VolumeStorage>(1.0f)), m_status(STATUS_PLAYING), m_currentID(0) + m_currentID(0), m_device(device), m_status(STATUS_PLAYING), m_volumeStorage(std::make_shared<VolumeStorage>(1.0f)) { } diff --git a/extern/glog/src/config.h b/extern/glog/src/config.h index f5c9c0b0a7b..2703b7ba9dd 100644 --- a/extern/glog/src/config.h +++ b/extern/glog/src/config.h @@ -14,4 +14,6 @@ #include "windows/config.h" #elif defined(__GNU__) #include "config_hurd.h" +#elif defined(__HAIKU__) + #include "config_haiku.h" #endif diff --git a/extern/glog/src/config_haiku.h b/extern/glog/src/config_haiku.h new file mode 100644 index 00000000000..4e6703bc186 --- /dev/null +++ b/extern/glog/src/config_haiku.h @@ -0,0 +1,172 @@ +/* src/config.h. Generated from config.h.in by configure. */ +/* src/config.h.in. Generated from configure.ac by autoheader. */ + +/* Namespace for Google classes */ +#define GOOGLE_NAMESPACE google + +/* Define if you have the `dladdr' function */ +#define HAVE_DLADDR 1 + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#define HAVE_DLFCN_H 1 + +/* 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 1 + +/* Define to 1 if you have the <glob.h> header file. */ +#define HAVE_GLOB_H 1 + +/* 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 1 + +/* 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 1 + +/* 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 1 + +/* define if the compiler implements namespaces */ +#define HAVE_NAMESPACES 1 + +/* Define if you have the 'pread' function */ +#define HAVE_PREAD 1 + +/* Define if you have POSIX threads libraries and header files. */ +#define HAVE_PTHREAD 1 + +/* Define to 1 if you have the <pwd.h> header file. */ +#define HAVE_PWD_H 1 + +/* Define if you have the 'pwrite' function */ +#define HAVE_PWRITE 1 + +/* define if the compiler implements pthread_rwlock_* */ +#define HAVE_RWLOCK 1 + +/* 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 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* 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 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/syscall.h> header file. */ +/* #undef HAVE_SYS_SYSCALL_H */ + +/* Define to 1 if you have the <sys/time.h> header file. */ +#define HAVE_SYS_TIME_H 1 + +/* 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 1 + +/* 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 if the compiler supports using expression for operator */ +#define HAVE_USING_OPERATOR 1 + +/* define if your compiler has __attribute__ */ +#define HAVE___ATTRIBUTE__ 1 + +/* define if your compiler has __builtin_expect */ +#define HAVE___BUILTIN_EXPECT 1 + +/* define if your compiler has __sync_val_compare_and_swap */ +/* #undef HAVE___SYNC_VAL_COMPARE_AND_SWAP */ + +/* Name of package */ +#define PACKAGE "glog" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "opensource@google.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "glog" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "glog 0.3.4" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "glog" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.3.4" + +/* How to access the PC from a struct ucontext */ +/* #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP] */ + +/* 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. */ +/* #undef STDC_HEADERS */ + +#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 */ +#define VERSION "0.3.4" + +/* 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 { + +/* 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 diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp index 0b9a4042e0e..2d4b0d35e54 100644 --- a/intern/cycles/app/cycles_standalone.cpp +++ b/intern/cycles/app/cycles_standalone.cpp @@ -121,7 +121,6 @@ static void scene_init() static void session_init() { options.session = new Session(options.session_params); - options.session->reset(session_buffer_params(), options.session_params.samples); if(options.session_params.background && !options.quiet) options.session->progress.set_update_callback(function_bind(&session_print_status)); @@ -134,6 +133,7 @@ static void session_init() scene_init(); options.session->scene = options.scene; + options.session->reset(session_buffer_params(), options.session_params.samples); options.session->start(); } diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index 999b9230d29..e476c012de1 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -190,9 +190,9 @@ public: KernelFunctions<void(*)(int, int, float*, float*, float*, float*, int*, int, int)> filter_nlm_update_output_kernel; KernelFunctions<void(*)(float*, float*, int*, int)> filter_nlm_normalize_kernel; - KernelFunctions<void(*)(float*, int, int, int, float*, int*, int*, int, int, float)> filter_construct_transform_kernel; - KernelFunctions<void(*)(int, int, float*, float*, float*, int*, float*, float3*, int*, int*, int, int, int, int)> filter_nlm_construct_gramian_kernel; - KernelFunctions<void(*)(int, int, int, int, int, float*, int*, float*, float3*, int*, int)> filter_finalize_kernel; + KernelFunctions<void(*)(float*, int, int, int, float*, int*, int*, int, int, float)> filter_construct_transform_kernel; + KernelFunctions<void(*)(int, int, float*, float*, float*, int*, float*, float3*, int*, int*, int, int, int)> filter_nlm_construct_gramian_kernel; + KernelFunctions<void(*)(int, int, int, float*, int*, float*, float3*, int*, int)> filter_finalize_kernel; KernelFunctions<void(*)(KernelGlobals *, ccl_constant KernelData*, ccl_global void*, int, ccl_global char*, int, int, int, int, int, int, int, int, ccl_global int*, int, @@ -565,13 +565,13 @@ public: (float*) color_variance_ptr, difference, local_rect, - task->buffer.w, + task->buffer.stride, task->buffer.pass_stride, 1.0f, task->nlm_k_2); - filter_nlm_blur_kernel()(difference, blurDifference, local_rect, task->buffer.w, 4); - filter_nlm_calc_weight_kernel()(blurDifference, difference, local_rect, task->buffer.w, 4); - filter_nlm_blur_kernel()(difference, blurDifference, local_rect, task->buffer.w, 4); + filter_nlm_blur_kernel()(difference, blurDifference, local_rect, task->buffer.stride, 4); + filter_nlm_calc_weight_kernel()(blurDifference, difference, local_rect, task->buffer.stride, 4); + filter_nlm_blur_kernel()(difference, blurDifference, local_rect, task->buffer.stride, 4); filter_nlm_construct_gramian_kernel()(dx, dy, blurDifference, (float*) task->buffer.mem.device_pointer, @@ -580,9 +580,8 @@ public: (float*) task->storage.XtWX.device_pointer, (float3*) task->storage.XtWY.device_pointer, local_rect, - &task->reconstruction_state.filter_rect.x, - task->buffer.w, - task->buffer.h, + &task->reconstruction_state.filter_window.x, + task->buffer.stride, 4, task->buffer.pass_stride); } @@ -591,8 +590,6 @@ public: filter_finalize_kernel()(x, y, y*task->filter_area.z + x, - task->buffer.w, - task->buffer.h, (float*) output_ptr, (int*) task->storage.rank.device_pointer, (float*) task->storage.XtWX.device_pointer, @@ -921,7 +918,7 @@ protected: #endif } - virtual bool load_kernels(DeviceRequestedFeatures& requested_features_) { + virtual bool load_kernels(const DeviceRequestedFeatures& requested_features_) { requested_features = requested_features_; return true; diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index ce0df36a76f..2e5f47002e8 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -1087,6 +1087,19 @@ public: threads, threads, 1, \ 0, 0, args, 0)); +/* Similar as above, but for 1-dimensional blocks. */ +#define CUDA_GET_BLOCKSIZE_1D(func, w, h) \ + int threads_per_block; \ + cuda_assert(cuFuncGetAttribute(&threads_per_block, CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, func)); \ + int xblocks = ((w) + threads_per_block - 1)/threads_per_block; \ + int yblocks = h; + +#define CUDA_LAUNCH_KERNEL_1D(func, args) \ + cuda_assert(cuLaunchKernel(func, \ + xblocks, yblocks, 1, \ + threads_per_block, 1, 1, \ + 0, 0, args, 0)); + bool denoising_non_local_means(device_ptr image_ptr, device_ptr guide_ptr, device_ptr variance_ptr, device_ptr out_ptr, DenoisingTask *task) { @@ -1095,60 +1108,65 @@ public: CUDAContextScope scope(this); - int4 rect = task->rect; - int w = align_up(rect.z-rect.x, 4); - int h = rect.w-rect.y; + int stride = task->buffer.stride; + int w = task->buffer.width; + int h = task->buffer.h; int r = task->nlm_state.r; int f = task->nlm_state.f; float a = task->nlm_state.a; float k_2 = task->nlm_state.k_2; - CUdeviceptr difference = task->nlm_state.temporary_1_ptr; - CUdeviceptr blurDifference = task->nlm_state.temporary_2_ptr; - CUdeviceptr weightAccum = task->nlm_state.temporary_3_ptr; + int shift_stride = stride*h; + int num_shifts = (2*r+1)*(2*r+1); + int mem_size = sizeof(float)*shift_stride*2*num_shifts; + int channel_offset = 0; - cuda_assert(cuMemsetD8(weightAccum, 0, sizeof(float)*w*h)); - cuda_assert(cuMemsetD8(out_ptr, 0, sizeof(float)*w*h)); + CUdeviceptr temporary_mem; + cuda_assert(cuMemAlloc(&temporary_mem, mem_size)); + CUdeviceptr difference = temporary_mem; + CUdeviceptr blurDifference = temporary_mem + sizeof(float)*shift_stride * num_shifts; - CUfunction cuNLMCalcDifference, cuNLMBlur, cuNLMCalcWeight, cuNLMUpdateOutput, cuNLMNormalize; - cuda_assert(cuModuleGetFunction(&cuNLMCalcDifference, cuFilterModule, "kernel_cuda_filter_nlm_calc_difference")); - cuda_assert(cuModuleGetFunction(&cuNLMBlur, cuFilterModule, "kernel_cuda_filter_nlm_blur")); - cuda_assert(cuModuleGetFunction(&cuNLMCalcWeight, cuFilterModule, "kernel_cuda_filter_nlm_calc_weight")); - cuda_assert(cuModuleGetFunction(&cuNLMUpdateOutput, cuFilterModule, "kernel_cuda_filter_nlm_update_output")); - cuda_assert(cuModuleGetFunction(&cuNLMNormalize, cuFilterModule, "kernel_cuda_filter_nlm_normalize")); + CUdeviceptr weightAccum = task->nlm_state.temporary_3_ptr; + cuda_assert(cuMemsetD8(weightAccum, 0, sizeof(float)*shift_stride)); + cuda_assert(cuMemsetD8(out_ptr, 0, sizeof(float)*shift_stride)); - cuda_assert(cuFuncSetCacheConfig(cuNLMCalcDifference, CU_FUNC_CACHE_PREFER_L1)); - cuda_assert(cuFuncSetCacheConfig(cuNLMBlur, CU_FUNC_CACHE_PREFER_L1)); - cuda_assert(cuFuncSetCacheConfig(cuNLMCalcWeight, CU_FUNC_CACHE_PREFER_L1)); - cuda_assert(cuFuncSetCacheConfig(cuNLMUpdateOutput, CU_FUNC_CACHE_PREFER_L1)); - cuda_assert(cuFuncSetCacheConfig(cuNLMNormalize, CU_FUNC_CACHE_PREFER_L1)); + { + CUfunction cuNLMCalcDifference, cuNLMBlur, cuNLMCalcWeight, cuNLMUpdateOutput; + cuda_assert(cuModuleGetFunction(&cuNLMCalcDifference, cuFilterModule, "kernel_cuda_filter_nlm_calc_difference")); + cuda_assert(cuModuleGetFunction(&cuNLMBlur, cuFilterModule, "kernel_cuda_filter_nlm_blur")); + cuda_assert(cuModuleGetFunction(&cuNLMCalcWeight, cuFilterModule, "kernel_cuda_filter_nlm_calc_weight")); + cuda_assert(cuModuleGetFunction(&cuNLMUpdateOutput, cuFilterModule, "kernel_cuda_filter_nlm_update_output")); - CUDA_GET_BLOCKSIZE(cuNLMCalcDifference, rect.z-rect.x, rect.w-rect.y); + cuda_assert(cuFuncSetCacheConfig(cuNLMCalcDifference, CU_FUNC_CACHE_PREFER_L1)); + cuda_assert(cuFuncSetCacheConfig(cuNLMBlur, CU_FUNC_CACHE_PREFER_L1)); + cuda_assert(cuFuncSetCacheConfig(cuNLMCalcWeight, CU_FUNC_CACHE_PREFER_L1)); + cuda_assert(cuFuncSetCacheConfig(cuNLMUpdateOutput, CU_FUNC_CACHE_PREFER_L1)); - int dx, dy; - int4 local_rect; - int channel_offset = 0; - void *calc_difference_args[] = {&dx, &dy, &guide_ptr, &variance_ptr, &difference, &local_rect, &w, &channel_offset, &a, &k_2}; - void *blur_args[] = {&difference, &blurDifference, &local_rect, &w, &f}; - void *calc_weight_args[] = {&blurDifference, &difference, &local_rect, &w, &f}; - void *update_output_args[] = {&dx, &dy, &blurDifference, &image_ptr, &out_ptr, &weightAccum, &local_rect, &w, &f}; - - for(int i = 0; i < (2*r+1)*(2*r+1); i++) { - dy = i / (2*r+1) - r; - dx = i % (2*r+1) - r; - local_rect = make_int4(max(0, -dx), max(0, -dy), rect.z-rect.x - max(0, dx), rect.w-rect.y - max(0, dy)); - - CUDA_LAUNCH_KERNEL(cuNLMCalcDifference, calc_difference_args); - CUDA_LAUNCH_KERNEL(cuNLMBlur, blur_args); - CUDA_LAUNCH_KERNEL(cuNLMCalcWeight, calc_weight_args); - CUDA_LAUNCH_KERNEL(cuNLMBlur, blur_args); - CUDA_LAUNCH_KERNEL(cuNLMUpdateOutput, update_output_args); - } - - local_rect = make_int4(0, 0, rect.z-rect.x, rect.w-rect.y); - void *normalize_args[] = {&out_ptr, &weightAccum, &local_rect, &w}; - CUDA_LAUNCH_KERNEL(cuNLMNormalize, normalize_args); - cuda_assert(cuCtxSynchronize()); + CUDA_GET_BLOCKSIZE_1D(cuNLMCalcDifference, w*h, num_shifts); + + void *calc_difference_args[] = {&guide_ptr, &variance_ptr, &difference, &w, &h, &stride, &shift_stride, &r, &channel_offset, &a, &k_2}; + void *blur_args[] = {&difference, &blurDifference, &w, &h, &stride, &shift_stride, &r, &f}; + void *calc_weight_args[] = {&blurDifference, &difference, &w, &h, &stride, &shift_stride, &r, &f}; + void *update_output_args[] = {&blurDifference, &image_ptr, &out_ptr, &weightAccum, &w, &h, &stride, &shift_stride, &r, &f}; + + CUDA_LAUNCH_KERNEL_1D(cuNLMCalcDifference, calc_difference_args); + CUDA_LAUNCH_KERNEL_1D(cuNLMBlur, blur_args); + CUDA_LAUNCH_KERNEL_1D(cuNLMCalcWeight, calc_weight_args); + CUDA_LAUNCH_KERNEL_1D(cuNLMBlur, blur_args); + CUDA_LAUNCH_KERNEL_1D(cuNLMUpdateOutput, update_output_args); + } + + cuMemFree(temporary_mem); + + { + CUfunction cuNLMNormalize; + cuda_assert(cuModuleGetFunction(&cuNLMNormalize, cuFilterModule, "kernel_cuda_filter_nlm_normalize")); + cuda_assert(cuFuncSetCacheConfig(cuNLMNormalize, CU_FUNC_CACHE_PREFER_L1)); + void *normalize_args[] = {&out_ptr, &weightAccum, &w, &h, &stride}; + CUDA_GET_BLOCKSIZE(cuNLMNormalize, w, h); + CUDA_LAUNCH_KERNEL(cuNLMNormalize, normalize_args); + cuda_assert(cuCtxSynchronize()); + } return !have_error(); } @@ -1194,91 +1212,81 @@ public: mem_zero(task->storage.XtWX); mem_zero(task->storage.XtWY); - CUfunction cuNLMCalcDifference, cuNLMBlur, cuNLMCalcWeight, cuNLMConstructGramian, cuFinalize; - cuda_assert(cuModuleGetFunction(&cuNLMCalcDifference, cuFilterModule, "kernel_cuda_filter_nlm_calc_difference")); - cuda_assert(cuModuleGetFunction(&cuNLMBlur, cuFilterModule, "kernel_cuda_filter_nlm_blur")); - cuda_assert(cuModuleGetFunction(&cuNLMCalcWeight, cuFilterModule, "kernel_cuda_filter_nlm_calc_weight")); - cuda_assert(cuModuleGetFunction(&cuNLMConstructGramian, cuFilterModule, "kernel_cuda_filter_nlm_construct_gramian")); - cuda_assert(cuModuleGetFunction(&cuFinalize, cuFilterModule, "kernel_cuda_filter_finalize")); + int r = task->radius; + int f = 4; + float a = 1.0f; + float k_2 = task->nlm_k_2; - cuda_assert(cuFuncSetCacheConfig(cuNLMCalcDifference, CU_FUNC_CACHE_PREFER_L1)); - cuda_assert(cuFuncSetCacheConfig(cuNLMBlur, CU_FUNC_CACHE_PREFER_L1)); - cuda_assert(cuFuncSetCacheConfig(cuNLMCalcWeight, CU_FUNC_CACHE_PREFER_L1)); - cuda_assert(cuFuncSetCacheConfig(cuNLMConstructGramian, CU_FUNC_CACHE_PREFER_SHARED)); - cuda_assert(cuFuncSetCacheConfig(cuFinalize, CU_FUNC_CACHE_PREFER_L1)); + int w = task->reconstruction_state.source_w; + int h = task->reconstruction_state.source_h; + int stride = task->buffer.stride; - CUDA_GET_BLOCKSIZE(cuNLMCalcDifference, - task->reconstruction_state.source_w, - task->reconstruction_state.source_h); + int shift_stride = stride*h; + int num_shifts = (2*r+1)*(2*r+1); + int mem_size = sizeof(float)*shift_stride*num_shifts; - CUdeviceptr difference = task->reconstruction_state.temporary_1_ptr; - CUdeviceptr blurDifference = task->reconstruction_state.temporary_2_ptr; + CUdeviceptr temporary_mem; + cuda_assert(cuMemAlloc(&temporary_mem, 2*mem_size)); + CUdeviceptr difference = temporary_mem; + CUdeviceptr blurDifference = temporary_mem + mem_size; - int r = task->radius; - int f = 4; - float a = 1.0f; - for(int i = 0; i < (2*r+1)*(2*r+1); i++) { - int dy = i / (2*r+1) - r; - int dx = i % (2*r+1) - r; - - int local_rect[4] = {max(0, -dx), max(0, -dy), - task->reconstruction_state.source_w - max(0, dx), - task->reconstruction_state.source_h - max(0, dy)}; - - void *calc_difference_args[] = {&dx, &dy, - &color_ptr, - &color_variance_ptr, - &difference, - &local_rect, - &task->buffer.w, - &task->buffer.pass_stride, - &a, - &task->nlm_k_2}; - CUDA_LAUNCH_KERNEL(cuNLMCalcDifference, calc_difference_args); - - void *blur_args[] = {&difference, - &blurDifference, - &local_rect, - &task->buffer.w, - &f}; - CUDA_LAUNCH_KERNEL(cuNLMBlur, blur_args); - - void *calc_weight_args[] = {&blurDifference, - &difference, - &local_rect, - &task->buffer.w, - &f}; - CUDA_LAUNCH_KERNEL(cuNLMCalcWeight, calc_weight_args); - - /* Reuse previous arguments. */ - CUDA_LAUNCH_KERNEL(cuNLMBlur, blur_args); - - void *construct_gramian_args[] = {&dx, &dy, - &blurDifference, + { + CUfunction cuNLMCalcDifference, cuNLMBlur, cuNLMCalcWeight, cuNLMConstructGramian; + cuda_assert(cuModuleGetFunction(&cuNLMCalcDifference, cuFilterModule, "kernel_cuda_filter_nlm_calc_difference")); + cuda_assert(cuModuleGetFunction(&cuNLMBlur, cuFilterModule, "kernel_cuda_filter_nlm_blur")); + cuda_assert(cuModuleGetFunction(&cuNLMCalcWeight, cuFilterModule, "kernel_cuda_filter_nlm_calc_weight")); + cuda_assert(cuModuleGetFunction(&cuNLMConstructGramian, cuFilterModule, "kernel_cuda_filter_nlm_construct_gramian")); + + cuda_assert(cuFuncSetCacheConfig(cuNLMCalcDifference, CU_FUNC_CACHE_PREFER_L1)); + cuda_assert(cuFuncSetCacheConfig(cuNLMBlur, CU_FUNC_CACHE_PREFER_L1)); + cuda_assert(cuFuncSetCacheConfig(cuNLMCalcWeight, CU_FUNC_CACHE_PREFER_L1)); + cuda_assert(cuFuncSetCacheConfig(cuNLMConstructGramian, CU_FUNC_CACHE_PREFER_SHARED)); + + CUDA_GET_BLOCKSIZE_1D(cuNLMCalcDifference, + task->reconstruction_state.source_w * task->reconstruction_state.source_h, + num_shifts); + + void *calc_difference_args[] = {&color_ptr, &color_variance_ptr, &difference, &w, &h, &stride, &shift_stride, &r, &task->buffer.pass_stride, &a, &k_2}; + void *blur_args[] = {&difference, &blurDifference, &w, &h, &stride, &shift_stride, &r, &f}; + void *calc_weight_args[] = {&blurDifference, &difference, &w, &h, &stride, &shift_stride, &r, &f}; + void *construct_gramian_args[] = {&blurDifference, &task->buffer.mem.device_pointer, &task->storage.transform.device_pointer, &task->storage.rank.device_pointer, &task->storage.XtWX.device_pointer, &task->storage.XtWY.device_pointer, - &local_rect, - &task->reconstruction_state.filter_rect, - &task->buffer.w, - &task->buffer.h, + &task->reconstruction_state.filter_window, + &w, &h, &stride, + &shift_stride, &r, &f, &task->buffer.pass_stride}; - CUDA_LAUNCH_KERNEL(cuNLMConstructGramian, construct_gramian_args); - } - - void *finalize_args[] = {&task->buffer.w, - &task->buffer.h, - &output_ptr, - &task->storage.rank.device_pointer, - &task->storage.XtWX.device_pointer, - &task->storage.XtWY.device_pointer, - &task->filter_area, - &task->reconstruction_state.buffer_params.x, - &task->render_buffer.samples}; - CUDA_LAUNCH_KERNEL(cuFinalize, finalize_args); + + CUDA_LAUNCH_KERNEL_1D(cuNLMCalcDifference, calc_difference_args); + CUDA_LAUNCH_KERNEL_1D(cuNLMBlur, blur_args); + CUDA_LAUNCH_KERNEL_1D(cuNLMCalcWeight, calc_weight_args); + CUDA_LAUNCH_KERNEL_1D(cuNLMBlur, blur_args); + CUDA_LAUNCH_KERNEL_1D(cuNLMConstructGramian, construct_gramian_args); + } + + cuMemFree(temporary_mem); + + { + CUfunction cuFinalize; + cuda_assert(cuModuleGetFunction(&cuFinalize, cuFilterModule, "kernel_cuda_filter_finalize")); + cuda_assert(cuFuncSetCacheConfig(cuFinalize, CU_FUNC_CACHE_PREFER_L1)); + void *finalize_args[] = {&output_ptr, + &task->storage.rank.device_pointer, + &task->storage.XtWX.device_pointer, + &task->storage.XtWY.device_pointer, + &task->filter_area, + &task->reconstruction_state.buffer_params.x, + &task->render_buffer.samples}; + CUDA_GET_BLOCKSIZE(cuFinalize, + task->reconstruction_state.source_w, + task->reconstruction_state.source_h); + CUDA_LAUNCH_KERNEL(cuFinalize, finalize_args); + } + cuda_assert(cuCtxSynchronize()); return !have_error(); diff --git a/intern/cycles/device/device_denoising.cpp b/intern/cycles/device/device_denoising.cpp index 69c43e4a8cf..1862deb9a61 100644 --- a/intern/cycles/device/device_denoising.cpp +++ b/intern/cycles/device/device_denoising.cpp @@ -57,10 +57,9 @@ void DenoisingTask::init_from_devicetask(const DeviceTask &task) render_buffer.denoising_clean_offset = task.pass_denoising_clean; /* Expand filter_area by radius pixels and clamp the result to the extent of the neighboring tiles */ - rect = make_int4(max(tiles->x[0], filter_area.x - radius), - max(tiles->y[0], filter_area.y - radius), - min(tiles->x[3], filter_area.x + filter_area.z + radius), - min(tiles->y[3], filter_area.y + filter_area.w + radius)); + rect = rect_from_shape(filter_area.x, filter_area.y, filter_area.z, filter_area.w); + rect = rect_expand(rect, radius); + rect = rect_clip(rect, make_int4(tiles->x[0], tiles->y[0], tiles->x[3], tiles->y[3])); } void DenoisingTask::tiles_from_rendertiles(RenderTile *rtiles) @@ -93,9 +92,10 @@ bool DenoisingTask::run_denoising() { /* Allocate denoising buffer. */ buffer.passes = 14; - buffer.w = align_up(rect.z - rect.x, 4); + buffer.width = rect.z - rect.x; + buffer.stride = align_up(buffer.width, 4); buffer.h = rect.w - rect.y; - buffer.pass_stride = align_up(buffer.w * buffer.h, divide_up(device->mem_address_alignment(), sizeof(float))); + buffer.pass_stride = align_up(buffer.stride * buffer.h, divide_up(device->mem_address_alignment(), sizeof(float))); buffer.mem.alloc_to_device(buffer.pass_stride * buffer.passes, false); device_ptr null_ptr = (device_ptr) 0; @@ -203,15 +203,17 @@ bool DenoisingTask::run_denoising() functions.construct_transform(); - storage.temporary_1.alloc_to_device(buffer.w*buffer.h, false); - storage.temporary_2.alloc_to_device(buffer.w*buffer.h, false); - reconstruction_state.temporary_1_ptr = storage.temporary_1.device_pointer; - reconstruction_state.temporary_2_ptr = storage.temporary_2.device_pointer; + device_only_memory<float> temporary_1(device, "Denoising NLM temporary 1"); + device_only_memory<float> temporary_2(device, "Denoising NLM temporary 2"); + temporary_1.alloc_to_device(buffer.pass_stride, false); + temporary_2.alloc_to_device(buffer.pass_stride, false); + reconstruction_state.temporary_1_ptr = temporary_1.device_pointer; + reconstruction_state.temporary_2_ptr = temporary_2.device_pointer; storage.XtWX.alloc_to_device(storage.w*storage.h*XTWX_SIZE, false); storage.XtWY.alloc_to_device(storage.w*storage.h*XTWY_SIZE, false); - reconstruction_state.filter_rect = make_int4(filter_area.x-rect.x, filter_area.y-rect.y, storage.w, storage.h); + reconstruction_state.filter_window = rect_from_shape(filter_area.x-rect.x, filter_area.y-rect.y, storage.w, storage.h); int tile_coordinate_offset = filter_area.y*render_buffer.stride + filter_area.x; reconstruction_state.buffer_params = make_int4(render_buffer.offset + tile_coordinate_offset, render_buffer.stride, diff --git a/intern/cycles/device/device_denoising.h b/intern/cycles/device/device_denoising.h index ec4e7933cdc..77a82d0ad04 100644 --- a/intern/cycles/device/device_denoising.h +++ b/intern/cycles/device/device_denoising.h @@ -94,7 +94,7 @@ public: device_ptr temporary_1_ptr; /* There two images are used as temporary storage. */ device_ptr temporary_2_ptr; - int4 filter_rect; + int4 filter_window; int4 buffer_params; int source_w; @@ -148,8 +148,9 @@ public: struct DenoiseBuffers { int pass_stride; int passes; - int w; + int stride; int h; + int width; device_only_memory<float> mem; DenoiseBuffers(Device *device) diff --git a/intern/cycles/device/opencl/opencl.h b/intern/cycles/device/opencl/opencl.h index c02f8ffafe6..f38c2f65c1e 100644 --- a/intern/cycles/device/opencl/opencl.h +++ b/intern/cycles/device/opencl/opencl.h @@ -353,7 +353,9 @@ public: void tex_free(device_memory& mem); size_t global_size_round_up(int group_size, int global_size); - void enqueue_kernel(cl_kernel kernel, size_t w, size_t h, size_t max_workgroup_size = -1); + void enqueue_kernel(cl_kernel kernel, size_t w, size_t h, + bool x_workgroups = false, + size_t max_workgroup_size = -1); void set_kernel_arg_mem(cl_kernel kernel, cl_uint *narg, const char *name); void set_kernel_arg_buffers(cl_kernel kernel, cl_uint *narg); diff --git a/intern/cycles/device/opencl/opencl_base.cpp b/intern/cycles/device/opencl/opencl_base.cpp index f43177247ef..fe084edc90e 100644 --- a/intern/cycles/device/opencl/opencl_base.cpp +++ b/intern/cycles/device/opencl/opencl_base.cpp @@ -560,7 +560,7 @@ size_t OpenCLDeviceBase::global_size_round_up(int group_size, int global_size) return global_size + ((r == 0)? 0: group_size - r); } -void OpenCLDeviceBase::enqueue_kernel(cl_kernel kernel, size_t w, size_t h, size_t max_workgroup_size) +void OpenCLDeviceBase::enqueue_kernel(cl_kernel kernel, size_t w, size_t h, bool x_workgroups, size_t max_workgroup_size) { size_t workgroup_size, max_work_items[3]; @@ -574,8 +574,15 @@ void OpenCLDeviceBase::enqueue_kernel(cl_kernel kernel, size_t w, size_t h, size } /* Try to divide evenly over 2 dimensions. */ - size_t sqrt_workgroup_size = max((size_t)sqrt((double)workgroup_size), 1); - size_t local_size[2] = {sqrt_workgroup_size, sqrt_workgroup_size}; + size_t local_size[2]; + if(x_workgroups) { + local_size[0] = workgroup_size; + local_size[1] = 1; + } + else { + size_t sqrt_workgroup_size = max((size_t)sqrt((double)workgroup_size), 1); + local_size[0] = local_size[1] = sqrt_workgroup_size; + } /* Some implementations have max size 1 on 2nd dimension. */ if(local_size[1] > max_work_items[1]) { @@ -731,17 +738,25 @@ bool OpenCLDeviceBase::denoising_non_local_means(device_ptr image_ptr, device_ptr out_ptr, DenoisingTask *task) { - int4 rect = task->rect; - int w = rect.z-rect.x; - int h = rect.w-rect.y; + + int stride = task->buffer.stride; + int w = task->buffer.width; + int h = task->buffer.h; int r = task->nlm_state.r; int f = task->nlm_state.f; float a = task->nlm_state.a; float k_2 = task->nlm_state.k_2; - cl_mem difference = CL_MEM_PTR(task->nlm_state.temporary_1_ptr); - cl_mem blurDifference = CL_MEM_PTR(task->nlm_state.temporary_2_ptr); - cl_mem weightAccum = CL_MEM_PTR(task->nlm_state.temporary_3_ptr); + int shift_stride = stride*h; + int num_shifts = (2*r+1)*(2*r+1); + int mem_size = sizeof(float)*shift_stride*num_shifts; + + cl_mem weightAccum = CL_MEM_PTR(task->nlm_state.temporary_3_ptr); + + cl_mem difference = clCreateBuffer(cxContext, CL_MEM_READ_WRITE, mem_size, NULL, &ciErr); + opencl_assert_err(ciErr, "clCreateBuffer denoising_non_local_means"); + cl_mem blurDifference = clCreateBuffer(cxContext, CL_MEM_READ_WRITE, mem_size, NULL, &ciErr); + opencl_assert_err(ciErr, "clCreateBuffer denoising_non_local_means"); cl_mem image_mem = CL_MEM_PTR(image_ptr); cl_mem guide_mem = CL_MEM_PTR(guide_ptr); @@ -757,31 +772,45 @@ bool OpenCLDeviceBase::denoising_non_local_means(device_ptr image_ptr, cl_kernel ckNLMUpdateOutput = denoising_program(ustring("filter_nlm_update_output")); cl_kernel ckNLMNormalize = denoising_program(ustring("filter_nlm_normalize")); - for(int i = 0; i < (2*r+1)*(2*r+1); i++) { - int dy = i / (2*r+1) - r; - int dx = i % (2*r+1) - r; - int4 local_rect = make_int4(max(0, -dx), max(0, -dy), rect.z-rect.x - max(0, dx), rect.w-rect.y - max(0, dy)); - kernel_set_args(ckNLMCalcDifference, 0, - dx, dy, guide_mem, variance_mem, - difference, local_rect, w, 0, a, k_2); - kernel_set_args(ckNLMBlur, 0, - difference, blurDifference, local_rect, w, f); - kernel_set_args(ckNLMCalcWeight, 0, - blurDifference, difference, local_rect, w, f); - kernel_set_args(ckNLMUpdateOutput, 0, - dx, dy, blurDifference, image_mem, - out_mem, weightAccum, local_rect, w, f); - - enqueue_kernel(ckNLMCalcDifference, w, h); - enqueue_kernel(ckNLMBlur, w, h); - enqueue_kernel(ckNLMCalcWeight, w, h); - enqueue_kernel(ckNLMBlur, w, h); - enqueue_kernel(ckNLMUpdateOutput, w, h); - } + kernel_set_args(ckNLMCalcDifference, 0, + guide_mem, + variance_mem, + difference, + w, h, stride, + shift_stride, + r, 0, a, k_2); + kernel_set_args(ckNLMBlur, 0, + difference, + blurDifference, + w, h, stride, + shift_stride, + r, f); + kernel_set_args(ckNLMCalcWeight, 0, + blurDifference, + difference, + w, h, stride, + shift_stride, + r, f); + kernel_set_args(ckNLMUpdateOutput, 0, + blurDifference, + image_mem, + out_mem, + weightAccum, + w, h, stride, + shift_stride, + r, f); + + enqueue_kernel(ckNLMCalcDifference, w*h, num_shifts, true); + enqueue_kernel(ckNLMBlur, w*h, num_shifts, true); + enqueue_kernel(ckNLMCalcWeight, w*h, num_shifts, true); + enqueue_kernel(ckNLMBlur, w*h, num_shifts, true); + enqueue_kernel(ckNLMUpdateOutput, w*h, num_shifts, true); + + opencl_assert(clReleaseMemObject(difference)); + opencl_assert(clReleaseMemObject(blurDifference)); - int4 local_rect = make_int4(0, 0, w, h); kernel_set_args(ckNLMNormalize, 0, - out_mem, weightAccum, local_rect, w); + out_mem, weightAccum, w, h, stride); enqueue_kernel(ckNLMNormalize, w, h); return true; @@ -837,81 +866,63 @@ bool OpenCLDeviceBase::denoising_reconstruct(device_ptr color_ptr, cl_kernel ckNLMConstructGramian = denoising_program(ustring("filter_nlm_construct_gramian")); cl_kernel ckFinalize = denoising_program(ustring("filter_finalize")); - cl_mem difference = CL_MEM_PTR(task->reconstruction_state.temporary_1_ptr); - cl_mem blurDifference = CL_MEM_PTR(task->reconstruction_state.temporary_2_ptr); - - int r = task->radius; - int f = 4; - float a = 1.0f; - for(int i = 0; i < (2*r+1)*(2*r+1); i++) { - int dy = i / (2*r+1) - r; - int dx = i % (2*r+1) - r; - - int local_rect[4] = {max(0, -dx), max(0, -dy), - task->reconstruction_state.source_w - max(0, dx), - task->reconstruction_state.source_h - max(0, dy)}; - - kernel_set_args(ckNLMCalcDifference, 0, - dx, dy, - color_mem, - color_variance_mem, - difference, - local_rect, - task->buffer.w, - task->buffer.pass_stride, - a, task->nlm_k_2); - enqueue_kernel(ckNLMCalcDifference, - task->reconstruction_state.source_w, - task->reconstruction_state.source_h); - - kernel_set_args(ckNLMBlur, 0, - difference, - blurDifference, - local_rect, - task->buffer.w, - f); - enqueue_kernel(ckNLMBlur, - task->reconstruction_state.source_w, - task->reconstruction_state.source_h); - - kernel_set_args(ckNLMCalcWeight, 0, - blurDifference, - difference, - local_rect, - task->buffer.w, - f); - enqueue_kernel(ckNLMCalcWeight, - task->reconstruction_state.source_w, - task->reconstruction_state.source_h); - - /* Reuse previous arguments. */ - enqueue_kernel(ckNLMBlur, - task->reconstruction_state.source_w, - task->reconstruction_state.source_h); - - kernel_set_args(ckNLMConstructGramian, 0, - dx, dy, - blurDifference, - buffer_mem, - transform_mem, - rank_mem, - XtWX_mem, - XtWY_mem, - local_rect, - task->reconstruction_state.filter_rect, - task->buffer.w, - task->buffer.h, - f, - task->buffer.pass_stride); - enqueue_kernel(ckNLMConstructGramian, - task->reconstruction_state.source_w, - task->reconstruction_state.source_h, - 256); - } + int w = task->reconstruction_state.source_w; + int h = task->reconstruction_state.source_h; + int stride = task->buffer.stride; + + int shift_stride = stride*h; + int num_shifts = (2*task->radius + 1)*(2*task->radius + 1); + int mem_size = sizeof(float)*shift_stride*num_shifts; + + cl_mem difference = clCreateBuffer(cxContext, CL_MEM_READ_WRITE, mem_size, NULL, &ciErr); + opencl_assert_err(ciErr, "clCreateBuffer denoising_reconstruct"); + cl_mem blurDifference = clCreateBuffer(cxContext, CL_MEM_READ_WRITE, mem_size, NULL, &ciErr); + opencl_assert_err(ciErr, "clCreateBuffer denoising_reconstruct"); + + kernel_set_args(ckNLMCalcDifference, 0, + color_mem, + color_variance_mem, + difference, + w, h, stride, + shift_stride, + task->radius, + task->buffer.pass_stride, + 1.0f, task->nlm_k_2); + kernel_set_args(ckNLMBlur, 0, + difference, + blurDifference, + w, h, stride, + shift_stride, + task->radius, 4); + kernel_set_args(ckNLMCalcWeight, 0, + blurDifference, + difference, + w, h, stride, + shift_stride, + task->radius, 4); + kernel_set_args(ckNLMConstructGramian, 0, + blurDifference, + buffer_mem, + transform_mem, + rank_mem, + XtWX_mem, + XtWY_mem, + task->reconstruction_state.filter_window, + w, h, stride, + shift_stride, + task->radius, 4, + task->buffer.pass_stride); + + enqueue_kernel(ckNLMCalcDifference, w*h, num_shifts, true); + enqueue_kernel(ckNLMBlur, w*h, num_shifts, true); + enqueue_kernel(ckNLMCalcWeight, w*h, num_shifts, true); + enqueue_kernel(ckNLMBlur, w*h, num_shifts, true); + enqueue_kernel(ckNLMConstructGramian, w*h, num_shifts, true, 256); + + opencl_assert(clReleaseMemObject(difference)); + opencl_assert(clReleaseMemObject(blurDifference)); kernel_set_args(ckFinalize, 0, - task->buffer.w, - task->buffer.h, output_mem, rank_mem, XtWX_mem, @@ -919,9 +930,7 @@ bool OpenCLDeviceBase::denoising_reconstruct(device_ptr color_ptr, task->filter_area, task->reconstruction_state.buffer_params, task->render_buffer.samples); - enqueue_kernel(ckFinalize, - task->reconstruction_state.source_w, - task->reconstruction_state.source_h); + enqueue_kernel(ckFinalize, w, h); return true; } diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index de056ce97f0..5f10bdf2041 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -254,6 +254,7 @@ set(SRC_UTIL_HEADERS ../util/util_math_int3.h ../util/util_math_int4.h ../util/util_math_matrix.h + ../util/util_rect.h ../util/util_static_assert.h ../util/util_transform.h ../util/util_texture.h diff --git a/intern/cycles/kernel/filter/filter_nlm_cpu.h b/intern/cycles/kernel/filter/filter_nlm_cpu.h index 5e989331bc2..e2da0fd872b 100644 --- a/intern/cycles/kernel/filter/filter_nlm_cpu.h +++ b/intern/cycles/kernel/filter/filter_nlm_cpu.h @@ -21,7 +21,7 @@ ccl_device_inline void kernel_filter_nlm_calc_difference(int dx, int dy, const float *ccl_restrict variance_image, float *difference_image, int4 rect, - int w, + int stride, int channel_offset, float a, float k_2) @@ -31,15 +31,15 @@ ccl_device_inline void kernel_filter_nlm_calc_difference(int dx, int dy, float diff = 0.0f; int numChannels = channel_offset? 3 : 1; for(int c = 0; c < numChannels; c++) { - float cdiff = weight_image[c*channel_offset + y*w+x] - weight_image[c*channel_offset + (y+dy)*w+(x+dx)]; - float pvar = variance_image[c*channel_offset + y*w+x]; - float qvar = variance_image[c*channel_offset + (y+dy)*w+(x+dx)]; + float cdiff = weight_image[c*channel_offset + y*stride + x] - weight_image[c*channel_offset + (y+dy)*stride + (x+dx)]; + float pvar = variance_image[c*channel_offset + y*stride + x]; + float qvar = variance_image[c*channel_offset + (y+dy)*stride + (x+dx)]; diff += (cdiff*cdiff - a*(pvar + min(pvar, qvar))) / (1e-8f + k_2*(pvar+qvar)); } if(numChannels > 1) { diff *= 1.0f/numChannels; } - difference_image[y*w+x] = diff; + difference_image[y*stride + x] = diff; } } } @@ -47,7 +47,7 @@ ccl_device_inline void kernel_filter_nlm_calc_difference(int dx, int dy, ccl_device_inline void kernel_filter_nlm_blur(const float *ccl_restrict difference_image, float *out_image, int4 rect, - int w, + int stride, int f) { int aligned_lowx = rect.x / 4; @@ -56,17 +56,17 @@ ccl_device_inline void kernel_filter_nlm_blur(const float *ccl_restrict differen const int low = max(rect.y, y-f); const int high = min(rect.w, y+f+1); for(int x = rect.x; x < rect.z; x++) { - out_image[y*w+x] = 0.0f; + out_image[y*stride + x] = 0.0f; } for(int y1 = low; y1 < high; y1++) { - float4* out_image4 = (float4*)(out_image + y*w); - float4* difference_image4 = (float4*)(difference_image + y1*w); + float4* out_image4 = (float4*)(out_image + y*stride); + float4* difference_image4 = (float4*)(difference_image + y1*stride); for(int x = aligned_lowx; x < aligned_highx; x++) { out_image4[x] += difference_image4[x]; } } for(int x = rect.x; x < rect.z; x++) { - out_image[y*w+x] *= 1.0f/(high - low); + out_image[y*stride + x] *= 1.0f/(high - low); } } } @@ -74,12 +74,12 @@ ccl_device_inline void kernel_filter_nlm_blur(const float *ccl_restrict differen ccl_device_inline void kernel_filter_nlm_calc_weight(const float *ccl_restrict difference_image, float *out_image, int4 rect, - int w, + int stride, int f) { for(int y = rect.y; y < rect.w; y++) { for(int x = rect.x; x < rect.z; x++) { - out_image[y*w+x] = 0.0f; + out_image[y*stride + x] = 0.0f; } } for(int dx = -f; dx <= f; dx++) { @@ -87,7 +87,7 @@ ccl_device_inline void kernel_filter_nlm_calc_weight(const float *ccl_restrict d int neg_dx = min(0, dx); for(int y = rect.y; y < rect.w; y++) { for(int x = rect.x-neg_dx; x < rect.z-pos_dx; x++) { - out_image[y*w+x] += difference_image[y*w+dx+x]; + out_image[y*stride + x] += difference_image[y*stride + x+dx]; } } } @@ -95,7 +95,7 @@ ccl_device_inline void kernel_filter_nlm_calc_weight(const float *ccl_restrict d for(int x = rect.x; x < rect.z; x++) { const int low = max(rect.x, x-f); const int high = min(rect.z, x+f+1); - out_image[y*w+x] = fast_expf(-max(out_image[y*w+x] * (1.0f/(high - low)), 0.0f)); + out_image[y*stride + x] = fast_expf(-max(out_image[y*stride + x] * (1.0f/(high - low)), 0.0f)); } } } @@ -106,7 +106,7 @@ ccl_device_inline void kernel_filter_nlm_update_output(int dx, int dy, float *out_image, float *accum_image, int4 rect, - int w, + int stride, int f) { for(int y = rect.y; y < rect.w; y++) { @@ -115,11 +115,11 @@ ccl_device_inline void kernel_filter_nlm_update_output(int dx, int dy, const int high = min(rect.z, x+f+1); float sum = 0.0f; for(int x1 = low; x1 < high; x1++) { - sum += difference_image[y*w+x1]; + sum += difference_image[y*stride + x1]; } float weight = sum * (1.0f/(high - low)); - accum_image[y*w+x] += weight; - out_image[y*w+x] += weight*image[(y+dy)*w+(x+dx)]; + accum_image[y*stride + x] += weight; + out_image[y*stride + x] += weight*image[(y+dy)*stride + (x+dx)]; } } } @@ -132,31 +132,31 @@ ccl_device_inline void kernel_filter_nlm_construct_gramian(int dx, int dy, float *XtWX, float3 *XtWY, int4 rect, - int4 filter_rect, - int w, int h, int f, + int4 filter_window, + int stride, int f, int pass_stride) { + int4 clip_area = rect_clip(rect, filter_window); /* fy and fy are in filter-window-relative coordinates, while x and y are in feature-window-relative coordinates. */ - for(int fy = max(0, rect.y-filter_rect.y); fy < min(filter_rect.w, rect.w-filter_rect.y); fy++) { - int y = fy + filter_rect.y; - for(int fx = max(0, rect.x-filter_rect.x); fx < min(filter_rect.z, rect.z-filter_rect.x); fx++) { - int x = fx + filter_rect.x; + for(int y = clip_area.y; y < clip_area.w; y++) { + for(int x = clip_area.x; x < clip_area.z; x++) { const int low = max(rect.x, x-f); const int high = min(rect.z, x+f+1); float sum = 0.0f; for(int x1 = low; x1 < high; x1++) { - sum += difference_image[y*w+x1]; + sum += difference_image[y*stride + x1]; } float weight = sum * (1.0f/(high - low)); - int storage_ofs = fy*filter_rect.z + fx; + int storage_ofs = coord_to_local_index(filter_window, x, y); float *l_transform = transform + storage_ofs*TRANSFORM_SIZE; float *l_XtWX = XtWX + storage_ofs*XTWX_SIZE; float3 *l_XtWY = XtWY + storage_ofs*XTWY_SIZE; int *l_rank = rank + storage_ofs; kernel_filter_construct_gramian(x, y, 1, - dx, dy, w, h, + dx, dy, + stride, pass_stride, buffer, l_transform, l_rank, diff --git a/intern/cycles/kernel/filter/filter_nlm_gpu.h b/intern/cycles/kernel/filter/filter_nlm_gpu.h index 2c5ac807051..4ca49ea6733 100644 --- a/intern/cycles/kernel/filter/filter_nlm_gpu.h +++ b/intern/cycles/kernel/filter/filter_nlm_gpu.h @@ -16,57 +16,114 @@ CCL_NAMESPACE_BEGIN +/* Determines pixel coordinates and offset for the current thread. + * Returns whether the thread should do any work. + * + * All coordinates are relative to the denoising buffer! + * + * Window is the rect that should be processed. + * co is filled with (x, y, dx, dy). + */ +ccl_device_inline bool get_nlm_coords_window(int w, int h, int r, int stride, + int4 *rect, int4 *co, int *ofs, + int4 window) +{ + /* Determine the pixel offset that this thread should apply. */ + int s = 2*r+1; + int si = ccl_global_id(1); + int sx = si % s; + int sy = si / s; + if(sy >= s) { + return false; + } + co->z = sx-r; + co->w = sy-r; + + /* Pixels still need to lie inside the denoising buffer after applying the offset, + * so determine the area for which this is the case. */ + *rect = make_int4(max(0, -co->z), max(0, -co->w), + w - max(0, co->z), h - max(0, co->w)); + + /* Find the intersection of the area that we want to process (window) and the area + * that can be processed (rect) to get the final area for this offset. */ + int4 clip_area = rect_clip(window, *rect); + + /* If the radius is larger than one of the sides of the window, + * there will be shifts for which there is no usable pixel at all. */ + if(!rect_is_valid(clip_area)) { + return false; + } + + /* Map the linear thread index to pixels inside the clip area. */ + int x, y; + if(!local_index_to_coord(clip_area, ccl_global_id(0), &x, &y)) { + return false; + } + co->x = x; + co->y = y; + + *ofs = (sy*s + sx) * stride; + + return true; +} + +ccl_device_inline bool get_nlm_coords(int w, int h, int r, int stride, + int4 *rect, int4 *co, int *ofs) +{ + return get_nlm_coords_window(w, h, r, stride, rect, co, ofs, make_int4(0, 0, w, h)); +} + ccl_device_inline void kernel_filter_nlm_calc_difference(int x, int y, int dx, int dy, const ccl_global float *ccl_restrict weight_image, const ccl_global float *ccl_restrict variance_image, ccl_global float *difference_image, - int4 rect, int w, + int4 rect, int stride, int channel_offset, float a, float k_2) { float diff = 0.0f; int numChannels = channel_offset? 3 : 1; for(int c = 0; c < numChannels; c++) { - float cdiff = weight_image[c*channel_offset + y*w+x] - weight_image[c*channel_offset + (y+dy)*w+(x+dx)]; - float pvar = variance_image[c*channel_offset + y*w+x]; - float qvar = variance_image[c*channel_offset + (y+dy)*w+(x+dx)]; + float cdiff = weight_image[c*channel_offset + y*stride + x] - weight_image[c*channel_offset + (y+dy)*stride + (x+dx)]; + float pvar = variance_image[c*channel_offset + y*stride + x]; + float qvar = variance_image[c*channel_offset + (y+dy)*stride + (x+dx)]; diff += (cdiff*cdiff - a*(pvar + min(pvar, qvar))) / (1e-8f + k_2*(pvar+qvar)); } if(numChannels > 1) { diff *= 1.0f/numChannels; } - difference_image[y*w+x] = diff; + difference_image[y*stride + x] = diff; } ccl_device_inline void kernel_filter_nlm_blur(int x, int y, const ccl_global float *ccl_restrict difference_image, ccl_global float *out_image, - int4 rect, int w, int f) + int4 rect, int stride, int f) { float sum = 0.0f; const int low = max(rect.y, y-f); const int high = min(rect.w, y+f+1); for(int y1 = low; y1 < high; y1++) { - sum += difference_image[y1*w+x]; + sum += difference_image[y1*stride + x]; } sum *= 1.0f/(high-low); - out_image[y*w+x] = sum; + out_image[y*stride + x] = sum; } ccl_device_inline void kernel_filter_nlm_calc_weight(int x, int y, const ccl_global float *ccl_restrict difference_image, ccl_global float *out_image, - int4 rect, int w, int f) + int4 rect, int stride, int f) { float sum = 0.0f; const int low = max(rect.x, x-f); const int high = min(rect.z, x+f+1); for(int x1 = low; x1 < high; x1++) { - sum += difference_image[y*w+x1]; + sum += difference_image[y*stride + x1]; } sum *= 1.0f/(high-low); - out_image[y*w+x] = fast_expf(-max(sum, 0.0f)); + out_image[y*stride + x] = fast_expf(-max(sum, 0.0f)); } ccl_device_inline void kernel_filter_nlm_update_output(int x, int y, @@ -75,25 +132,25 @@ ccl_device_inline void kernel_filter_nlm_update_output(int x, int y, const ccl_global float *ccl_restrict image, ccl_global float *out_image, ccl_global float *accum_image, - int4 rect, int w, int f) + int4 rect, int stride, int f) { float sum = 0.0f; const int low = max(rect.x, x-f); const int high = min(rect.z, x+f+1); for(int x1 = low; x1 < high; x1++) { - sum += difference_image[y*w+x1]; + sum += difference_image[y*stride + x1]; } sum *= 1.0f/(high-low); if(out_image) { - accum_image[y*w+x] += sum; - out_image[y*w+x] += sum*image[(y+dy)*w+(x+dx)]; + atomic_add_and_fetch_float(accum_image + y*stride + x, sum); + atomic_add_and_fetch_float(out_image + y*stride + x, sum*image[(y+dy)*stride + (x+dx)]); } else { - accum_image[y*w+x] = sum; + accum_image[y*stride + x] = sum; } } -ccl_device_inline void kernel_filter_nlm_construct_gramian(int fx, int fy, +ccl_device_inline void kernel_filter_nlm_construct_gramian(int x, int y, int dx, int dy, const ccl_global float *ccl_restrict difference_image, const ccl_global float *ccl_restrict buffer, @@ -102,30 +159,31 @@ ccl_device_inline void kernel_filter_nlm_construct_gramian(int fx, int fy, ccl_global float *XtWX, ccl_global float3 *XtWY, int4 rect, - int4 filter_rect, - int w, int h, int f, + int4 filter_window, + int stride, int f, int pass_stride, int localIdx) { - int y = fy + filter_rect.y; - int x = fx + filter_rect.x; const int low = max(rect.x, x-f); const int high = min(rect.z, x+f+1); float sum = 0.0f; for(int x1 = low; x1 < high; x1++) { - sum += difference_image[y*w+x1]; + sum += difference_image[y*stride + x1]; } float weight = sum * (1.0f/(high - low)); - int storage_ofs = fy*filter_rect.z + fx; + /* Reconstruction data is only stored for pixels inside the filter window, + * so compute the pixels's index in there. */ + int storage_ofs = coord_to_local_index(filter_window, x, y); transform += storage_ofs; rank += storage_ofs; XtWX += storage_ofs; XtWY += storage_ofs; kernel_filter_construct_gramian(x, y, - filter_rect.z*filter_rect.w, - dx, dy, w, h, + rect_size(filter_window), + dx, dy, + stride, pass_stride, buffer, transform, rank, @@ -136,9 +194,9 @@ ccl_device_inline void kernel_filter_nlm_construct_gramian(int fx, int fy, ccl_device_inline void kernel_filter_nlm_normalize(int x, int y, ccl_global float *out_image, const ccl_global float *ccl_restrict accum_image, - int4 rect, int w) + int stride) { - out_image[y*w+x] /= accum_image[y*w+x]; + out_image[y*stride + x] /= accum_image[y*stride + x]; } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/filter/filter_reconstruction.h b/intern/cycles/kernel/filter/filter_reconstruction.h index 25a3025056c..b7bf322f9ce 100644 --- a/intern/cycles/kernel/filter/filter_reconstruction.h +++ b/intern/cycles/kernel/filter/filter_reconstruction.h @@ -19,7 +19,7 @@ CCL_NAMESPACE_BEGIN ccl_device_inline void kernel_filter_construct_gramian(int x, int y, int storage_stride, int dx, int dy, - int w, int h, + int buffer_stride, int pass_stride, const ccl_global float *ccl_restrict buffer, const ccl_global float *ccl_restrict transform, @@ -33,8 +33,8 @@ ccl_device_inline void kernel_filter_construct_gramian(int x, int y, return; } - int p_offset = y *w + x; - int q_offset = (y+dy)*w + (x+dx); + int p_offset = y * buffer_stride + x; + int q_offset = (y+dy) * buffer_stride + (x+dx); #ifdef __KERNEL_GPU__ const int stride = storage_stride; @@ -65,7 +65,7 @@ ccl_device_inline void kernel_filter_construct_gramian(int x, int y, math_vec3_add_strided(XtWY, (*rank)+1, design_row, weight * q_color, stride); } -ccl_device_inline void kernel_filter_finalize(int x, int y, int w, int h, +ccl_device_inline void kernel_filter_finalize(int x, int y, ccl_global float *buffer, ccl_global int *rank, int storage_stride, diff --git a/intern/cycles/kernel/kernels/cpu/filter_cpu.h b/intern/cycles/kernel/kernels/cpu/filter_cpu.h index bf13ba62806..4231aba88d7 100644 --- a/intern/cycles/kernel/kernels/cpu/filter_cpu.h +++ b/intern/cycles/kernel/kernels/cpu/filter_cpu.h @@ -74,7 +74,7 @@ void KERNEL_FUNCTION_FULL_NAME(filter_nlm_calc_difference)(int dx, float *variance, float *difference_image, int* rect, - int w, + int stride, int channel_offset, float a, float k_2); @@ -82,13 +82,13 @@ void KERNEL_FUNCTION_FULL_NAME(filter_nlm_calc_difference)(int dx, void KERNEL_FUNCTION_FULL_NAME(filter_nlm_blur)(float *difference_image, float *out_image, int* rect, - int w, + int stride, int f); void KERNEL_FUNCTION_FULL_NAME(filter_nlm_calc_weight)(float *difference_image, float *out_image, int* rect, - int w, + int stride, int f); void KERNEL_FUNCTION_FULL_NAME(filter_nlm_update_output)(int dx, @@ -98,7 +98,7 @@ void KERNEL_FUNCTION_FULL_NAME(filter_nlm_update_output)(int dx, float *out_image, float *accum_image, int* rect, - int w, + int stride, int f); void KERNEL_FUNCTION_FULL_NAME(filter_nlm_construct_gramian)(int dx, @@ -110,22 +110,19 @@ void KERNEL_FUNCTION_FULL_NAME(filter_nlm_construct_gramian)(int dx, float *XtWX, float3 *XtWY, int *rect, - int *filter_rect, - int w, - int h, + int *filter_window, + int stride, int f, int pass_stride); void KERNEL_FUNCTION_FULL_NAME(filter_nlm_normalize)(float *out_image, float *accum_image, int* rect, - int w); + int stride); void KERNEL_FUNCTION_FULL_NAME(filter_finalize)(int x, int y, int storage_ofs, - int w, - int h, float *buffer, int *rank, float *XtWX, diff --git a/intern/cycles/kernel/kernels/cpu/filter_cpu_impl.h b/intern/cycles/kernel/kernels/cpu/filter_cpu_impl.h index 2fbb0ea2bdb..ab39260784b 100644 --- a/intern/cycles/kernel/kernels/cpu/filter_cpu_impl.h +++ b/intern/cycles/kernel/kernels/cpu/filter_cpu_impl.h @@ -150,7 +150,7 @@ void KERNEL_FUNCTION_FULL_NAME(filter_nlm_calc_difference)(int dx, float *variance, float *difference_image, int *rect, - int w, + int stride, int channel_offset, float a, float k_2) @@ -158,33 +158,33 @@ void KERNEL_FUNCTION_FULL_NAME(filter_nlm_calc_difference)(int dx, #ifdef KERNEL_STUB STUB_ASSERT(KERNEL_ARCH, filter_nlm_calc_difference); #else - kernel_filter_nlm_calc_difference(dx, dy, weight_image, variance, difference_image, load_int4(rect), w, channel_offset, a, k_2); + kernel_filter_nlm_calc_difference(dx, dy, weight_image, variance, difference_image, load_int4(rect), stride, channel_offset, a, k_2); #endif } void KERNEL_FUNCTION_FULL_NAME(filter_nlm_blur)(float *difference_image, float *out_image, int *rect, - int w, + int stride, int f) { #ifdef KERNEL_STUB STUB_ASSERT(KERNEL_ARCH, filter_nlm_blur); #else - kernel_filter_nlm_blur(difference_image, out_image, load_int4(rect), w, f); + kernel_filter_nlm_blur(difference_image, out_image, load_int4(rect), stride, f); #endif } void KERNEL_FUNCTION_FULL_NAME(filter_nlm_calc_weight)(float *difference_image, float *out_image, int *rect, - int w, + int stride, int f) { #ifdef KERNEL_STUB STUB_ASSERT(KERNEL_ARCH, filter_nlm_calc_weight); #else - kernel_filter_nlm_calc_weight(difference_image, out_image, load_int4(rect), w, f); + kernel_filter_nlm_calc_weight(difference_image, out_image, load_int4(rect), stride, f); #endif } @@ -195,13 +195,13 @@ void KERNEL_FUNCTION_FULL_NAME(filter_nlm_update_output)(int dx, float *out_image, float *accum_image, int *rect, - int w, + int stride, int f) { #ifdef KERNEL_STUB STUB_ASSERT(KERNEL_ARCH, filter_nlm_update_output); #else - kernel_filter_nlm_update_output(dx, dy, difference_image, image, out_image, accum_image, load_int4(rect), w, f); + kernel_filter_nlm_update_output(dx, dy, difference_image, image, out_image, accum_image, load_int4(rect), stride, f); #endif } @@ -214,36 +214,33 @@ void KERNEL_FUNCTION_FULL_NAME(filter_nlm_construct_gramian)(int dx, float *XtWX, float3 *XtWY, int *rect, - int *filter_rect, - int w, - int h, + int *filter_window, + int stride, int f, int pass_stride) { #ifdef KERNEL_STUB STUB_ASSERT(KERNEL_ARCH, filter_nlm_construct_gramian); #else - kernel_filter_nlm_construct_gramian(dx, dy, difference_image, buffer, transform, rank, XtWX, XtWY, load_int4(rect), load_int4(filter_rect), w, h, f, pass_stride); + kernel_filter_nlm_construct_gramian(dx, dy, difference_image, buffer, transform, rank, XtWX, XtWY, load_int4(rect), load_int4(filter_window), stride, f, pass_stride); #endif } void KERNEL_FUNCTION_FULL_NAME(filter_nlm_normalize)(float *out_image, float *accum_image, int *rect, - int w) + int stride) { #ifdef KERNEL_STUB STUB_ASSERT(KERNEL_ARCH, filter_nlm_normalize); #else - kernel_filter_nlm_normalize(out_image, accum_image, load_int4(rect), w); + kernel_filter_nlm_normalize(out_image, accum_image, load_int4(rect), stride); #endif } void KERNEL_FUNCTION_FULL_NAME(filter_finalize)(int x, int y, int storage_ofs, - int w, - int h, float *buffer, int *rank, float *XtWX, @@ -257,7 +254,7 @@ void KERNEL_FUNCTION_FULL_NAME(filter_finalize)(int x, XtWX += storage_ofs*XTWX_SIZE; XtWY += storage_ofs*XTWY_SIZE; rank += storage_ofs; - kernel_filter_finalize(x, y, w, h, buffer, rank, 1, XtWX, XtWY, load_int4(buffer_params), sample); + kernel_filter_finalize(x, y, buffer, rank, 1, XtWX, XtWY, load_int4(buffer_params), sample); #endif } diff --git a/intern/cycles/kernel/kernels/cuda/filter.cu b/intern/cycles/kernel/kernels/cuda/filter.cu index c8172355a7f..035f0484488 100644 --- a/intern/cycles/kernel/kernels/cuda/filter.cu +++ b/intern/cycles/kernel/kernels/cuda/filter.cu @@ -134,95 +134,140 @@ kernel_cuda_filter_construct_transform(float const* __restrict__ buffer, extern "C" __global__ void CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS) -kernel_cuda_filter_nlm_calc_difference(int dx, int dy, - const float *ccl_restrict weight_image, +kernel_cuda_filter_nlm_calc_difference(const float *ccl_restrict weight_image, const float *ccl_restrict variance_image, float *difference_image, - int4 rect, int w, + int w, + int h, + int stride, + int shift_stride, + int r, int channel_offset, - float a, float k_2) + float a, + float k_2) { - int x = blockDim.x*blockIdx.x + threadIdx.x + rect.x; - int y = blockDim.y*blockIdx.y + threadIdx.y + rect.y; - if(x < rect.z && y < rect.w) { - kernel_filter_nlm_calc_difference(x, y, dx, dy, weight_image, variance_image, difference_image, rect, w, channel_offset, a, k_2); + int4 co, rect; + int ofs; + if(get_nlm_coords(w, h, r, shift_stride, &rect, &co, &ofs)) { + kernel_filter_nlm_calc_difference(co.x, co.y, co.z, co.w, + weight_image, + variance_image, + difference_image + ofs, + rect, stride, + channel_offset, a, k_2); } } extern "C" __global__ void CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS) -kernel_cuda_filter_nlm_blur(const float *ccl_restrict difference_image, float *out_image, int4 rect, int w, int f) +kernel_cuda_filter_nlm_blur(const float *ccl_restrict difference_image, + float *out_image, + int w, + int h, + int stride, + int shift_stride, + int r, + int f) { - int x = blockDim.x*blockIdx.x + threadIdx.x + rect.x; - int y = blockDim.y*blockIdx.y + threadIdx.y + rect.y; - if(x < rect.z && y < rect.w) { - kernel_filter_nlm_blur(x, y, difference_image, out_image, rect, w, f); + int4 co, rect; + int ofs; + if(get_nlm_coords(w, h, r, shift_stride, &rect, &co, &ofs)) { + kernel_filter_nlm_blur(co.x, co.y, + difference_image + ofs, + out_image + ofs, + rect, stride, f); } } extern "C" __global__ void CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS) -kernel_cuda_filter_nlm_calc_weight(const float *ccl_restrict difference_image, float *out_image, int4 rect, int w, int f) +kernel_cuda_filter_nlm_calc_weight(const float *ccl_restrict difference_image, + float *out_image, + int w, + int h, + int stride, + int shift_stride, + int r, + int f) { - int x = blockDim.x*blockIdx.x + threadIdx.x + rect.x; - int y = blockDim.y*blockIdx.y + threadIdx.y + rect.y; - if(x < rect.z && y < rect.w) { - kernel_filter_nlm_calc_weight(x, y, difference_image, out_image, rect, w, f); + int4 co, rect; + int ofs; + if(get_nlm_coords(w, h, r, shift_stride, &rect, &co, &ofs)) { + kernel_filter_nlm_calc_weight(co.x, co.y, + difference_image + ofs, + out_image + ofs, + rect, stride, f); } } extern "C" __global__ void CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS) -kernel_cuda_filter_nlm_update_output(int dx, int dy, - const float *ccl_restrict difference_image, +kernel_cuda_filter_nlm_update_output(const float *ccl_restrict difference_image, const float *ccl_restrict image, - float *out_image, float *accum_image, - int4 rect, int w, + float *out_image, + float *accum_image, + int w, + int h, + int stride, + int shift_stride, + int r, int f) { - int x = blockDim.x*blockIdx.x + threadIdx.x + rect.x; - int y = blockDim.y*blockIdx.y + threadIdx.y + rect.y; - if(x < rect.z && y < rect.w) { - kernel_filter_nlm_update_output(x, y, dx, dy, difference_image, image, out_image, accum_image, rect, w, f); + int4 co, rect; + int ofs; + if(get_nlm_coords(w, h, r, shift_stride, &rect, &co, &ofs)) { + kernel_filter_nlm_update_output(co.x, co.y, co.z, co.w, + difference_image + ofs, + image, + out_image, + accum_image, + rect, stride, f); } } extern "C" __global__ void CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS) -kernel_cuda_filter_nlm_normalize(float *out_image, const float *ccl_restrict accum_image, int4 rect, int w) +kernel_cuda_filter_nlm_normalize(float *out_image, + const float *ccl_restrict accum_image, + int w, + int h, + int stride) { - int x = blockDim.x*blockIdx.x + threadIdx.x + rect.x; - int y = blockDim.y*blockIdx.y + threadIdx.y + rect.y; - if(x < rect.z && y < rect.w) { - kernel_filter_nlm_normalize(x, y, out_image, accum_image, rect, w); + int x = blockDim.x*blockIdx.x + threadIdx.x; + int y = blockDim.y*blockIdx.y + threadIdx.y; + if(x < w && y < h) { + kernel_filter_nlm_normalize(x, y, out_image, accum_image, stride); } } extern "C" __global__ void CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS) -kernel_cuda_filter_nlm_construct_gramian(int dx, int dy, - const float *ccl_restrict difference_image, +kernel_cuda_filter_nlm_construct_gramian(const float *ccl_restrict difference_image, const float *ccl_restrict buffer, float const* __restrict__ transform, int *rank, float *XtWX, float3 *XtWY, - int4 rect, - int4 filter_rect, - int w, int h, int f, + int4 filter_window, + int w, + int h, + int stride, + int shift_stride, + int r, + int f, int pass_stride) { - int x = blockDim.x*blockIdx.x + threadIdx.x + max(0, rect.x-filter_rect.x); - int y = blockDim.y*blockIdx.y + threadIdx.y + max(0, rect.y-filter_rect.y); - if(x < min(filter_rect.z, rect.z-filter_rect.x) && y < min(filter_rect.w, rect.w-filter_rect.y)) { - kernel_filter_nlm_construct_gramian(x, y, - dx, dy, - difference_image, + int4 co, rect; + int ofs; + if(get_nlm_coords_window(w, h, r, shift_stride, &rect, &co, &ofs, filter_window)) { + kernel_filter_nlm_construct_gramian(co.x, co.y, + co.z, co.w, + difference_image + ofs, buffer, transform, rank, XtWX, XtWY, - rect, filter_rect, - w, h, f, + rect, filter_window, + stride, f, pass_stride, threadIdx.y*blockDim.x + threadIdx.x); } @@ -230,10 +275,12 @@ kernel_cuda_filter_nlm_construct_gramian(int dx, int dy, extern "C" __global__ void CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS) -kernel_cuda_filter_finalize(int w, int h, - float *buffer, int *rank, - float *XtWX, float3 *XtWY, - int4 filter_area, int4 buffer_params, +kernel_cuda_filter_finalize(float *buffer, + int *rank, + float *XtWX, + float3 *XtWY, + int4 filter_area, + int4 buffer_params, int sample) { int x = blockDim.x*blockIdx.x + threadIdx.x; @@ -243,7 +290,10 @@ kernel_cuda_filter_finalize(int w, int h, rank += storage_ofs; XtWX += storage_ofs; XtWY += storage_ofs; - kernel_filter_finalize(x, y, w, h, buffer, rank, filter_area.z*filter_area.w, XtWX, XtWY, buffer_params, sample); + kernel_filter_finalize(x, y, buffer, rank, + filter_area.z*filter_area.w, + XtWX, XtWY, + buffer_params, sample); } } diff --git a/intern/cycles/kernel/kernels/opencl/filter.cl b/intern/cycles/kernel/kernels/opencl/filter.cl index 7a7b596a350..2b77807c38b 100644 --- a/intern/cycles/kernel/kernels/opencl/filter.cl +++ b/intern/cycles/kernel/kernels/opencl/filter.cl @@ -126,113 +126,136 @@ __kernel void kernel_ocl_filter_construct_transform(const ccl_global float *ccl_ } } -__kernel void kernel_ocl_filter_nlm_calc_difference(int dx, - int dy, - const ccl_global float *ccl_restrict weight_image, +__kernel void kernel_ocl_filter_nlm_calc_difference(const ccl_global float *ccl_restrict weight_image, const ccl_global float *ccl_restrict variance_image, ccl_global float *difference_image, - int4 rect, int w, + int h, + int stride, + int shift_stride, + int r, int channel_offset, float a, float k_2) { - int x = get_global_id(0) + rect.x; - int y = get_global_id(1) + rect.y; - if(x < rect.z && y < rect.w) { - kernel_filter_nlm_calc_difference(x, y, dx, dy, weight_image, variance_image, difference_image, rect, w, channel_offset, a, k_2); + int4 co, rect; + int ofs; + if(get_nlm_coords(w, h, r, shift_stride, &rect, &co, &ofs)) { + kernel_filter_nlm_calc_difference(co.x, co.y, co.z, co.w, + weight_image, + variance_image, + difference_image + ofs, + rect, stride, + channel_offset, a, k_2); } } __kernel void kernel_ocl_filter_nlm_blur(const ccl_global float *ccl_restrict difference_image, ccl_global float *out_image, - int4 rect, int w, + int h, + int stride, + int shift_stride, + int r, int f) { - int x = get_global_id(0) + rect.x; - int y = get_global_id(1) + rect.y; - if(x < rect.z && y < rect.w) { - kernel_filter_nlm_blur(x, y, difference_image, out_image, rect, w, f); + int4 co, rect; + int ofs; + if(get_nlm_coords(w, h, r, shift_stride, &rect, &co, &ofs)) { + kernel_filter_nlm_blur(co.x, co.y, + difference_image + ofs, + out_image + ofs, + rect, stride, f); } } __kernel void kernel_ocl_filter_nlm_calc_weight(const ccl_global float *ccl_restrict difference_image, ccl_global float *out_image, - int4 rect, int w, + int h, + int stride, + int shift_stride, + int r, int f) { - int x = get_global_id(0) + rect.x; - int y = get_global_id(1) + rect.y; - if(x < rect.z && y < rect.w) { - kernel_filter_nlm_calc_weight(x, y, difference_image, out_image, rect, w, f); + int4 co, rect; + int ofs; + if(get_nlm_coords(w, h, r, shift_stride, &rect, &co, &ofs)) { + kernel_filter_nlm_calc_weight(co.x, co.y, + difference_image + ofs, + out_image + ofs, + rect, stride, f); } } -__kernel void kernel_ocl_filter_nlm_update_output(int dx, - int dy, - const ccl_global float *ccl_restrict difference_image, +__kernel void kernel_ocl_filter_nlm_update_output(const ccl_global float *ccl_restrict difference_image, const ccl_global float *ccl_restrict image, ccl_global float *out_image, ccl_global float *accum_image, - int4 rect, int w, + int h, + int stride, + int shift_stride, + int r, int f) { - int x = get_global_id(0) + rect.x; - int y = get_global_id(1) + rect.y; - if(x < rect.z && y < rect.w) { - kernel_filter_nlm_update_output(x, y, dx, dy, difference_image, image, out_image, accum_image, rect, w, f); + int4 co, rect; + int ofs; + if(get_nlm_coords(w, h, r, shift_stride, &rect, &co, &ofs)) { + kernel_filter_nlm_update_output(co.x, co.y, co.z, co.w, + difference_image + ofs, + image, + out_image, + accum_image, + rect, stride, f); } } __kernel void kernel_ocl_filter_nlm_normalize(ccl_global float *out_image, const ccl_global float *ccl_restrict accum_image, - int4 rect, - int w) + int w, + int h, + int stride) { - int x = get_global_id(0) + rect.x; - int y = get_global_id(1) + rect.y; - if(x < rect.z && y < rect.w) { - kernel_filter_nlm_normalize(x, y, out_image, accum_image, rect, w); + int x = get_global_id(0); + int y = get_global_id(1); + if(x < w && y < h) { + kernel_filter_nlm_normalize(x, y, out_image, accum_image, stride); } } -__kernel void kernel_ocl_filter_nlm_construct_gramian(int dx, - int dy, - const ccl_global float *ccl_restrict difference_image, +__kernel void kernel_ocl_filter_nlm_construct_gramian(const ccl_global float *ccl_restrict difference_image, const ccl_global float *ccl_restrict buffer, const ccl_global float *ccl_restrict transform, ccl_global int *rank, ccl_global float *XtWX, ccl_global float3 *XtWY, - int4 rect, - int4 filter_rect, + int4 filter_window, int w, int h, + int stride, + int shift_stride, + int r, int f, int pass_stride) { - int x = get_global_id(0) + max(0, rect.x-filter_rect.x); - int y = get_global_id(1) + max(0, rect.y-filter_rect.y); - if(x < min(filter_rect.z, rect.z-filter_rect.x) && y < min(filter_rect.w, rect.w-filter_rect.y)) { - kernel_filter_nlm_construct_gramian(x, y, - dx, dy, - difference_image, + int4 co, rect; + int ofs; + if(get_nlm_coords_window(w, h, r, shift_stride, &rect, &co, &ofs, filter_window)) { + kernel_filter_nlm_construct_gramian(co.x, co.y, + co.z, co.w, + difference_image + ofs, buffer, transform, rank, XtWX, XtWY, - rect, filter_rect, - w, h, f, + rect, filter_window, + stride, f, pass_stride, get_local_id(1)*get_local_size(0) + get_local_id(0)); } } -__kernel void kernel_ocl_filter_finalize(int w, - int h, - ccl_global float *buffer, +__kernel void kernel_ocl_filter_finalize(ccl_global float *buffer, ccl_global int *rank, ccl_global float *XtWX, ccl_global float3 *XtWY, @@ -247,7 +270,10 @@ __kernel void kernel_ocl_filter_finalize(int w, rank += storage_ofs; XtWX += storage_ofs; XtWY += storage_ofs; - kernel_filter_finalize(x, y, w, h, buffer, rank, filter_area.z*filter_area.w, XtWX, XtWY, buffer_params, sample); + kernel_filter_finalize(x, y, buffer, rank, + filter_area.z*filter_area.w, + XtWX, XtWY, + buffer_params, sample); } } diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index 7f3747a0f58..bc9def7ca41 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -68,6 +68,7 @@ set(SRC_HEADERS util_path.h util_progress.h util_queue.h + util_rect.h util_set.h util_simd.h util_sky_model.cpp diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 39ce6a93982..d0e91a2a1c9 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -320,6 +320,8 @@ CCL_NAMESPACE_END #include "util/util_math_float3.h" #include "util/util_math_float4.h" +#include "util/util_rect.h" + CCL_NAMESPACE_BEGIN #ifndef __KERNEL_OPENCL__ diff --git a/intern/cycles/util/util_math_intersect.h b/intern/cycles/util/util_math_intersect.h index 2b65a0dfa48..498c21b9706 100644 --- a/intern/cycles/util/util_math_intersect.h +++ b/intern/cycles/util/util_math_intersect.h @@ -117,38 +117,44 @@ bool ray_triangle_intersect( const float3 e2 = v1 - v2; /* Perform edge tests. */ -#ifdef __KERNEL_SSE2__ +#if defined(__KERNEL_SSE2__) && defined (__KERNEL_SSE__) const float3 crossU = cross(v2 + v0, e0); const float3 crossV = cross(v0 + v1, e1); const float3 crossW = cross(v1 + v2, e2); -# ifndef __KERNEL_SSE__ - const ssef crossX(crossU.x, crossV.x, crossW.x, crossW.x); - const ssef crossY(crossU.y, crossV.y, crossW.y, crossW.y); - const ssef crossZ(crossU.z, crossV.z, crossW.z, crossW.z); -# else + ssef crossX(crossU); ssef crossY(crossV); ssef crossZ(crossW); ssef zero = _mm_setzero_ps(); _MM_TRANSPOSE4_PS(crossX, crossY, crossZ, zero); -# endif + const ssef dirX(ray_dir.x); const ssef dirY(ray_dir.y); const ssef dirZ(ray_dir.z); - /*const*/ ssef UVWW = crossX*dirX + crossY*dirY + crossZ*dirZ; - const float minUVW = reduce_min(UVWW); - const float maxUVW = reduce_max(UVWW); + + ssef UVWW = madd(crossX, dirX, madd(crossY, dirY, crossZ * dirZ)); #else /* __KERNEL_SSE2__ */ const float U = dot(cross(v2 + v0, e0), ray_dir); const float V = dot(cross(v0 + v1, e1), ray_dir); const float W = dot(cross(v1 + v2, e2), ray_dir); +#endif /* __KERNEL_SSE2__ */ + +#if defined(__KERNEL_SSE2__) && defined (__KERNEL_SSE__) + int uvw_sign = movemask(UVWW) & 0x7; + if (uvw_sign != 0) + { + if (uvw_sign != 0x7) + return false; + } +#else const float minUVW = min(U, min(V, W)); const float maxUVW = max(U, max(V, W)); -#endif /* __KERNEL_SSE2__ */ if(minUVW < 0.0f && maxUVW > 0.0f) { return false; } +#endif + /* Calculate geometry normal and denominator. */ const float3 Ng1 = cross(e1, e0); @@ -171,7 +177,7 @@ bool ray_triangle_intersect( } const float inv_den = 1.0f / den; -#ifdef __KERNEL_SSE2__ +#if defined(__KERNEL_SSE2__) && defined (__KERNEL_SSE__) UVWW *= inv_den; _mm_store_ss(isect_u, UVWW); _mm_store_ss(isect_v, shuffle<1,1,3,3>(UVWW)); diff --git a/intern/cycles/util/util_math_matrix.h b/intern/cycles/util/util_math_matrix.h index b31dbe4fc67..382dad64ea5 100644 --- a/intern/cycles/util/util_math_matrix.h +++ b/intern/cycles/util/util_math_matrix.h @@ -98,7 +98,10 @@ ccl_device_inline void math_vec3_add(float3 *v, int n, float *x, float3 w) ccl_device_inline void math_vec3_add_strided(ccl_global float3 *v, int n, float *x, float3 w, int stride) { for(int i = 0; i < n; i++) { - v[i*stride] += w*x[i]; + ccl_global float *elem = (ccl_global float*) (v + i*stride); + atomic_add_and_fetch_float(elem+0, w.x*x[i]); + atomic_add_and_fetch_float(elem+1, w.y*x[i]); + atomic_add_and_fetch_float(elem+2, w.z*x[i]); } } @@ -136,7 +139,7 @@ ccl_device_inline void math_trimatrix_add_gramian_strided(ccl_global float *A, { for(int row = 0; row < n; row++) { for(int col = 0; col <= row; col++) { - MATHS(A, row, col, stride) += v[row]*v[col]*weight; + atomic_add_and_fetch_float(&MATHS(A, row, col, stride), v[row]*v[col]*weight); } } } diff --git a/intern/cycles/util/util_rect.h b/intern/cycles/util/util_rect.h new file mode 100644 index 00000000000..17a55a14d0b --- /dev/null +++ b/intern/cycles/util/util_rect.h @@ -0,0 +1,73 @@ +/* + * Copyright 2017 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UTIL_RECT_H__ +#define __UTIL_RECT_H__ + +#include "util/util_types.h" + +CCL_NAMESPACE_BEGIN + +/* Rectangles are represented as a int4 containing the coordinates of the lower-left and + * upper-right corners in the order (x0, y0, x1, y1). */ + +ccl_device_inline int4 rect_from_shape(int x0, int y0, int w, int h) +{ + return make_int4(x0, y0, x0 + w, y0 + h); +} + +ccl_device_inline int4 rect_expand(int4 rect, int d) +{ + return make_int4(rect.x - d, rect.y - d, rect.z + d, rect.w + d); +} + +/* Returns the intersection of two rects. */ +ccl_device_inline int4 rect_clip(int4 a, int4 b) +{ + return make_int4(max(a.x, b.x), max(a.y, b.y), min(a.z, b.z), min(a.w, b.w)); +} + +ccl_device_inline bool rect_is_valid(int4 rect) +{ + return (rect.z > rect.x) && (rect.w > rect.y); +} + +/* Returns the local row-major index of the pixel inside the rect. */ +ccl_device_inline int coord_to_local_index(int4 rect, int x, int y) +{ + int w = rect.z - rect.x; + return (y - rect.y) * w + (x - rect.x); +} + +/* Finds the coordinates of a pixel given by its row-major index in the rect, + * and returns whether the pixel is inside it. */ +ccl_device_inline bool local_index_to_coord(int4 rect, int idx, int *x, int *y) +{ + int w = rect.z - rect.x; + *x = (idx % w) + rect.x; + *y = (idx / w) + rect.y; + return (*y < rect.w); +} + +ccl_device_inline int rect_size(int4 rect) +{ + return (rect.z - rect.x) * (rect.w - rect.y); +} + +CCL_NAMESPACE_END + +#endif /* __UTIL_RECT_H__ */ + diff --git a/intern/guardedalloc/intern/mallocn_intern.h b/intern/guardedalloc/intern/mallocn_intern.h index a292a2eb5a0..9a5848c50ad 100644 --- a/intern/guardedalloc/intern/mallocn_intern.h +++ b/intern/guardedalloc/intern/mallocn_intern.h @@ -63,6 +63,9 @@ #elif defined(WIN32) # include <malloc.h> # define malloc_usable_size _msize +#elif defined(__HAIKU__) +# include <malloc.h> +size_t malloc_usable_size(void *ptr); #else # pragma message "We don't know how to use malloc_usable_size on your platform" # undef USE_MALLOC_USABLE_SIZE diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h index 1a23d653676..6312b4eb1a6 100644 --- a/intern/libmv/libmv/numeric/numeric.h +++ b/intern/libmv/libmv/numeric/numeric.h @@ -35,7 +35,8 @@ #if !defined(__MINGW64__) # if defined(_WIN32) || defined(__APPLE__) || \ - defined(__FreeBSD__) || defined(__NetBSD__) + defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__HAIKU__) inline void sincos(double x, double *sinx, double *cosx) { *sinx = sin(x); *cosx = cos(x); diff --git a/release/scripts/modules/bl_i18n_utils/merge_po.py b/release/scripts/modules/bl_i18n_utils/merge_po.py index 2fda42199bb..ecb26123999 100755 --- a/release/scripts/modules/bl_i18n_utils/merge_po.py +++ b/release/scripts/modules/bl_i18n_utils/merge_po.py @@ -35,9 +35,9 @@ if __package__ is None: import utils else: from . import ( - settings, - utils, - ) + settings, + utils, + ) # XXX This is a quick hack to make it work with new I18n... objects! To be reworked! diff --git a/release/scripts/modules/bl_previews_utils/bl_previews_render.py b/release/scripts/modules/bl_previews_utils/bl_previews_render.py index 71208ef3485..32266e972bb 100644 --- a/release/scripts/modules/bl_previews_utils/bl_previews_render.py +++ b/release/scripts/modules/bl_previews_utils/bl_previews_render.py @@ -24,7 +24,11 @@ import os import bpy -from mathutils import Vector, Euler, Matrix +from mathutils import ( + Euler, + Matrix, + Vector, +) INTERN_PREVIEW_TYPES = {'MATERIAL', 'LAMP', 'WORLD', 'TEXTURE', 'IMAGE'} @@ -39,7 +43,7 @@ def rna_backup_gen(data, include_props=None, exclude_props=None, root=()): # only writable properties... for p in data.bl_rna.properties: pid = p.identifier - if pid in {'rna_type', }: + if pid == "rna_type": continue path = root + (pid,) if include_props is not None and path not in include_props: diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py index 545b891505f..a80135a59e1 100644 --- a/release/scripts/modules/bpy/__init__.py +++ b/release/scripts/modules/bpy/__init__.py @@ -35,10 +35,20 @@ __all__ = ( # internal blender C module -from _bpy import types, props, app, data, context +from _bpy import ( + app, + context, + data, + msgbus, + props, + types, +) # python modules -from . import utils, path +from . import ( + path, + utils, +) # fake operator module from .ops import ops_fake_module as ops diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py index a7ecd0b80c0..8a516f12b17 100644 --- a/release/scripts/modules/bpy_extras/io_utils.py +++ b/release/scripts/modules/bpy_extras/io_utils.py @@ -36,10 +36,10 @@ __all__ = ( import bpy from bpy.props import ( - StringProperty, - BoolProperty, - EnumProperty, - ) + BoolProperty, + EnumProperty, + StringProperty, +) def _check_axis_conversion(op): diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index eb0123f12eb..04b3858bb0d 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -32,10 +32,10 @@ __all__ = ( import bpy from bpy.props import ( - BoolProperty, - BoolVectorProperty, - FloatVectorProperty, - ) + BoolProperty, + BoolVectorProperty, + FloatVectorProperty, +) def add_object_align_init(context, operator): diff --git a/release/scripts/modules/bpyml_ui.py b/release/scripts/modules/bpyml_ui.py index dd5fc38d0eb..1ba89ad098b 100644 --- a/release/scripts/modules/bpyml_ui.py +++ b/release/scripts/modules/bpyml_ui.py @@ -21,7 +21,11 @@ import bpy as _bpy import bpyml -from bpyml import TAG, ARGS, CHILDREN +from bpyml import ( + TAG, + ARGS, + CHILDREN, +) _uilayout_rna = _bpy.types.UILayout.bl_rna @@ -29,7 +33,7 @@ _uilayout_tags = ( ["ui"] + _uilayout_rna.properties.keys() + _uilayout_rna.functions.keys() - ) +) # these need to be imported directly # >>> from bpyml_ui.locals import * diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py index c7152c8a22f..144462c6b62 100644 --- a/release/scripts/startup/bl_operators/add_mesh_torus.py +++ b/release/scripts/startup/bl_operators/add_mesh_torus.py @@ -21,10 +21,10 @@ import bpy from bpy.types import Operator from bpy.props import ( - FloatProperty, - IntProperty, - BoolProperty, - ) + BoolProperty, + FloatProperty, + IntProperty, +) from bpy.app.translations import pgettext_data as data_ from bpy_extras import object_utils diff --git a/release/scripts/startup/bl_operators/console.py b/release/scripts/startup/bl_operators/console.py index fb36f80239e..0025967c97c 100644 --- a/release/scripts/startup/bl_operators/console.py +++ b/release/scripts/startup/bl_operators/console.py @@ -21,9 +21,9 @@ import bpy from bpy.types import Operator from bpy.props import ( - BoolProperty, - StringProperty, - ) + BoolProperty, + StringProperty, +) def _lang_module_get(sc): @@ -167,4 +167,4 @@ classes = ( ConsoleCopyAsScript, ConsoleExec, ConsoleLanguage, -)
\ No newline at end of file +) diff --git a/release/scripts/startup/bl_operators/file.py b/release/scripts/startup/bl_operators/file.py index d710b9af715..1b51906a032 100644 --- a/release/scripts/startup/bl_operators/file.py +++ b/release/scripts/startup/bl_operators/file.py @@ -21,10 +21,10 @@ import bpy from bpy.types import Operator from bpy.props import ( - StringProperty, - BoolProperty, - CollectionProperty, - ) + BoolProperty, + CollectionProperty, + StringProperty, +) # ########## Datablock previews... ########## @@ -252,4 +252,4 @@ class WM_OT_previews_batch_clear(Operator): classes = ( WM_OT_previews_batch_clear, WM_OT_previews_batch_generate, -)
\ No newline at end of file +) diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index b7d3866989d..a4e601dc7d1 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -1,4 +1,5 @@ # ##### BEGIN GPL LICENSE BLOCK ##### + # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -351,9 +352,9 @@ def align_objects(context, from bpy.props import ( - EnumProperty, - BoolProperty - ) + BoolProperty, + EnumProperty, +) class AlignObjects(Operator): diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index c18f50def82..ae64caca91e 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -24,9 +24,9 @@ from bpy.types import Operator from bpy.props import ( BoolProperty, EnumProperty, - IntProperty, FloatProperty, FloatVectorProperty, + IntProperty, ) diff --git a/release/scripts/startup/bl_operators/object_randomize_transform.py b/release/scripts/startup/bl_operators/object_randomize_transform.py index f856b85844e..a91e1a5b031 100644 --- a/release/scripts/startup/bl_operators/object_randomize_transform.py +++ b/release/scripts/startup/bl_operators/object_randomize_transform.py @@ -90,9 +90,11 @@ def randomize_selected(context, seed, delta, uniform(0.0, 0.0), uniform(0.0, 0.0), uniform(0.0, 0.0) -from bpy.props import (IntProperty, - BoolProperty, - FloatVectorProperty) +from bpy.props import ( + BoolProperty, + FloatVectorProperty, + IntProperty, +) class RandomizeLocRotSize(Operator): @@ -189,4 +191,4 @@ class RandomizeLocRotSize(Operator): classes = ( RandomizeLocRotSize, -)
\ No newline at end of file +) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 20586b727d5..f1f32233a42 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -21,11 +21,11 @@ import bpy from bpy.types import Operator from bpy.props import ( - StringProperty, BoolProperty, - IntProperty, - FloatProperty, EnumProperty, + FloatProperty, + IntProperty, + StringProperty, ) from bpy.app.translations import pgettext_tip as tip_ diff --git a/release/scripts/startup/bl_ui/properties_collection.py b/release/scripts/startup/bl_ui/properties_collection.py index dab9def37f4..cc6d606d27e 100644 --- a/release/scripts/startup/bl_ui/properties_collection.py +++ b/release/scripts/startup/bl_ui/properties_collection.py @@ -27,6 +27,16 @@ class CollectionButtonsPanel: bl_context = "collection" +def get_collection_from_context(context): + active_object = context.active_object + + if active_object and active_object.dupli_group and context.space_data.collection_context == 'GROUP': + group = active_object.dupli_group + return group.view_layer.collections.active + else: + return context.layer_collection + + class COLLECTION_PT_context_collection(CollectionButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} @@ -34,8 +44,14 @@ class COLLECTION_PT_context_collection(CollectionButtonsPanel, Panel): def draw(self, context): layout = self.layout space = context.space_data + active_object = context.active_object + + if active_object and active_object.dupli_group: + split = layout.split(percentage=0.2) + split.row().prop(space, "collection_context", expand=True) + layout = split - collection = context.layer_collection + collection = get_collection_from_context(context) name = collection.name if name == 'Master Collection': layout.label(text=name, icon='COLLAPSEMENU') @@ -54,7 +70,7 @@ class COLLECTION_PT_clay_settings(CollectionButtonsPanel, Panel): def draw(self, context): layout = self.layout scene_props = context.scene.collection_properties['BLENDER_CLAY'] - collection = context.layer_collection + collection = get_collection_from_context(context) collection_props = collection.engine_overrides['BLENDER_CLAY'] col = layout.column() @@ -81,7 +97,7 @@ class COLLECTION_PT_object_mode_settings(CollectionButtonsPanel, Panel): def draw(self, context): layout = self.layout scene_props = context.scene.collection_properties['ObjectMode'] - collection = context.layer_collection + collection = get_collection_from_context(context) collection_props = collection.engine_overrides['ObjectMode'] col = layout.column() @@ -100,7 +116,7 @@ class COLLECTION_PT_edit_mode_settings(CollectionButtonsPanel, Panel): def draw(self, context): layout = self.layout scene_props = context.scene.collection_properties['EditMode'] - collection = context.layer_collection + collection = get_collection_from_context(context) collection_props = collection.engine_overrides['EditMode'] col = layout.column() @@ -124,7 +140,7 @@ class COLLECTION_PT_paint_weight_mode_settings(CollectionButtonsPanel, Panel): def draw(self, context): layout = self.layout scene_props = context.scene.collection_properties['WeightPaintMode'] - collection = context.layer_collection + collection = get_collection_from_context(context) collection_props = collection.engine_overrides['WeightPaintMode'] col = layout.column() @@ -143,7 +159,7 @@ class COLLECTION_PT_paint_vertex_mode_settings(CollectionButtonsPanel, Panel): def draw(self, context): layout = self.layout scene_props = context.scene.collection_properties['VertexPaintMode'] - collection = context.layer_collection + collection = get_collection_from_context(context) collection_props = collection.engine_overrides['VertexPaintMode'] col = layout.column() diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py index e0e46e4a266..f0ef0032059 100644 --- a/release/scripts/startup/bl_ui/properties_data_bone.py +++ b/release/scripts/startup/bl_ui/properties_data_bone.py @@ -188,13 +188,13 @@ class BONE_PT_curved(BoneButtonsPanel, Panel): row = col.row() sub = row.column(align=True) sub.label(text="Scale:") - sub.prop(bbone, "bbone_scalein", text="Scale In") - sub.prop(bbone, "bbone_scaleout", text="Scale Out") + sub.prop(bbone, "bbone_scalein", text="In") + sub.prop(bbone, "bbone_scaleout", text="Out") sub = row.column(align=True) sub.label("Easing:") - sub.prop(bbone, "bbone_easein", text="Ease In") - sub.prop(bbone, "bbone_easeout", text="Ease Out") + sub.prop(bbone, "bbone_easein", text="In") + sub.prop(bbone, "bbone_easeout", text="Out") if pchan: layout.separator() diff --git a/release/scripts/startup/bl_ui/properties_data_lightprobe.py b/release/scripts/startup/bl_ui/properties_data_lightprobe.py index b1deacb3051..f839c804857 100644 --- a/release/scripts/startup/bl_ui/properties_data_lightprobe.py +++ b/release/scripts/startup/bl_ui/properties_data_lightprobe.py @@ -75,6 +75,13 @@ class DATA_PT_lightprobe(DataButtonsPanel, Panel): col.prop(probe, "influence_distance", "Distance") col.prop(probe, "falloff") + col.separator() + + col.label("Visibily:") + col.prop(probe, "visibility_buffer_bias", "Bias") + col.prop(probe, "visibility_bleed_bias", "Bleed Bias") + col.prop(probe, "visibility_blur", "Blur") + elif probe.type == 'PLANAR': col = split.column(align=True) col.label("Influence:") diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index d98e3f00e7d..9f927fe3368 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -217,7 +217,8 @@ class DATA_PT_vertex_groups(MeshButtonsPanel, Panel): col = row.column(align=True) col.operator("object.vertex_group_add", icon='ZOOMIN', text="") - col.operator("object.vertex_group_remove", icon='ZOOMOUT', text="").all = False + props = col.operator("object.vertex_group_remove", icon='ZOOMOUT', text="") + props.all_unlocked = props.all = False col.menu("MESH_MT_vertex_group_specials", icon='DOWNARROW_HLT', text="") if group: col.separator() diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py index 49ecb94248e..23787756121 100644 --- a/release/scripts/startup/bl_ui/properties_object.py +++ b/release/scripts/startup/bl_ui/properties_object.py @@ -219,13 +219,8 @@ class OBJECT_PT_groups(ObjectButtonsPanel, Panel): row.operator("object.group_remove", text="", icon='X', emboss=False) row.menu("GROUP_MT_specials", icon='DOWNARROW_HLT', text="") - split = col.box().split() - - col = split.column() - col.prop(group, "layers", text="Dupli Visibility") - - col = split.column() - col.prop(group, "dupli_offset", text="") + row = col.box().row() + row.prop(group, "dupli_offset", text="") class OBJECT_PT_display(ObjectButtonsPanel, Panel): diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 01dba8ec69b..8012043501f 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -873,6 +873,7 @@ class RENDER_PT_eevee_indirect_lighting(RenderButtonsPanel, Panel): col = layout.column() col.prop(props, "gi_diffuse_bounces") col.prop(props, "gi_cubemap_resolution") + col.prop(props, "gi_visibility_resolution") classes = ( diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py index 7f3cefb1161..c133e02fab8 100644 --- a/release/scripts/startup/bl_ui/properties_view_layer.py +++ b/release/scripts/startup/bl_ui/properties_view_layer.py @@ -448,6 +448,8 @@ class VIEWLAYER_PT_eevee_indirect_lighting(ViewLayerButtonsPanel, Panel): col = layout.column() col.template_override_property(layer_props, scene_props, "gi_diffuse_bounces") + col.template_override_property(layer_props, scene_props, "gi_cubemap_resolution") + col.template_override_property(layer_props, scene_props, "gi_visibility_resolution") classes = ( diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index 8c7fcb29ad2..f032f6a899b 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -48,15 +48,16 @@ class INFO_HT_header(Header): layout.template_ID(window, "workspace", new="workspace.workspace_add_menu", unlink="workspace.workspace_delete") layout.template_search_preview(window, "screen", workspace, "screens", new="screen.new", unlink="screen.delete", rows=2, cols=6) - if hasattr(workspace, 'object_mode'): - act_mode_item = bpy.types.Object.bl_rna.properties['mode'].enum_items[workspace.object_mode] + if hasattr(window, 'object_mode'): + act_mode_item = bpy.types.Object.bl_rna.properties['mode'].enum_items[window.object_mode] else: act_mode_item = bpy.types.Object.bl_rna.properties['mode'].enum_items[layer.objects.active.mode] layout.operator_menu_enum("object.mode_set", "mode", text=act_mode_item.name, icon=act_mode_item.icon) row = layout.row() row.active = not workspace.use_scene_settings - row.template_search(workspace, "view_layer", scene, "view_layers") + # Active workspace view-layer is retrieved through window, not through workspace. + row.template_search(window, "view_layer", scene, "view_layers") if view_render.has_multiple_engines: row.prop(view_render, "engine", text="") diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 106e6695553..94924106542 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -361,6 +361,7 @@ class SEQUENCER_MT_add_effect(Menu): layout.operator("sequencer.effect_strip_add", text="Wipe").type = 'WIPE' layout.operator("sequencer.effect_strip_add", text="Glow").type = 'GLOW' layout.operator("sequencer.effect_strip_add", text="Text").type = 'TEXT' + layout.operator("sequencer.effect_strip_add", text="Color Mix").type = 'COLORMIX' layout.operator("sequencer.effect_strip_add", text="Transform").type = 'TRANSFORM' layout.operator("sequencer.effect_strip_add", text="Color").type = 'COLOR' layout.operator("sequencer.effect_strip_add", text="Speed Control").type = 'SPEED' @@ -602,7 +603,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', 'SPEED', - 'MULTICAM', 'GAUSSIAN_BLUR', 'TEXT', + 'MULTICAM', 'GAUSSIAN_BLUR', 'TEXT', 'COLORMIX' } def draw(self, context): @@ -750,6 +751,12 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): row = col.row(align=True) row.prop(strip, "size_x") row.prop(strip, "size_y") + elif strip.type == 'COLORMIX': + split = layout.split(percentage=0.35) + split.label(text="Blend Mode:") + split.prop(strip, "blend_effect", text="") + row = layout.row(align=True) + row.prop(strip, "factor", slider=True) class SEQUENCER_PT_input(SequencerButtonsPanel, Panel): @@ -770,7 +777,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel): 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', - 'MULTICAM', 'SPEED', 'ADJUSTMENT', + 'MULTICAM', 'SPEED', 'ADJUSTMENT', 'COLORMIX' } def draw(self, context): @@ -1009,7 +1016,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel): 'META', 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', - 'MULTICAM', 'SPEED', 'ADJUSTMENT', + 'MULTICAM', 'SPEED', 'ADJUSTMENT', 'COLORMIX' } def draw(self, context): diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index a4911bbadcd..0260b2603be 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -863,6 +863,7 @@ class USERPREF_PT_theme(Panel): colsub.row().prop(ui_state, "inner_anim_sel") colsub.row().prop(ui_state, "inner_driven") colsub.row().prop(ui_state, "inner_driven_sel") + colsub.row().prop(ui_state, "blend") subsplit = row.split(percentage=0.85) @@ -871,7 +872,8 @@ class USERPREF_PT_theme(Panel): colsub = padding.column() colsub.row().prop(ui_state, "inner_key") colsub.row().prop(ui_state, "inner_key_sel") - colsub.row().prop(ui_state, "blend") + colsub.row().prop(ui_state, "inner_overridden") + colsub.row().prop(ui_state, "inner_overridden_sel") col.separator() col.separator() diff --git a/release/scripts/templates_py/operator_mesh_add.py b/release/scripts/templates_py/operator_mesh_add.py index 2590d53e49a..3231214c773 100644 --- a/release/scripts/templates_py/operator_mesh_add.py +++ b/release/scripts/templates_py/operator_mesh_add.py @@ -34,11 +34,11 @@ def add_box(width, height, depth): from bpy.props import ( - BoolProperty, - BoolVectorProperty, - FloatProperty, - FloatVectorProperty, - ) + BoolProperty, + BoolVectorProperty, + FloatProperty, + FloatVectorProperty, +) class AddBox(bpy.types.Operator): diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index 7003547ead2..5e93779b5f6 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -845,7 +845,7 @@ static void import_endjob(void *user_data) if (lc == NULL) { BLI_assert(BLI_listbase_count_ex(&view_layer->layer_collections, 1) == 0); /* when there is no collection linked to this ViewLayer, create one */ - SceneCollection *sc = BKE_collection_add(data->scene, NULL, NULL); + SceneCollection *sc = BKE_collection_add(&data->scene->id, NULL, COLLECTION_TYPE_NONE, NULL); lc = BKE_collection_link(view_layer, sc); } @@ -853,7 +853,7 @@ static void import_endjob(void *user_data) Object *ob = (*iter)->object(); ob->lay = data->scene->lay; - BKE_collection_object_add(data->scene, lc->scene_collection, ob); + BKE_collection_object_add(&data->scene->id, lc->scene_collection, ob); base = BKE_view_layer_base_find(view_layer, ob); BKE_view_layer_base_select(view_layer, base); diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 622767baa10..d95b4a838b8 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -35,6 +35,7 @@ struct ID; struct ListBase; struct Main; struct AnimData; +struct FCurve; struct KeyingSet; struct KS_Path; struct PathResolvedRNA; @@ -46,6 +47,7 @@ struct ReportList; struct bAction; struct bActionGroup; struct AnimMapper; +struct FCurve; /* ************************************* */ /* AnimData API */ @@ -152,9 +154,15 @@ char *BKE_animdata_driver_path_hack(struct bContext *C, struct PointerRNA *ptr, /* Define for callback looper used in BKE_animdata_main_cb */ typedef void (*ID_AnimData_Edit_Callback)(struct ID *id, struct AnimData *adt, void *user_data); +/* Define for callback looper used in BKE_fcurves_main_cb */ +typedef void (*ID_FCurve_Edit_Callback)(struct ID *id, struct FCurve *fcu, void *user_data); + /* Loop over all datablocks applying callback */ -void BKE_animdata_main_cb(struct Main *main, ID_AnimData_Edit_Callback func, void *user_data); +void BKE_animdata_main_cb(struct Main *bmain, ID_AnimData_Edit_Callback func, void *user_data); + +/* Loop over all datablocks applying callback to all its F-Curves */ +void BKE_fcurves_main_cb(struct Main *bmain, ID_FCurve_Edit_Callback func, void *user_data); /* ************************************* */ // TODO: overrides, remapping, and path-finding api's @@ -172,7 +180,6 @@ void BKE_animsys_evaluate_animdata(struct Scene *scene, struct ID *id, struct An void BKE_animsys_evaluate_all_animation(struct Main *main, struct Scene *scene, float ctime); /* TODO(sergey): This is mainly a temp public function. */ -struct FCurve; bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu, float curval); /* ------------ Specialized API --------------- */ diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index 52985d3ec56..48b4ff881ae 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -37,28 +37,35 @@ extern "C" { struct Base; struct BLI_Iterator; +struct Group; +struct ID; +struct LayerCollection; struct Main; struct Object; struct Scene; struct SceneCollection; -struct SceneCollection *BKE_collection_add(struct Scene *scene, struct SceneCollection *sc_parent, const char *name); -bool BKE_collection_remove(struct Scene *scene, struct SceneCollection *sc); -struct SceneCollection *BKE_collection_master(const struct Scene *scene); +struct SceneCollection *BKE_collection_add( + struct ID *owner_id, struct SceneCollection *sc_parent, const int type, const char *name); +bool BKE_collection_remove(struct ID *owner_id, struct SceneCollection *sc); +void BKE_collection_copy_data(struct SceneCollection *sc_dst, struct SceneCollection *sc_src, const int flag); +struct SceneCollection *BKE_collection_master(const struct ID *owner_id); void BKE_collection_rename(const struct Scene *scene, struct SceneCollection *sc, const char *name); -void BKE_collection_master_free(struct Scene *scene, const bool do_id_user); -void BKE_collection_object_add(const struct Scene *scene, struct SceneCollection *sc, struct Object *object); +void BKE_collection_master_free(struct ID *owner_id, const bool do_id_user); +bool BKE_collection_object_add(const struct ID *owner_id, struct SceneCollection *sc, struct Object *object); void BKE_collection_object_add_from(struct Scene *scene, struct Object *ob_src, struct Object *ob_dst); -void BKE_collection_object_remove(struct Main *bmain, const struct Scene *scene, struct SceneCollection *sc, struct Object *object, const bool free_us); -void BKE_collections_object_remove(struct Main *bmain, struct Scene *scene, struct Object *object, const bool free_us); -void BKE_collection_object_move(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src, struct Object *ob); +bool BKE_collection_object_remove(struct Main *bmain, struct ID *owner_id, struct SceneCollection *sc, struct Object *object, const bool free_us); +bool BKE_collections_object_remove(struct Main *bmain, struct ID *owner_id, struct Object *object, const bool free_us); +void BKE_collection_object_move(struct ID *owner_id, struct SceneCollection *sc_dst, struct SceneCollection *sc_src, struct Object *ob); + +struct Group *BKE_collection_group_create(struct Main *bmain, struct Scene *scene, struct LayerCollection *lc); void BKE_collection_reinsert_after(const struct Scene *scene, struct SceneCollection *sc_reinsert, struct SceneCollection *sc_after); void BKE_collection_reinsert_into(struct SceneCollection *sc_reinsert, struct SceneCollection *sc_into); -bool BKE_collection_move_above(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src); -bool BKE_collection_move_below(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src); -bool BKE_collection_move_into(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src); +bool BKE_collection_move_above(const struct ID *owner_id, struct SceneCollection *sc_dst, struct SceneCollection *sc_src); +bool BKE_collection_move_below(const struct ID *owner_id, struct SceneCollection *sc_dst, struct SceneCollection *sc_src); +bool BKE_collection_move_into(const struct ID *owner_id, struct SceneCollection *sc_dst, struct SceneCollection *sc_src); typedef void (*BKE_scene_objects_Cb)(struct Object *ob, void *data); typedef void (*BKE_scene_collections_Cb)(struct SceneCollection *ob, void *data); @@ -75,11 +82,11 @@ void BKE_scene_objects_iterator_begin(struct BLI_Iterator *iter, void *data_in); void BKE_scene_objects_iterator_next(struct BLI_Iterator *iter); void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter); -#define FOREACH_SCENE_COLLECTION(scene, _instance) \ +#define FOREACH_SCENE_COLLECTION(_id, _instance) \ ITER_BEGIN(BKE_scene_collections_iterator_begin, \ BKE_scene_collections_iterator_next, \ BKE_scene_collections_iterator_end, \ - scene, SceneCollection *, _instance) + _id, SceneCollection *, _instance) #define FOREACH_SCENE_COLLECTION_END \ ITER_END diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index a0d8bdfe60f..31d26d5d4fa 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -156,6 +156,7 @@ struct ARegion *CTX_wm_region(const bContext *C); void *CTX_wm_region_data(const bContext *C); struct ARegion *CTX_wm_menu(const bContext *C); struct wmManipulatorGroup *CTX_wm_manipulator_group(const bContext *C); +struct wmMsgBus *CTX_wm_message_bus(const bContext *C); struct ReportList *CTX_wm_reports(const bContext *C); struct View3D *CTX_wm_view3d(const bContext *C); @@ -255,7 +256,7 @@ struct LayerCollection *CTX_data_layer_collection(const bContext *C); struct SceneCollection *CTX_data_scene_collection(const bContext *C); struct ViewLayer *CTX_data_view_layer(const bContext *C); struct ViewRender *CTX_data_view_render(const bContext *C); -struct RenderEngineType *CTX_data_engine(const bContext *C); +struct RenderEngineType *CTX_data_engine_type(const bContext *C); struct ToolSettings *CTX_data_tool_settings(const bContext *C); const char *CTX_data_mode_string(const bContext *C); diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index 9aab6950496..ac436876dc4 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -41,6 +41,7 @@ struct Object; struct Scene; void BKE_group_free(struct Group *group); +void BKE_group_init(struct Group *group); struct Group *BKE_group_add(struct Main *bmain, const char *name); void BKE_group_copy_data(struct Main *bmain, struct Group *group_dst, const struct Group *group_src, const int flag); struct Group *BKE_group_copy(struct Main *bmain, const struct Group *group); @@ -52,7 +53,26 @@ bool BKE_group_object_exists(struct Group *group, struct Object *ob); bool BKE_group_object_cyclic_check(struct Main *bmain, struct Object *object, struct Group *group); bool BKE_group_is_animated(struct Group *group, struct Object *parent); -void BKE_group_tag_recalc(struct Group *group); void BKE_group_handle_recalc_and_update(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *parent, struct Group *group); +#define FOREACH_GROUP_BASE(_group, _base) \ + for (Base *_base = (Base *)(_group)->view_layer->object_bases.first; \ + _base; \ + _base = _base->next) \ + { + +#define FOREACH_GROUP_BASE_END \ + } + +#define FOREACH_GROUP_OBJECT(_group, _object) \ + for (Base *_base = (Base *)(_group)->view_layer->object_bases.first; \ + _base; \ + _base = _base->next) \ + { \ + Object *_object = _base->object; \ + BLI_assert(_object != NULL); + +#define FOREACH_GROUP_OBJECT_END \ + } + #endif /* __BKE_GROUP_H__ */ diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index ecad9c21f99..e4f8b8790f6 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -42,6 +42,7 @@ extern "C" { struct Base; struct EvaluationContext; +struct Group; struct ID; struct IDProperty; struct LayerCollection; @@ -59,6 +60,7 @@ void BKE_layer_exit(void); struct ViewLayer *BKE_view_layer_from_scene_get(const struct Scene *scene); struct ViewLayer *BKE_view_layer_from_workspace_get(const struct Scene *scene, const struct WorkSpace *workspace); struct ViewLayer *BKE_view_layer_add(struct Scene *scene, const char *name); +struct ViewLayer *BKE_view_layer_group_add(struct Group *group); /* DEPRECATED */ struct ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const struct Scene *scene); @@ -68,12 +70,17 @@ void BKE_view_layer_free(struct ViewLayer *view_layer); void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, const int tag); struct Object *BKE_view_layer_camera_find(struct ViewLayer *view_layer); -struct ViewLayer *BKE_view_layer_find_from_collection(const struct Scene *scene, struct LayerCollection *lc); +struct ViewLayer *BKE_view_layer_first_from_id(const struct ID *owner_id); +struct ViewLayer *BKE_view_layer_find_from_collection(const struct ID *owner_id, struct LayerCollection *lc); struct Base *BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob); -struct Base *BKE_view_layer_base_find_by_name(struct ViewLayer *view_layer, struct Object *ob); void BKE_view_layer_base_deselect_all(struct ViewLayer *view_layer); void BKE_view_layer_base_select(struct ViewLayer *view_layer, struct Base *selbase); +void BKE_view_layer_copy_data( + struct ViewLayer *view_layer_dst, struct ViewLayer *view_layer_src, + struct SceneCollection *mc_dst, struct SceneCollection *mc_src, + const int flag); + void BKE_layer_collection_free(struct ViewLayer *view_layer, struct LayerCollection *lc); struct LayerCollection *BKE_layer_collection_get_active(struct ViewLayer *view_layer); @@ -84,11 +91,11 @@ int BKE_layer_collection_count(struct ViewLayer *view_layer); struct LayerCollection *BKE_layer_collection_from_index(struct ViewLayer *view_layer, const int index); int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct LayerCollection *lc); -bool BKE_layer_collection_move_above(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src); -bool BKE_layer_collection_move_below(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src); -bool BKE_layer_collection_move_into(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src); +bool BKE_layer_collection_move_above(const struct ID *owner_id, struct LayerCollection *lc_dst, struct LayerCollection *lc_src); +bool BKE_layer_collection_move_below(const struct ID *owner_id, struct LayerCollection *lc_dst, struct LayerCollection *lc_src); +bool BKE_layer_collection_move_into(const struct ID *owner_id, struct LayerCollection *lc_dst, struct LayerCollection *lc_src); -void BKE_layer_collection_resync(const struct Scene *scene, const struct SceneCollection *sc); +void BKE_layer_collection_resync(const struct ID *owner_id, const struct SceneCollection *sc); struct LayerCollection *BKE_collection_link(struct ViewLayer *view_layer, struct SceneCollection *sc); @@ -102,13 +109,13 @@ bool BKE_scene_has_object(struct Scene *scene, struct Object *ob); /* syncing */ -void BKE_layer_sync_new_scene_collection(struct Scene *scene, const struct SceneCollection *sc_parent, struct SceneCollection *sc); -void BKE_layer_sync_object_link(const struct Scene *scene, struct SceneCollection *sc, struct Object *ob); -void BKE_layer_sync_object_unlink(const struct Scene *scene, struct SceneCollection *sc, struct Object *ob); +void BKE_layer_sync_new_scene_collection(struct ID *owner_id, const struct SceneCollection *sc_parent, struct SceneCollection *sc); +void BKE_layer_sync_object_link(const struct ID *owner_id, struct SceneCollection *sc, struct Object *ob); +void BKE_layer_sync_object_unlink(const struct ID *owner_id, struct SceneCollection *sc, struct Object *ob); /* override */ -void BKE_override_view_layer_datablock_add(struct ViewLayer *view_layer, int id_type, const char *data_path, const struct ID *id); +void BKE_override_view_layer_datablock_add(struct ViewLayer *view_layer, int id_type, const char *data_path, const struct ID *owner_id); void BKE_override_view_layer_int_add(struct ViewLayer *view_layer, int id_type, const char *data_path, const int value); void BKE_override_layer_collection_boolean_add(struct LayerCollection *layer_collection, int id_type, const char *data_path, const bool value); @@ -152,7 +159,7 @@ void BKE_collection_engine_property_value_set_bool(struct IDProperty *props, con /* evaluation */ void BKE_layer_eval_layer_collection_pre(const struct EvaluationContext *eval_ctx, - struct Scene *scene, + struct ID *owner_id, struct ViewLayer *view_layer); void BKE_layer_eval_layer_collection(const struct EvaluationContext *eval_ctx, struct LayerCollection *layer_collection, diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index f320597ef2d..0abf99415c7 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -77,6 +77,7 @@ enum { LIB_ID_COPY_CACHES = 1 << 18, /* Copy runtime data caches. */ /* XXX TODO Do we want to keep that? would rather try to get rid of it... */ LIB_ID_COPY_ACTIONS = 1 << 19, /* EXCEPTION! Deep-copy actions used by animdata of copied ID. */ + LIB_ID_COPY_KEEP_LIB = 1 << 20, /* Keep the library pointer when copying datablock outside of bmain. */ }; void BKE_libblock_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag); @@ -147,6 +148,7 @@ bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const boo bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop); bool id_copy(struct Main *bmain, const struct ID *id, struct ID **newid, bool test); bool BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag, const bool test); +void BKE_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b); void id_sort_by_name(struct ListBase *lb, struct ID *id); void BKE_id_expand_local(struct Main *bmain, struct ID *id); void BKE_id_copy_ensure_local(struct Main *bmain, const struct ID *old_id, struct ID *new_id); diff --git a/source/blender/blenkernel/BKE_library_override.h b/source/blender/blenkernel/BKE_library_override.h new file mode 100644 index 00000000000..1ba009660f2 --- /dev/null +++ b/source/blender/blenkernel/BKE_library_override.h @@ -0,0 +1,86 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Bastien Montagne. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_LIBRARY_OVERRIDE_H__ +#define __BKE_LIBRARY_OVERRIDE_H__ + +/** \file BKE_library_override.h + * \ingroup bke + * \since December 2016 + * \author mont29 + */ + +struct ID; +struct IDOverrideStatic; +struct IDOverrideStaticProperty; +struct IDOverrideStaticPropertyOperation; +struct Main; + +struct IDOverrideStatic *BKE_override_static_init(struct ID *local_id, struct ID *reference_id); +void BKE_override_static_copy(struct ID *dst_id, const struct ID *src_id); +void BKE_override_static_clear(struct IDOverrideStatic *override); +void BKE_override_static_free(struct IDOverrideStatic **override); + +struct ID *BKE_override_static_create_from(struct Main *bmain, struct ID *reference_id); + +struct IDOverrideStaticProperty *BKE_override_static_property_find(struct IDOverrideStatic *override, const char *rna_path); +struct IDOverrideStaticProperty *BKE_override_static_property_get(struct IDOverrideStatic *override, const char *rna_path, bool *r_created); +void BKE_override_static_property_delete(struct IDOverrideStatic *override, struct IDOverrideStaticProperty *override_property); + +struct IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find( + struct IDOverrideStaticProperty *override_property, + const char *subitem_refname, const char *subitem_locname, + const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict); +struct IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get( + struct IDOverrideStaticProperty *override_property, const short operation, + const char *subitem_refname, const char *subitem_locname, + const int subitem_refindex, const int subitem_locindex, + const bool strict, bool *r_strict, bool *r_created); +void BKE_override_static_property_operation_delete( + struct IDOverrideStaticProperty *override_property, struct IDOverrideStaticPropertyOperation *override_property_operation); + +bool BKE_override_static_status_check_local(struct ID *local); +bool BKE_override_static_status_check_reference(struct ID *local); + +bool BKE_override_static_operations_create(struct ID *local); +void BKE_main_override_static_operations_create(struct Main *bmain); + +void BKE_override_static_update(struct Main *bmain, struct ID *local); +void BKE_main_override_static_update(struct Main *bmain); + + +/* Storage (.blend file writing) part. */ + +/* For now, we just use a temp main list. */ +typedef struct Main OverrideStaticStorage; + +OverrideStaticStorage *BKE_override_static_operations_store_initialize(void); +struct ID *BKE_override_static_operations_store_start(OverrideStaticStorage *override_storage, struct ID *local); +void BKE_override_static_operations_store_end(OverrideStaticStorage *override_storage, struct ID *local); +void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage); + + + +#endif /* __BKE_LIBRARY_OVERRIDE_H__ */ diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index d6e7d98f371..b66fc0aab16 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -56,6 +56,9 @@ enum { * How to handle that kind of cases totally depends on what caller code is doing... */ IDWALK_CB_LOOPBACK = (1 << 4), + /** That ID is used as static override's reference by its owner. */ + IDWALK_CB_STATIC_OVERRIDE_REFERENCE = (1 << 5), + /** * Adjusts #ID.us reference-count. * \note keep in sync with 'newlibadr_us' use in readfile.c diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h index fd37fd762f4..3425ca011b7 100644 --- a/source/blender/blenkernel/BKE_library_remap.h +++ b/source/blender/blenkernel/BKE_library_remap.h @@ -51,6 +51,8 @@ enum { * This is needed e.g. in reload scenario, since we have to ensure remapping of Armature data of local proxy * is also performed. Usual nightmare... */ ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4, + /* Do not remap static override pointers. */ + ID_REMAP_SKIP_STATIC_OVERRIDE = 1 << 5, }; /* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */ diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 31125545670..2b183906f57 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -184,7 +184,6 @@ void BKE_object_tfm_protected_restore(struct Object *ob, /* Dependency graph evaluation callbacks. */ void BKE_object_eval_local_transform(const struct EvaluationContext *eval_ctx, - struct Scene *scene, struct Object *ob); void BKE_object_eval_parent(const struct EvaluationContext *eval_ctx, struct Scene *scene, @@ -194,8 +193,9 @@ void BKE_object_eval_constraints(const struct EvaluationContext *eval_ctx, struct Object *ob); void BKE_object_eval_done(const struct EvaluationContext *eval_ctx, struct Object *ob); +bool BKE_object_eval_proxy_copy(const struct EvaluationContext *eval_ct, + struct Object *object); void BKE_object_eval_uber_transform(const struct EvaluationContext *eval_ctx, - struct Scene *scene, struct Object *ob); void BKE_object_eval_uber_data(const struct EvaluationContext *eval_ctx, struct Scene *scene, @@ -205,6 +205,10 @@ void BKE_object_eval_cloth(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *object); +void BKE_object_eval_transform_all(const struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *object); + void BKE_object_eval_update_shading(const struct EvaluationContext *eval_ctx, struct Object *object); void BKE_object_data_select_update(const struct EvaluationContext *eval_ctx, @@ -226,6 +230,7 @@ void BKE_object_handle_update_ex( struct Scene *scene, struct Object *ob, struct RigidBodyWorld *rbw, const bool do_proxy_update); + void BKE_object_sculpt_modifiers_changed(struct Object *ob); int BKE_object_obdata_texspace_get(struct Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index fb6d8e7c75e..94d78ae47e3 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -57,6 +57,7 @@ struct wmWindow; struct wmWindowManager; struct WorkSpace; struct GPUFXSettings; +struct wmMsgBus; #include "BLI_compiler_attrs.h" @@ -140,6 +141,12 @@ typedef struct ARegionType { /* contextual changes should be handled here */ void (*listener)(struct bScreen *, struct ScrArea *, struct ARegion *, struct wmNotifier *, const struct Scene *scene); + /* Optional callback to generate subscriptions. */ + void (*message_subscribe)( + const struct bContext *C, + struct WorkSpace *workspace, struct Scene *scene, + struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus); void (*free)(struct ARegion *); diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h index f295af3150a..9f989f7ae8f 100644 --- a/source/blender/blenkernel/BKE_workspace.h +++ b/source/blender/blenkernel/BKE_workspace.h @@ -32,6 +32,7 @@ struct EvaluationContext; struct Main; struct Scene; struct TransformOrientation; +struct ViewLayer; /** * Plan is to store the object-mode per workspace, not per object anymore. @@ -62,10 +63,17 @@ void BKE_workspace_layout_remove( struct Main *bmain, struct WorkSpace *workspace, struct WorkSpaceLayout *layout) ATTR_NONNULL(); +void BKE_workspace_relations_free( + ListBase *relation_list); + /* -------------------------------------------------------------------- */ /* General Utils */ +void BKE_workspace_view_layer_remove_references( + const struct Main *bmain, + const struct ViewLayer *view_layer) ATTR_NONNULL(); + void BKE_workspace_transform_orientation_remove( struct WorkSpace *workspace, struct TransformOrientation *orientation) ATTR_NONNULL(); struct TransformOrientation *BKE_workspace_transform_orientation_find( @@ -98,14 +106,24 @@ void BKE_workspace_active_layout_set(struct WorkSpaceInstanceHook *h struct bScreen *BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS; void BKE_workspace_active_screen_set( struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace, struct bScreen *screen) SETTER_ATTRS; -enum eObjectMode BKE_workspace_object_mode_get(const struct WorkSpace *workspace) GETTER_ATTRS; #ifdef USE_WORKSPACE_MODE -void BKE_workspace_object_mode_set(struct WorkSpace *workspace, const enum eObjectMode mode) SETTER_ATTRS; +enum eObjectMode BKE_workspace_object_mode_get( + const struct WorkSpace *workspace, + const struct Scene *scene) GETTER_ATTRS; +void BKE_workspace_object_mode_set( + struct WorkSpace *workspace, + struct Scene *scene, + const enum eObjectMode mode) SETTER_ATTRS; #endif -struct Base *BKE_workspace_active_base_get(const struct WorkSpace *workspace); +struct Base *BKE_workspace_active_base_get(const struct WorkSpace *workspace, const struct Scene *scene); struct ListBase *BKE_workspace_transform_orientations_get(struct WorkSpace *workspace) GETTER_ATTRS; -struct ViewLayer *BKE_workspace_view_layer_get(const struct WorkSpace *workspace) GETTER_ATTRS; -void BKE_workspace_view_layer_set(struct WorkSpace *workspace, struct ViewLayer *layer) SETTER_ATTRS; +struct ViewLayer *BKE_workspace_view_layer_get( + const struct WorkSpace *workspace, + const struct Scene *scene) GETTER_ATTRS; +void BKE_workspace_view_layer_set( + struct WorkSpace *workspace, + struct ViewLayer *layer, + struct Scene *scene) SETTER_ATTRS; struct ListBase *BKE_workspace_layouts_get(struct WorkSpace *workspace) GETTER_ATTRS; const char *BKE_workspace_layout_name_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS; diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 24b0adb1adb..c99c3d6ffa9 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -124,6 +124,7 @@ set(SRC intern/lattice.c intern/library.c intern/library_idmap.c + intern/library_override.c intern/library_query.c intern/library_remap.c intern/linestyle.c @@ -256,6 +257,7 @@ set(SRC BKE_lattice.h BKE_library.h BKE_library_idmap.h + BKE_library_override.h BKE_library_query.h BKE_library_remap.h BKE_linestyle.h diff --git a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c index e9002af19b1..f68d1a2697c 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c @@ -27,6 +27,7 @@ #include "BLI_utildefines.h" /* for BLI_assert */ #include "BLI_math.h" +#include "BLI_task.h" #include "CCGSubSurf.h" #include "CCGSubSurf_intern.h" @@ -121,179 +122,251 @@ static float EDGE_getSharpness(CCGEdge *e, int lvl) return e->crease - lvl; } -static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss, - CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF, - int numEffectedV, int numEffectedE, int numEffectedF) + + +typedef struct CCGSubSurfCalcSubdivData { + CCGSubSurf *ss; + CCGVert **effectedV; + CCGEdge **effectedE; + CCGFace **effectedF; + int numEffectedV; + int numEffectedE; + int numEffectedF; + + int curLvl; +} CCGSubSurfCalcSubdivData; + +static void ccgSubSurf__calcVertNormals_faces_accumulate_cb(void *userdata, int ptrIdx) { - int i, ptrIdx; - int subdivLevels = ss->subdivLevels; - int lvl = ss->subdivLevels; - int edgeSize = ccg_edgesize(lvl); - int gridSize = ccg_gridsize(lvl); - int normalDataOffset = ss->normalDataOffset; - int vertDataSize = ss->meshIFC.vertDataSize; + CCGSubSurfCalcSubdivData *data = userdata; -#pragma omp parallel for private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) - for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace *) effectedF[ptrIdx]; - int S, x, y; - float no[3]; + CCGSubSurf *ss = data->ss; + CCGFace *f = data->effectedF[ptrIdx]; - for (S = 0; S < f->numVerts; S++) { - for (y = 0; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - NormZero(FACE_getIFNo(f, lvl, S, x, y)); - } - } + const int subdivLevels = ss->subdivLevels; + const int lvl = ss->subdivLevels; + const int gridSize = ccg_gridsize(lvl); + const int normalDataOffset = ss->normalDataOffset; + const int vertDataSize = ss->meshIFC.vertDataSize; - if (FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected) { - for (x = 0; x < gridSize - 1; x++) { - NormZero(FACE_getIFNo(f, lvl, S, x, gridSize - 1)); - } + int S, x, y; + float no[3]; + + for (S = 0; S < f->numVerts; S++) { + for (y = 0; y < gridSize - 1; y++) { + for (x = 0; x < gridSize - 1; x++) { + NormZero(FACE_getIFNo(f, lvl, S, x, y)); } - if (FACE_getEdges(f)[S]->flags & Edge_eEffected) { - for (y = 0; y < gridSize - 1; y++) { - NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, y)); - } + } + + if (FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected) { + for (x = 0; x < gridSize - 1; x++) { + NormZero(FACE_getIFNo(f, lvl, S, x, gridSize - 1)); } - if (FACE_getVerts(f)[S]->flags & Vert_eEffected) { - NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, gridSize - 1)); + } + if (FACE_getEdges(f)[S]->flags & Edge_eEffected) { + for (y = 0; y < gridSize - 1; y++) { + NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, y)); } } + if (FACE_getVerts(f)[S]->flags & Vert_eEffected) { + NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, gridSize - 1)); + } + } - for (S = 0; S < f->numVerts; S++) { - int yLimit = !(FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected); - int xLimit = !(FACE_getEdges(f)[S]->flags & Edge_eEffected); - int yLimitNext = xLimit; - int xLimitPrev = yLimit; - - for (y = 0; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - int xPlusOk = (!xLimit || x < gridSize - 2); - int yPlusOk = (!yLimit || y < gridSize - 2); - - FACE_calcIFNo(f, lvl, S, x, y, no); - - NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 0), no); - if (xPlusOk) - NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 0), no); - if (yPlusOk) - NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 1), no); - if (xPlusOk && yPlusOk) { - if (x < gridSize - 2 || y < gridSize - 2 || FACE_getVerts(f)[S]->flags & Vert_eEffected) { - NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 1), no); - } + for (S = 0; S < f->numVerts; S++) { + int yLimit = !(FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected); + int xLimit = !(FACE_getEdges(f)[S]->flags & Edge_eEffected); + int yLimitNext = xLimit; + int xLimitPrev = yLimit; + + for (y = 0; y < gridSize - 1; y++) { + for (x = 0; x < gridSize - 1; x++) { + int xPlusOk = (!xLimit || x < gridSize - 2); + int yPlusOk = (!yLimit || y < gridSize - 2); + + FACE_calcIFNo(f, lvl, S, x, y, no); + + NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 0), no); + if (xPlusOk) + NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 0), no); + if (yPlusOk) + NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 1), no); + if (xPlusOk && yPlusOk) { + if (x < gridSize - 2 || y < gridSize - 2 || FACE_getVerts(f)[S]->flags & Vert_eEffected) { + NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 1), no); } + } - if (x == 0 && y == 0) { - int K; + if (x == 0 && y == 0) { + int K; - if (!yLimitNext || 1 < gridSize - 1) - NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, 1), no); - if (!xLimitPrev || 1 < gridSize - 1) - NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, 1, 0), no); + if (!yLimitNext || 1 < gridSize - 1) + NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, 1), no); + if (!xLimitPrev || 1 < gridSize - 1) + NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, 1, 0), no); - for (K = 0; K < f->numVerts; K++) { - if (K != S) { - NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no); - } + for (K = 0; K < f->numVerts; K++) { + if (K != S) { + NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no); } } - else if (y == 0) { - NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x), no); - if (!yLimitNext || x < gridSize - 2) - NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x + 1), no); - } - else if (x == 0) { - NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y, 0), no); - if (!xLimitPrev || y < gridSize - 2) - NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y + 1, 0), no); - } + } + else if (y == 0) { + NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x), no); + if (!yLimitNext || x < gridSize - 2) + NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x + 1), no); + } + else if (x == 0) { + NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y, 0), no); + if (!xLimitPrev || y < gridSize - 2) + NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y + 1, 0), no); } } } } - /* XXX can I reduce the number of normalisations here? */ - for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { - CCGVert *v = (CCGVert *) effectedV[ptrIdx]; - float *no = VERT_getNo(v, lvl); +} - NormZero(no); +static void ccgSubSurf__calcVertNormals_faces_finalize_cb(void *userdata, int ptrIdx) +{ + CCGSubSurfCalcSubdivData *data = userdata; - for (i = 0; i < v->numFaces; i++) { - CCGFace *f = v->faces[i]; - NormAdd(no, FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1)); - } + CCGSubSurf *ss = data->ss; + CCGFace *f = data->effectedF[ptrIdx]; - if (UNLIKELY(v->numFaces == 0)) { - NormCopy(no, VERT_getCo(v, lvl)); + const int subdivLevels = ss->subdivLevels; + const int lvl = ss->subdivLevels; + const int gridSize = ccg_gridsize(lvl); + const int normalDataOffset = ss->normalDataOffset; + const int vertDataSize = ss->meshIFC.vertDataSize; + + int S, x, y; + + for (S = 0; S < f->numVerts; S++) { + NormCopy(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, gridSize - 1), + FACE_getIFNo(f, lvl, S, gridSize - 1, 0)); + } + + for (S = 0; S < f->numVerts; S++) { + for (y = 0; y < gridSize; y++) { + for (x = 0; x < gridSize; x++) { + float *no = FACE_getIFNo(f, lvl, S, x, y); + Normalize(no); + } } - Normalize(no); + VertDataCopy((float *)((byte *)FACE_getCenterData(f) + normalDataOffset), + FACE_getIFNo(f, lvl, S, 0, 0), ss); - for (i = 0; i < v->numFaces; i++) { - CCGFace *f = v->faces[i]; - NormCopy(FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1), no); + for (x = 1; x < gridSize - 1; x++) { + NormCopy(FACE_getIENo(f, lvl, S, x), + FACE_getIFNo(f, lvl, S, x, 0)); } } - for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { - CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; +} - if (e->numFaces) { - CCGFace *fLast = e->faces[e->numFaces - 1]; - int x; +static void ccgSubSurf__calcVertNormals_edges_accumulate_cb(void *userdata, int ptrIdx) +{ + CCGSubSurfCalcSubdivData *data = userdata; - for (i = 0; i < e->numFaces - 1; i++) { - CCGFace *f = e->faces[i]; - const int f_ed_idx = ccg_face_getEdgeIndex(f, e); - const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e); + CCGSubSurf *ss = data->ss; + CCGEdge *e = data->effectedE[ptrIdx]; - for (x = 1; x < edgeSize - 1; x++) { - NormAdd(_face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), - _face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); - } + const int subdivLevels = ss->subdivLevels; + const int lvl = ss->subdivLevels; + const int edgeSize = ccg_edgesize(lvl); + const int normalDataOffset = ss->normalDataOffset; + const int vertDataSize = ss->meshIFC.vertDataSize; + + if (e->numFaces) { + CCGFace *fLast = e->faces[e->numFaces - 1]; + int x, i; + + for (i = 0; i < e->numFaces - 1; i++) { + CCGFace *f = e->faces[i]; + const int f_ed_idx = ccg_face_getEdgeIndex(f, e); + const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e); + + for (x = 1; x < edgeSize - 1; x++) { + NormAdd(_face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), + _face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); } + } - for (i = 0; i < e->numFaces - 1; i++) { - CCGFace *f = e->faces[i]; - const int f_ed_idx = ccg_face_getEdgeIndex(f, e); - const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e); + for (i = 0; i < e->numFaces - 1; i++) { + CCGFace *f = e->faces[i]; + const int f_ed_idx = ccg_face_getEdgeIndex(f, e); + const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e); - for (x = 1; x < edgeSize - 1; x++) { - NormCopy(_face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), - _face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); - } + for (x = 1; x < edgeSize - 1; x++) { + NormCopy(_face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), + _face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); } } } +} -#pragma omp parallel for private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) - for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace *) effectedF[ptrIdx]; - int S, x, y; +static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss, + CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF, + int numEffectedV, int numEffectedE, int numEffectedF) +{ + int i, ptrIdx; + const int subdivLevels = ss->subdivLevels; + const int lvl = ss->subdivLevels; + const int edgeSize = ccg_edgesize(lvl); + const int gridSize = ccg_gridsize(lvl); + const int normalDataOffset = ss->normalDataOffset; + const int vertDataSize = ss->meshIFC.vertDataSize; + + CCGSubSurfCalcSubdivData data = { + .ss = ss, + .effectedV = effectedV, + .effectedE = effectedE, + .effectedF = effectedF, + .numEffectedV = numEffectedV, + .numEffectedE = numEffectedE, + .numEffectedF = numEffectedF + }; + + BLI_task_parallel_range(0, numEffectedF, + &data, + ccgSubSurf__calcVertNormals_faces_accumulate_cb, + numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT); - for (S = 0; S < f->numVerts; S++) { - NormCopy(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, gridSize - 1), - FACE_getIFNo(f, lvl, S, gridSize - 1, 0)); + /* XXX can I reduce the number of normalisations here? */ + for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { + CCGVert *v = (CCGVert *) effectedV[ptrIdx]; + float *no = VERT_getNo(v, lvl); + + NormZero(no); + + for (i = 0; i < v->numFaces; i++) { + CCGFace *f = v->faces[i]; + NormAdd(no, FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1)); } - for (S = 0; S < f->numVerts; S++) { - for (y = 0; y < gridSize; y++) { - for (x = 0; x < gridSize; x++) { - float *no = FACE_getIFNo(f, lvl, S, x, y); - Normalize(no); - } - } + if (UNLIKELY(v->numFaces == 0)) { + NormCopy(no, VERT_getCo(v, lvl)); + } - VertDataCopy((float *)((byte *)FACE_getCenterData(f) + normalDataOffset), - FACE_getIFNo(f, lvl, S, 0, 0), ss); + Normalize(no); - for (x = 1; x < gridSize - 1; x++) - NormCopy(FACE_getIENo(f, lvl, S, x), - FACE_getIFNo(f, lvl, S, x, 0)); + for (i = 0; i < v->numFaces; i++) { + CCGFace *f = v->faces[i]; + NormCopy(FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1), no); } } + BLI_task_parallel_range(0, numEffectedE, + &data, + ccgSubSurf__calcVertNormals_edges_accumulate_cb, + numEffectedE * edgeSize * 4 >= CCG_OMP_LIMIT); + + BLI_task_parallel_range(0, numEffectedF, + &data, + ccgSubSurf__calcVertNormals_faces_finalize_cb, + numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT); + for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; @@ -322,100 +395,268 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss, } } -static void ccgSubSurf__calcSubdivLevel( - CCGSubSurf *ss, - CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF, - const int numEffectedV, const int numEffectedE, const int numEffectedF, const int curLvl) + +static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb(void *userdata, int ptrIdx) { + CCGSubSurfCalcSubdivData *data = userdata; + + CCGSubSurf *ss = data->ss; + CCGFace *f = data->effectedF[ptrIdx]; + const int subdivLevels = ss->subdivLevels; + const int curLvl = data->curLvl; const int nextLvl = curLvl + 1; - int edgeSize = ccg_edgesize(curLvl); - int gridSize = ccg_gridsize(curLvl); - int ptrIdx, i; - int vertDataSize = ss->meshIFC.vertDataSize; - float *q = ss->q, *r = ss->r; + const int gridSize = ccg_gridsize(curLvl); + const int vertDataSize = ss->meshIFC.vertDataSize; -#pragma omp parallel for private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) - for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace *) effectedF[ptrIdx]; - int S, x, y; + int S, x, y; - /* interior face midpoints + /* interior face midpoints + * - old interior face points + */ + for (S = 0; S < f->numVerts; S++) { + for (y = 0; y < gridSize - 1; y++) { + for (x = 0; x < gridSize - 1; x++) { + int fx = 1 + 2 * x; + int fy = 1 + 2 * y; + const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y + 0); + const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y + 0); + const float *co2 = FACE_getIFCo(f, curLvl, S, x + 1, y + 1); + const float *co3 = FACE_getIFCo(f, curLvl, S, x + 0, y + 1); + float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); + + VertDataAvg4(co, co0, co1, co2, co3, ss); + } + } + } + + /* interior edge midpoints + * - old interior edge points + * - new interior face midpoints + */ + for (S = 0; S < f->numVerts; S++) { + for (x = 0; x < gridSize - 1; x++) { + int fx = x * 2 + 1; + const float *co0 = FACE_getIECo(f, curLvl, S, x + 0); + const float *co1 = FACE_getIECo(f, curLvl, S, x + 1); + const float *co2 = FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx); + const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1); + float *co = FACE_getIECo(f, nextLvl, S, fx); + + VertDataAvg4(co, co0, co1, co2, co3, ss); + } + + /* interior face interior edge midpoints * - old interior face points + * - new interior face midpoints */ - for (S = 0; S < f->numVerts; S++) { + + /* vertical */ + for (x = 1; x < gridSize - 1; x++) { for (y = 0; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - int fx = 1 + 2 * x; - int fy = 1 + 2 * y; - const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y + 0); - const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y + 0); - const float *co2 = FACE_getIFCo(f, curLvl, S, x + 1, y + 1); - const float *co3 = FACE_getIFCo(f, curLvl, S, x + 0, y + 1); - float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(co, co0, co1, co2, co3, ss); - } + int fx = x * 2; + int fy = y * 2 + 1; + const float *co0 = FACE_getIFCo(f, curLvl, S, x, y + 0); + const float *co1 = FACE_getIFCo(f, curLvl, S, x, y + 1); + const float *co2 = FACE_getIFCo(f, nextLvl, S, fx - 1, fy); + const float *co3 = FACE_getIFCo(f, nextLvl, S, fx + 1, fy); + float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); + + VertDataAvg4(co, co0, co1, co2, co3, ss); } } - /* interior edge midpoints - * - old interior edge points - * - new interior face midpoints - */ - for (S = 0; S < f->numVerts; S++) { + /* horizontal */ + for (y = 1; y < gridSize - 1; y++) { for (x = 0; x < gridSize - 1; x++) { int fx = x * 2 + 1; - const float *co0 = FACE_getIECo(f, curLvl, S, x + 0); - const float *co1 = FACE_getIECo(f, curLvl, S, x + 1); - const float *co2 = FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx); - const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1); - float *co = FACE_getIECo(f, nextLvl, S, fx); - + int fy = y * 2; + const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y); + const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y); + const float *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy - 1); + const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy + 1); + float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); + VertDataAvg4(co, co0, co1, co2, co3, ss); } + } + } +} - /* interior face interior edge midpoints - * - old interior face points - * - new interior face midpoints - */ - - /* vertical */ - for (x = 1; x < gridSize - 1; x++) { - for (y = 0; y < gridSize - 1; y++) { - int fx = x * 2; - int fy = y * 2 + 1; - const float *co0 = FACE_getIFCo(f, curLvl, S, x, y + 0); - const float *co1 = FACE_getIFCo(f, curLvl, S, x, y + 1); - const float *co2 = FACE_getIFCo(f, nextLvl, S, fx - 1, fy); - const float *co3 = FACE_getIFCo(f, nextLvl, S, fx + 1, fy); - float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(co, co0, co1, co2, co3, ss); - } - } +static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb(void *userdata, int ptrIdx) +{ + CCGSubSurfCalcSubdivData *data = userdata; + + CCGSubSurf *ss = data->ss; + CCGFace *f = data->effectedF[ptrIdx]; + + const int subdivLevels = ss->subdivLevels; + const int curLvl = data->curLvl; + const int nextLvl = curLvl + 1; + const int gridSize = ccg_gridsize(curLvl); + const int vertDataSize = ss->meshIFC.vertDataSize; + + float *q_thread = alloca(vertDataSize); + float *r_thread = alloca(vertDataSize); - /* horizontal */ + int S, x, y; + + /* interior center point shift + * - old face center point (shifting) + * - old interior edge points + * - new interior face midpoints + */ + VertDataZero(q_thread, ss); + for (S = 0; S < f->numVerts; S++) { + VertDataAdd(q_thread, FACE_getIFCo(f, nextLvl, S, 1, 1), ss); + } + VertDataMulN(q_thread, 1.0f / f->numVerts, ss); + VertDataZero(r_thread, ss); + for (S = 0; S < f->numVerts; S++) { + VertDataAdd(r_thread, FACE_getIECo(f, curLvl, S, 1), ss); + } + VertDataMulN(r_thread, 1.0f / f->numVerts, ss); + + VertDataMulN((float *)FACE_getCenterData(f), f->numVerts - 2.0f, ss); + VertDataAdd((float *)FACE_getCenterData(f), q_thread, ss); + VertDataAdd((float *)FACE_getCenterData(f), r_thread, ss); + VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss); + + for (S = 0; S < f->numVerts; S++) { + /* interior face shift + * - old interior face point (shifting) + * - new interior edge midpoints + * - new interior face midpoints + */ + for (x = 1; x < gridSize - 1; x++) { for (y = 1; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - int fx = x * 2 + 1; - int fy = y * 2; - const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y); - const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y); - const float *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy - 1); - const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy + 1); - float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(co, co0, co1, co2, co3, ss); - } + int fx = x * 2; + int fy = y * 2; + const float *co = FACE_getIFCo(f, curLvl, S, x, y); + float *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy); + + VertDataAvg4(q_thread, + FACE_getIFCo(f, nextLvl, S, fx - 1, fy - 1), + FACE_getIFCo(f, nextLvl, S, fx + 1, fy - 1), + FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 1), + FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 1), + ss); + + VertDataAvg4(r_thread, + FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 0), + FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 0), + FACE_getIFCo(f, nextLvl, S, fx + 0, fy - 1), + FACE_getIFCo(f, nextLvl, S, fx + 0, fy + 1), + ss); + + VertDataCopy(nCo, co, ss); + VertDataSub(nCo, q_thread, ss); + VertDataMulN(nCo, 0.25f, ss); + VertDataAdd(nCo, r_thread, ss); } } + + /* interior edge interior shift + * - old interior edge point (shifting) + * - new interior edge midpoints + * - new interior face midpoints + */ + for (x = 1; x < gridSize - 1; x++) { + int fx = x * 2; + const float *co = FACE_getIECo(f, curLvl, S, x); + float *nCo = FACE_getIECo(f, nextLvl, S, fx); + + VertDataAvg4(q_thread, + FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx - 1), + FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx + 1), + FACE_getIFCo(f, nextLvl, S, fx + 1, +1), + FACE_getIFCo(f, nextLvl, S, fx - 1, +1), + ss); + + VertDataAvg4(r_thread, + FACE_getIECo(f, nextLvl, S, fx - 1), + FACE_getIECo(f, nextLvl, S, fx + 1), + FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx), + FACE_getIFCo(f, nextLvl, S, fx, 1), + ss); + + VertDataCopy(nCo, co, ss); + VertDataSub(nCo, q_thread, ss); + VertDataMulN(nCo, 0.25f, ss); + VertDataAdd(nCo, r_thread, ss); + } } +} + +static void ccgSubSurf__calcSubdivLevel_verts_copydata_cb(void *userdata, int ptrIdx) +{ + CCGSubSurfCalcSubdivData *data = userdata; + + CCGSubSurf *ss = data->ss; + CCGFace *f = data->effectedF[ptrIdx]; + + const int subdivLevels = ss->subdivLevels; + const int nextLvl = data->curLvl + 1; + const int gridSize = ccg_gridsize(nextLvl); + const int cornerIdx = gridSize - 1; + const int vertDataSize = ss->meshIFC.vertDataSize; + + int S, x; + + for (S = 0; S < f->numVerts; S++) { + CCGEdge *e = FACE_getEdges(f)[S]; + CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts]; + + VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss); + VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss); + VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx), ss); + for (x = 1; x < gridSize - 1; x++) { + float *co = FACE_getIECo(f, nextLvl, S, x); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co, ss); + VertDataCopy(FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 0, x), co, ss); + } + for (x = 0; x < gridSize - 1; x++) { + int eI = gridSize - 1 - x; + VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss); + } + } +} + +static void ccgSubSurf__calcSubdivLevel( + CCGSubSurf *ss, + CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF, + const int numEffectedV, const int numEffectedE, const int numEffectedF, const int curLvl) +{ + const int subdivLevels = ss->subdivLevels; + const int nextLvl = curLvl + 1; + int edgeSize = ccg_edgesize(curLvl); + int ptrIdx, i; + const int vertDataSize = ss->meshIFC.vertDataSize; + float *q = ss->q, *r = ss->r; + + CCGSubSurfCalcSubdivData data = { + .ss = ss, + .effectedV = effectedV, + .effectedE = effectedE, + .effectedF = effectedF, + .numEffectedV = numEffectedV, + .numEffectedE = numEffectedE, + .numEffectedF = numEffectedF, + .curLvl = curLvl + }; + + BLI_task_parallel_range(0, numEffectedF, + &data, + ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb, + numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT); /* exterior edge midpoints * - old exterior edge points * - new interior face midpoints */ + /* Not worth parallelizing. */ for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; float sharpness = EDGE_getSharpness(e, curLvl); @@ -470,6 +711,7 @@ static void ccgSubSurf__calcSubdivLevel( * - old exterior edge points * - new interior face midpoints */ + /* Not worth parallelizing. */ for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { CCGVert *v = (CCGVert *) effectedV[ptrIdx]; const float *co = VERT_getCo(v, curLvl); @@ -600,6 +842,7 @@ static void ccgSubSurf__calcSubdivLevel( * - old exterior edge midpoints * - new interior face midpoints */ + /* Not worth parallelizing. */ for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; float sharpness = EDGE_getSharpness(e, curLvl); @@ -682,151 +925,25 @@ static void ccgSubSurf__calcSubdivLevel( } } -#pragma omp parallel private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) - { - float *q_thread, *r_thread; - -#pragma omp critical - { - q_thread = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf q"); - r_thread = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf r"); - } - -#pragma omp for schedule(static) - for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace *) effectedF[ptrIdx]; - int S, x, y; - - /* interior center point shift - * - old face center point (shifting) - * - old interior edge points - * - new interior face midpoints - */ - VertDataZero(q_thread, ss); - for (S = 0; S < f->numVerts; S++) { - VertDataAdd(q_thread, FACE_getIFCo(f, nextLvl, S, 1, 1), ss); - } - VertDataMulN(q_thread, 1.0f / f->numVerts, ss); - VertDataZero(r_thread, ss); - for (S = 0; S < f->numVerts; S++) { - VertDataAdd(r_thread, FACE_getIECo(f, curLvl, S, 1), ss); - } - VertDataMulN(r_thread, 1.0f / f->numVerts, ss); - - VertDataMulN((float *)FACE_getCenterData(f), f->numVerts - 2.0f, ss); - VertDataAdd((float *)FACE_getCenterData(f), q_thread, ss); - VertDataAdd((float *)FACE_getCenterData(f), r_thread, ss); - VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss); - - for (S = 0; S < f->numVerts; S++) { - /* interior face shift - * - old interior face point (shifting) - * - new interior edge midpoints - * - new interior face midpoints - */ - for (x = 1; x < gridSize - 1; x++) { - for (y = 1; y < gridSize - 1; y++) { - int fx = x * 2; - int fy = y * 2; - const float *co = FACE_getIFCo(f, curLvl, S, x, y); - float *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(q_thread, - FACE_getIFCo(f, nextLvl, S, fx - 1, fy - 1), - FACE_getIFCo(f, nextLvl, S, fx + 1, fy - 1), - FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 1), - FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 1), - ss); - - VertDataAvg4(r_thread, - FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 0), - FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 0), - FACE_getIFCo(f, nextLvl, S, fx + 0, fy - 1), - FACE_getIFCo(f, nextLvl, S, fx + 0, fy + 1), - ss); - - VertDataCopy(nCo, co, ss); - VertDataSub(nCo, q_thread, ss); - VertDataMulN(nCo, 0.25f, ss); - VertDataAdd(nCo, r_thread, ss); - } - } - - /* interior edge interior shift - * - old interior edge point (shifting) - * - new interior edge midpoints - * - new interior face midpoints - */ - for (x = 1; x < gridSize - 1; x++) { - int fx = x * 2; - const float *co = FACE_getIECo(f, curLvl, S, x); - float *nCo = FACE_getIECo(f, nextLvl, S, fx); - - VertDataAvg4(q_thread, - FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx - 1), - FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx + 1), - FACE_getIFCo(f, nextLvl, S, fx + 1, +1), - FACE_getIFCo(f, nextLvl, S, fx - 1, +1), ss); - - VertDataAvg4(r_thread, - FACE_getIECo(f, nextLvl, S, fx - 1), - FACE_getIECo(f, nextLvl, S, fx + 1), - FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx), - FACE_getIFCo(f, nextLvl, S, fx, 1), - ss); - - VertDataCopy(nCo, co, ss); - VertDataSub(nCo, q_thread, ss); - VertDataMulN(nCo, 0.25f, ss); - VertDataAdd(nCo, r_thread, ss); - } - } - } - -#pragma omp critical - { - MEM_freeN(q_thread); - MEM_freeN(r_thread); - } - } + BLI_task_parallel_range(0, numEffectedF, + &data, + ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb, + numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT); /* copy down */ edgeSize = ccg_edgesize(nextLvl); - gridSize = ccg_gridsize(nextLvl); - const int cornerIdx = gridSize - 1; -#pragma omp parallel for private(i) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) + /* Not worth parallelizing. */ for (i = 0; i < numEffectedE; i++) { CCGEdge *e = effectedE[i]; VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss); VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize - 1), VERT_getCo(e->v1, nextLvl), ss); } -#pragma omp parallel for private(i) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) - for (i = 0; i < numEffectedF; i++) { - CCGFace *f = effectedF[i]; - int S, x; - - for (S = 0; S < f->numVerts; S++) { - CCGEdge *e = FACE_getEdges(f)[S]; - CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts]; - - VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss); - VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx), ss); - for (x = 1; x < gridSize - 1; x++) { - float *co = FACE_getIECo(f, nextLvl, S, x); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co, ss); - VertDataCopy(FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 0, x), co, ss); - } - for (x = 0; x < gridSize - 1; x++) { - int eI = gridSize - 1 - x; - VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss); - } - } - } + BLI_task_parallel_range(0, numEffectedF, + &data, + ccgSubSurf__calcSubdivLevel_verts_copydata_cb, + numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT); } void ccgSubSurf__sync_legacy(CCGSubSurf *ss) diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 5b7947df9dd..07de2ad6342 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -800,8 +800,7 @@ static void nlastrips_path_rename_fix(ID *owner_id, const char *prefix, const ch } } -/* ----------------------- */ - +/* Rename Sub-ID Entities in RNA Paths ----------------------- */ /* Fix up the given RNA-Path * @@ -947,8 +946,7 @@ void BKE_animdata_fix_paths_rename(ID *owner_id, AnimData *adt, ID *ref_id, cons MEM_freeN(newN); } -/* *************************** */ -/* remove of individual paths */ +/* Remove FCurves with Prefix -------------------------------------- */ /* Check RNA-Paths for a list of F-Curves */ static void fcurves_path_remove_fix(const char *prefix, ListBase *curves) @@ -976,7 +974,6 @@ static void nlastrips_path_remove_fix(const char *prefix, ListBase *strips) /* recursively check strips, fixing only actions... */ for (strip = strips->first; strip; strip = strip->next) { - /* fix strip's action */ if (strip->act) fcurves_path_remove_fix(prefix, &strip->act->curves); @@ -999,7 +996,6 @@ void BKE_animdata_fix_paths_remove(ID *id, const char *prefix) /* check if there's any AnimData to start with */ if (adt) { - /* free fcurves */ if (adt->action) fcurves_path_remove_fix(prefix, &adt->action->curves); @@ -1017,6 +1013,75 @@ void BKE_animdata_fix_paths_remove(ID *id, const char *prefix) } } + +/* Apply Op to All FCurves in Database --------------------------- */ + +/* "User-Data" wrapper used by BKE_fcurves_main_cb() */ +typedef struct AllFCurvesCbWrapper { + ID_FCurve_Edit_Callback func; /* Operation to apply on F-Curve */ + void *user_data; /* Custom data for that operation */ +} AllFCurvesCbWrapper; + +/* Helper for adt_apply_all_fcurves_cb() - Apply wrapped operator to list of F-Curves */ +static void fcurves_apply_cb(ID *id, ListBase *fcurves, ID_FCurve_Edit_Callback func, void *user_data) +{ + FCurve *fcu; + + for (fcu = fcurves->first; fcu; fcu = fcu->next) { + func(id, fcu, user_data); + } +} + +/* Helper for adt_apply_all_fcurves_cb() - Recursively go through each NLA strip */ +static void nlastrips_apply_all_curves_cb(ID *id, ListBase *strips, AllFCurvesCbWrapper *wrapper) +{ + NlaStrip *strip; + + for (strip = strips->first; strip; strip = strip->next) { + /* fix strip's action */ + if (strip->act) { + fcurves_apply_cb(id, &strip->act->curves, wrapper->func, wrapper->user_data); + } + + /* check sub-strips (if metas) */ + nlastrips_apply_all_curves_cb(id, &strip->strips, wrapper); + } +} + +/* Helper for BKE_fcurves_main_cb() - Dispatch wrapped operator to all F-Curves */ +static void adt_apply_all_fcurves_cb(ID *id, AnimData *adt, void *wrapper_data) +{ + AllFCurvesCbWrapper *wrapper = wrapper_data; + NlaTrack *nlt; + + if (adt->action) { + fcurves_apply_cb(id, &adt->action->curves, wrapper->func, wrapper->user_data); + } + + if (adt->tmpact) { + fcurves_apply_cb(id, &adt->tmpact->curves, wrapper->func, wrapper->user_data); + } + + /* free drivers - stored as a list of F-Curves */ + fcurves_apply_cb(id, &adt->drivers, wrapper->func, wrapper->user_data); + + /* NLA Data - Animation Data for Strips */ + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + nlastrips_apply_all_curves_cb(id, &nlt->strips, wrapper); + } +} + +/* apply the given callback function on all F-Curves attached to data in main database */ +void BKE_fcurves_main_cb(Main *mainptr, ID_FCurve_Edit_Callback func, void *user_data) +{ + /* Wrap F-Curve operation stuff to pass to the general AnimData-level func */ + AllFCurvesCbWrapper wrapper = {func, user_data}; + + /* Use the AnimData-based function so that we don't have to reimplement all that stuff */ + BKE_animdata_main_cb(mainptr, adt_apply_all_fcurves_cb, &wrapper); +} + + /* Whole Database Ops -------------------------------------------- */ /* apply the given callback function on all data in main database */ diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 155967c7bd2..1b8bf3feb10 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -700,8 +700,6 @@ void BKE_pose_eval_flush(const struct EvaluationContext *UNUSED(eval_ctx), /* 6. release the IK tree */ BIK_release_tree(scene, ob, ctime); - - ob->recalc &= ~OB_RECALC_ALL; } void BKE_pose_eval_proxy_copy(const struct EvaluationContext *UNUSED(eval_ctx), Object *ob) @@ -712,8 +710,4 @@ void BKE_pose_eval_proxy_copy(const struct EvaluationContext *UNUSED(eval_ctx), printf("Proxy copy error, lib Object: %s proxy Object: %s\n", ob->id.name + 2, ob->proxy_from->id.name + 2); } - /* Rest of operations are NO-OP in depsgraph, so can clear - * flag now. - */ - ob->recalc &= ~OB_RECALC_ALL; } diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 25305b1d25a..8d69563f5ff 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -34,12 +34,14 @@ #include "BLI_string_utils.h" #include "BKE_collection.h" +#include "BKE_group.h" #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_scene.h" +#include "DNA_group_types.h" #include "DNA_ID.h" #include "DNA_layer_types.h" #include "DNA_object_types.h" @@ -47,15 +49,31 @@ #include "MEM_guardedalloc.h" +/* Prototypes. */ +static bool is_collection_in_tree(const struct SceneCollection *sc_reference, struct SceneCollection *sc_parent); + +static SceneCollection *collection_master_from_id(const ID *owner_id) +{ + switch (GS(owner_id->name)) { + case ID_SCE: + return ((Scene *)owner_id)->collection; + case ID_GR: + return ((Group *)owner_id)->collection; + default: + BLI_assert(!"ID doesn't support collections"); + return NULL; + } +} /** * Add a collection to a collection ListBase and syncronize all render layers * The ListBase is NULL when the collection is to be added to the master collection */ -SceneCollection *BKE_collection_add(Scene *scene, SceneCollection *sc_parent, const char *name) +SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name) { - SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc_master = collection_master_from_id(owner_id); SceneCollection *sc = MEM_callocN(sizeof(SceneCollection), "New Collection"); + sc->type = type; if (!name) { name = DATA_("New Collection"); @@ -65,10 +83,10 @@ SceneCollection *BKE_collection_add(Scene *scene, SceneCollection *sc_parent, co sc_parent = sc_master; } - BKE_collection_rename(scene, sc, name); + BKE_collection_rename((Scene *)owner_id, sc, name); BLI_addtail(&sc_parent->scene_collections, sc); - BKE_layer_sync_new_scene_collection(scene, sc_parent, sc); + BKE_layer_sync_new_scene_collection(owner_id, sc_parent, sc); return sc; } @@ -147,25 +165,25 @@ static void layer_collection_remove(ViewLayer *view_layer, ListBase *lb, const S /** * Remove a collection from the scene, and syncronize all render layers */ -bool BKE_collection_remove(Scene *scene, SceneCollection *sc) +bool BKE_collection_remove(ID *owner_id, SceneCollection *sc) { - SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc_master = collection_master_from_id(owner_id); - /* the master collection cannot be removed */ + /* The master collection cannot be removed. */ if (sc == sc_master) { return false; } - /* unlink from the respective collection tree */ + /* Unlink from the respective collection tree. */ if (!collection_remlink(sc_master, sc)) { BLI_assert(false); } - /* clear the collection items */ + /* Clear the collection items. */ collection_free(sc, true); /* check all layers that use this collection and clear them */ - for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { layer_collection_remove(view_layer, &view_layer->layer_collections, sc); view_layer->active_collection = 0; } @@ -175,11 +193,54 @@ bool BKE_collection_remove(Scene *scene, SceneCollection *sc) } /** - * Returns the master collection + * Copy SceneCollection tree but keep pointing to the same objects + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ -SceneCollection *BKE_collection_master(const Scene *scene) +void BKE_collection_copy_data(SceneCollection *sc_dst, SceneCollection *sc_src, const int flag) +{ + BLI_duplicatelist(&sc_dst->objects, &sc_src->objects); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + for (LinkData *link = sc_dst->objects.first; link; link = link->next) { + id_us_plus(link->data); + } + } + + BLI_duplicatelist(&sc_dst->filter_objects, &sc_src->filter_objects); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + for (LinkData *link = sc_dst->filter_objects.first; link; link = link->next) { + id_us_plus(link->data); + } + } + + BLI_duplicatelist(&sc_dst->scene_collections, &sc_src->scene_collections); + for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first; + nsc_src; + nsc_src = nsc_src->next, nsc_dst = nsc_dst->next) + { + BKE_collection_copy_data(nsc_dst, nsc_src, flag); + } +} + +static SceneCollection *master_collection_from_id(const ID *owner_id) { - return scene->collection; + switch (GS(owner_id->name)) { + case ID_SCE: + return ((const Scene *)owner_id)->collection; + case ID_GR: + return ((const Group *)owner_id)->collection; + default: + BLI_assert(!"ID doesn't support scene collection"); + return NULL; + } +} + +/** + * Returns the master collection of the scene or group + */ +SceneCollection *BKE_collection_master(const ID *owner_id) +{ + return master_collection_from_id(owner_id); } struct UniqueNameCheckData { @@ -207,41 +268,58 @@ static bool collection_unique_name_check(void *arg, const char *name) return false; } -void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char *name) +static void collection_rename(const ID *owner_id, SceneCollection *sc, const char *name) { - SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc_master = collection_master_from_id(owner_id); struct UniqueNameCheckData data = {.lb = &sc_master->scene_collections, .lookup_sc = sc}; BLI_strncpy(sc->name, name, sizeof(sc->name)); BLI_uniquename_cb(collection_unique_name_check, &data, DATA_("Collection"), '.', sc->name, sizeof(sc->name)); } +void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char *name) +{ + collection_rename(&scene->id, sc, name); +} + /** * Free (or release) any data used by the master collection (does not free the master collection itself). - * Used only to clear the entire scene data since it's not doing re-syncing of the LayerCollection tree + * Used only to clear the entire scene or group data since it's not doing re-syncing of the LayerCollection tree */ -void BKE_collection_master_free(Scene *scene, const bool do_id_user) +void BKE_collection_master_free(ID *owner_id, const bool do_id_user) { - collection_free(BKE_collection_master(scene), do_id_user); + collection_free(BKE_collection_master(owner_id), do_id_user); } -static void collection_object_add(const Scene *scene, SceneCollection *sc, Object *ob) +static void collection_object_add(const ID *owner_id, SceneCollection *sc, Object *ob) { BLI_addtail(&sc->objects, BLI_genericNodeN(ob)); - id_us_plus((ID *)ob); - BKE_layer_sync_object_link(scene, sc, ob); + + if (GS(owner_id->name) == ID_SCE) { + id_us_plus((ID *)ob); + } + else { + BLI_assert(GS(owner_id->name) == ID_GR); + if ((ob->flag & OB_FROMGROUP) == 0) { + ob->flag |= OB_FROMGROUP; + } + } + + BKE_layer_sync_object_link(owner_id, sc, ob); } /** * Add object to collection */ -void BKE_collection_object_add(const Scene *scene, SceneCollection *sc, Object *ob) +bool BKE_collection_object_add(const ID *owner_id, SceneCollection *sc, Object *ob) { if (BLI_findptr(&sc->objects, ob, offsetof(LinkData, data))) { /* don't add the same object twice */ - return; + return false; } - collection_object_add(scene, sc, ob); + + collection_object_add(owner_id, sc, ob); + return true; } /** @@ -253,7 +331,7 @@ void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst FOREACH_SCENE_COLLECTION(scene, sc) { if (BLI_findptr(&sc->objects, ob_src, offsetof(LinkData, data))) { - collection_object_add(scene, sc, ob_dst); + collection_object_add(&scene->id, sc, ob_dst); } } FOREACH_SCENE_COLLECTION_END @@ -274,50 +352,139 @@ void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst * Remove object from collection. * \param bmain: Can be NULL if free_us is false. */ -void BKE_collection_object_remove(Main *bmain, const Scene *scene, SceneCollection *sc, Object *ob, const bool free_us) +bool BKE_collection_object_remove(Main *bmain, ID *owner_id, SceneCollection *sc, Object *ob, const bool free_us) { - LinkData *link = BLI_findptr(&sc->objects, ob, offsetof(LinkData, data)); if (link == NULL) { - return; + return false; } BLI_remlink(&sc->objects, link); MEM_freeN(link); TODO_LAYER_SYNC_FILTER; /* need to remove all instances of ob in scene collections -> filter_objects */ - BKE_layer_sync_object_unlink(scene, sc, ob); + BKE_layer_sync_object_unlink(owner_id, sc, ob); - if (free_us) { - BKE_libblock_free_us(bmain, ob); + if (GS(owner_id->name) == ID_SCE) { + if (free_us) { + BKE_libblock_free_us(bmain, ob); + } + else { + id_us_min(&ob->id); + } } else { - id_us_min(&ob->id); + BLI_assert(GS(owner_id->name) == ID_GR); } + + return true; } /** * Move object from a collection into another */ -void BKE_collection_object_move(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src, Object *ob) +void BKE_collection_object_move(ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src, Object *ob) { - BKE_collection_object_add(scene, sc_dst, ob); - BKE_collection_object_remove(NULL, scene, sc_src, ob, false); + BKE_collection_object_add(owner_id, sc_dst, ob); + BKE_collection_object_remove(NULL, owner_id, sc_src, ob, false); } /** * Remove object from all collections of scene */ -void BKE_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us) +bool BKE_collections_object_remove(Main *bmain, ID *owner_id, Object *ob, const bool free_us) { - BKE_scene_remove_rigidbody_object(scene, ob); + bool removed = false; + if (GS(owner_id->name) == ID_SCE) { + BKE_scene_remove_rigidbody_object((Scene *)owner_id, ob); + } + else { + BLI_assert(GS(owner_id->name) == ID_GR); + } - FOREACH_SCENE_COLLECTION(scene, sc) + FOREACH_SCENE_COLLECTION(owner_id, sc) { - BKE_collection_object_remove(bmain, scene, sc, ob, free_us); + removed |= BKE_collection_object_remove(bmain, owner_id, sc, ob, free_us); } FOREACH_SCENE_COLLECTION_END + return removed; +} + +static void layer_collection_sync(LayerCollection *lc_dst, LayerCollection *lc_src) +{ + lc_dst->flag = lc_src->flag; + + /* Pending: sync overrides. */ + IDP_MergeGroup(lc_dst->properties, lc_src->properties, true); + + /* Continue recursively. */ + LayerCollection *lc_dst_nested, *lc_src_nested; + lc_src_nested = lc_src->layer_collections.first; + for (lc_dst_nested = lc_dst->layer_collections.first; + lc_dst_nested && lc_src_nested; + lc_dst_nested = lc_dst_nested->next, lc_src_nested = lc_src_nested->next) + { + layer_collection_sync(lc_dst_nested, lc_src_nested); + } +} + +/** + * Leave only the master collection in, remove everything else. + * @param group + */ +static void collection_group_cleanup(Group *group) +{ + /* Unlink all the LayerCollections. */ + while (group->view_layer->layer_collections.last != NULL) { + BKE_collection_unlink(group->view_layer, group->view_layer->layer_collections.last); + } + + /* Remove all the SceneCollections but the master. */ + collection_free(group->collection, false); +} + +/** + * Create a group from a collection + * + * Any ViewLayer that may have this the related SceneCollection linked is converted + * to a Group Collection. + */ +Group *BKE_collection_group_create(Main *bmain, Scene *scene, LayerCollection *lc_src) +{ + SceneCollection *sc_dst, *sc_src = lc_src->scene_collection; + LayerCollection *lc_dst; + + /* The master collection can't be converted. */ + if (sc_src == BKE_collection_master(&scene->id)) { + return NULL; + } + + /* If a sub-collection of sc_dst is directly linked into a ViewLayer we can't convert. */ + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (LayerCollection *lc_child = view_layer->layer_collections.first; lc_child; lc_child = lc_child->next) { + if (is_collection_in_tree(lc_child->scene_collection, sc_src)) { + return NULL; + } + } + } + + /* Create new group with the same data as the original collection. */ + Group *group = BKE_group_add(bmain, sc_src->name); + collection_group_cleanup(group); + + sc_dst = BKE_collection_add(&group->id, NULL, COLLECTION_TYPE_GROUP_INTERNAL, sc_src->name); + BKE_collection_copy_data(sc_dst, sc_src, 0); + FOREACH_SCENE_COLLECTION(&group->id, sc_group) + { + sc_group->type = COLLECTION_TYPE_GROUP_INTERNAL; + } + FOREACH_SCENE_COLLECTION_END + + lc_dst = BKE_collection_link(group->view_layer, sc_dst); + layer_collection_sync(lc_dst, lc_src); + + return group; } /* ---------------------------------------------------------------------- */ @@ -353,10 +520,10 @@ static bool is_collection_in_tree(const SceneCollection *sc_reference, SceneColl return find_collection_parent(sc_reference, sc_parent) != NULL; } -bool BKE_collection_move_above(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src) +bool BKE_collection_move_above(const ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src) { /* Find the SceneCollection the sc_src belongs to */ - SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc_master = master_collection_from_id(owner_id); /* Master Layer can't be moved around*/ if (ELEM(sc_master, sc_src, sc_dst)) { @@ -386,16 +553,16 @@ bool BKE_collection_move_above(const Scene *scene, SceneCollection *sc_dst, Scen BLI_insertlinkbefore(&sc_dst_parent->scene_collections, sc_dst, sc_src); /* Update the tree */ - BKE_layer_collection_resync(scene, sc_src_parent); - BKE_layer_collection_resync(scene, sc_dst_parent); + BKE_layer_collection_resync(owner_id, sc_src_parent); + BKE_layer_collection_resync(owner_id, sc_dst_parent); return true; } -bool BKE_collection_move_below(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src) +bool BKE_collection_move_below(const ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src) { /* Find the SceneCollection the sc_src belongs to */ - SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc_master = master_collection_from_id(owner_id); /* Master Layer can't be moved around*/ if (ELEM(sc_master, sc_src, sc_dst)) { @@ -425,16 +592,16 @@ bool BKE_collection_move_below(const Scene *scene, SceneCollection *sc_dst, Scen BLI_insertlinkafter(&sc_dst_parent->scene_collections, sc_dst, sc_src); /* Update the tree */ - BKE_layer_collection_resync(scene, sc_src_parent); - BKE_layer_collection_resync(scene, sc_dst_parent); + BKE_layer_collection_resync(owner_id, sc_src_parent); + BKE_layer_collection_resync(owner_id, sc_dst_parent); return true; } -bool BKE_collection_move_into(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src) +bool BKE_collection_move_into(const ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src) { /* Find the SceneCollection the sc_src belongs to */ - SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc_master = master_collection_from_id(owner_id); if (sc_src == sc_master) { return false; } @@ -460,8 +627,8 @@ bool BKE_collection_move_into(const Scene *scene, SceneCollection *sc_dst, Scene BLI_addtail(&sc_dst->scene_collections, sc_src); /* Update the tree */ - BKE_layer_collection_resync(scene, sc_src_parent); - BKE_layer_collection_resync(scene, sc_dst); + BKE_layer_collection_resync(owner_id, sc_src_parent); + BKE_layer_collection_resync(owner_id, sc_dst); return true; } @@ -471,7 +638,7 @@ bool BKE_collection_move_into(const Scene *scene, SceneCollection *sc_dst, Scene /* scene collection iteractor */ typedef struct SceneCollectionsIteratorData { - Scene *scene; + ID *owner_id; void **array; int tot, cur; } SceneCollectionsIteratorData; @@ -498,17 +665,20 @@ static void scene_collections_build_array(SceneCollection *sc, void *data) (*array)++; } -static void scene_collections_array(Scene *scene, SceneCollection ***collections_array, int *tot) +static void scene_collections_array(ID *owner_id, SceneCollection ***collections_array, int *tot) { - SceneCollection *sc = BKE_collection_master(scene); + SceneCollection *sc; SceneCollection **array; *collections_array = NULL; *tot = 0; - if (scene == NULL) + if (owner_id == NULL) { return; + } + sc = master_collection_from_id(owner_id); + BLI_assert(sc != NULL); scene_collection_callback(sc, scene_collections_count, tot); if (*tot == 0) @@ -524,13 +694,13 @@ static void scene_collections_array(Scene *scene, SceneCollection ***collections */ void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in) { - Scene *scene = data_in; + ID *owner_id = data_in; SceneCollectionsIteratorData *data = MEM_callocN(sizeof(SceneCollectionsIteratorData), __func__); - data->scene = scene; + data->owner_id = owner_id; iter->data = data; - scene_collections_array(scene, (SceneCollection ***)&data->array, &data->tot); + scene_collections_array(owner_id, (SceneCollection ***)&data->array, &data->tot); BLI_assert(data->tot != 0); data->cur = 0; diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index a004d32847a..2f80fbbec46 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -47,6 +47,7 @@ #include "BKE_cloth.h" #include "BKE_effect.h" +#include "BKE_group.h" #include "BKE_layer.h" #include "BKE_modifier.h" #include "BKE_scene.h" @@ -502,12 +503,14 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned /* objects in dupli groups, one level only for now */ if (ob->dup_group && level == 0) { - GroupObject *go; Group *group= ob->dup_group; /* add objects */ - for (go= group->gobject.first; go; go= go->next) - add_collision_object(objs, numobj, maxobj, go->ob, self, level+1, modifier_type); + FOREACH_GROUP_OBJECT(group, object) + { + add_collision_object(objs, numobj, maxobj, object, self, level+1, modifier_type); + } + FOREACH_GROUP_OBJECT_END } } @@ -515,9 +518,7 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned // collision object will exclude self Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type, bool dupli) { - Base *base; Object **objs; - GroupObject *go; unsigned int numobj= 0, maxobj= 100; int level = dupli ? 0 : 1; @@ -526,11 +527,15 @@ Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, unsi /* gather all collision objects */ if (group) { /* use specified group */ - for (go= group->gobject.first; go; go= go->next) - add_collision_object(&objs, &numobj, &maxobj, go->ob, self, level, modifier_type); + FOREACH_GROUP_OBJECT(group, object) + { + add_collision_object(&objs, &numobj, &maxobj, object, self, level, modifier_type); + } + FOREACH_GROUP_OBJECT_END } else { Scene *sce_iter; + Base *base; /* add objects in same layer in scene */ for (SETLOOPER(scene, sce_iter, base)) { if ((base->flag & BASE_VISIBLED) != 0) { @@ -576,24 +581,28 @@ static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self, /* objects in dupli groups, one level only for now */ if (ob->dup_group && level == 0) { - GroupObject *go; Group *group= ob->dup_group; /* add objects */ - for (go= group->gobject.first; go; go= go->next) - add_collider_cache_object(objs, go->ob, self, level+1); + FOREACH_GROUP_OBJECT(group, object) + { + add_collider_cache_object(objs, object, self, level+1); + } + FOREACH_GROUP_OBJECT_END } } ListBase *get_collider_cache(Scene *scene, Object *self, Group *group) { - GroupObject *go; ListBase *objs= NULL; /* add object in same layer in scene */ if (group) { - for (go= group->gobject.first; go; go= go->next) - add_collider_cache_object(&objs, go->ob, self, 0); + FOREACH_GROUP_OBJECT(group, object) + { + add_collider_cache_object(&objs, object, self, 0); + } + FOREACH_GROUP_OBJECT_END } else { Scene *sce_iter; @@ -802,8 +811,8 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa if ( cloth->bvhselftree ) { // search for overlapping collision pairs overlap = BLI_bvhtree_overlap(cloth->bvhselftree, cloth->bvhselftree, &result, NULL, NULL); - - // #pragma omp parallel for private(k, i, j) schedule(static) + + /* Could be parallelized (using BLI_task)... */ for ( k = 0; k < result; k++ ) { float temp[3]; float length = 0; diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 8067c1edce0..1f673d2c15f 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -679,6 +679,11 @@ struct wmManipulatorGroup *CTX_wm_manipulator_group(const bContext *C) return C->wm.manipulator_group; } +struct wmMsgBus *CTX_wm_message_bus(const bContext *C) +{ + return C->wm.manager ? C->wm.manager->message_bus : NULL; +} + struct ReportList *CTX_wm_reports(const bContext *C) { if (C->wm.manager) @@ -955,7 +960,7 @@ ViewRender *CTX_data_view_render(const bContext *C) } } -RenderEngineType *CTX_data_engine(const bContext *C) +RenderEngineType *CTX_data_engine_type(const bContext *C) { ViewRender *view_render = CTX_data_view_render(C); return RE_engines_find(view_render->engine_id); @@ -999,7 +1004,7 @@ SceneCollection *CTX_data_scene_collection(const bContext *C) /* fallback */ Scene *scene = CTX_data_scene(C); - return BKE_collection_master(scene); + return BKE_collection_master(&scene->id); } int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob) @@ -1277,8 +1282,8 @@ void CTX_data_eval_ctx(const bContext *C, EvaluationContext *eval_ctx) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - RenderEngineType *engine = CTX_data_engine(C); + RenderEngineType *engine_type = CTX_data_engine_type(C); DEG_evaluation_context_init_from_scene(eval_ctx, - scene, view_layer, engine, + scene, view_layer, engine_type, DAG_EVAL_VIEWPORT); } diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 9e292422019..80a31697424 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -491,33 +491,24 @@ static void scene_setSubframe(Scene *scene, float subframe) static int surface_getBrushFlags(DynamicPaintSurface *surface, const ViewLayer *view_layer) { Base *base = NULL; - GroupObject *go = NULL; Object *brushObj = NULL; ModifierData *md = NULL; int flags = 0; if (surface->brush_group) - go = surface->brush_group->gobject.first; + base = FIRSTBASE(surface->brush_group->view_layer); else base = FIRSTBASE(view_layer); - while (base || go) { + while (base) { brushObj = NULL; /* select object */ - if (surface->brush_group) { - if (go->ob) - brushObj = go->ob; - } - else { - brushObj = base->object; - } + brushObj = base->object; - if (surface->brush_group) - go = go->next; - else - base = base->next; + /* next item */ + base = base->next; if (!brushObj) { continue; @@ -5780,7 +5771,6 @@ static int dynamicPaint_doStep(const struct EvaluationContext *eval_ctx, Scene * */ { Base *base = NULL; - GroupObject *go = NULL; Object *brushObj = NULL; ModifierData *md = NULL; ViewLayer *view_layer = eval_ctx->view_layer; @@ -5791,25 +5781,17 @@ static int dynamicPaint_doStep(const struct EvaluationContext *eval_ctx, Scene * /* either from group or from all objects */ if (surface->brush_group) - go = surface->brush_group->gobject.first; + base = FIRSTBASE(surface->brush_group->view_layer); else base = FIRSTBASE(view_layer); - while (base || go) { + while (base) { brushObj = NULL; /* select object */ - if (surface->brush_group) { - if (go->ob) - brushObj = go->ob; - } - else - brushObj = base->object; + brushObj = base->object; /* next item */ - if (surface->brush_group) - go = go->next; - else - base = base->next; + base = base->next; if (!brushObj) { /* skip item */ diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 502ad9c44a7..16124fb4777 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -64,6 +64,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_effect.h" #include "BKE_global.h" +#include "BKE_group.h" #include "BKE_layer.h" #include "BKE_library.h" #include "BKE_modifier.h" @@ -215,51 +216,41 @@ ListBase *pdInitEffectors( { ViewLayer *view_layer; Base *base; - unsigned int layer= ob_src->lay; ListBase *effectors = NULL; - /* eval_ctx is NULL during deg build */ - if (eval_ctx) { + if (weights->group) { + view_layer = weights->group->view_layer; + } + else if (eval_ctx) { view_layer = eval_ctx->view_layer; } else { + /* eval_ctx is NULL during deg build */ view_layer = BKE_view_layer_context_active_PLACEHOLDER(scene); } - - if (weights->group) { - GroupObject *go; - - for (go= weights->group->gobject.first; go; go= go->next) { - if ( (go->ob->lay & layer) ) { - if ( go->ob->pd && go->ob->pd->forcefield ) - add_object_to_effectors(&effectors, eval_ctx, scene, weights, go->ob, ob_src, for_simulation); - if ( go->ob->particlesystem.first ) { - ParticleSystem *psys= go->ob->particlesystem.first; + for (base = FIRSTBASE(view_layer); base; base = base->next) { + if ((base->flag & BASE_VISIBLED) == 0) { + continue; + } - for ( ; psys; psys=psys->next ) - add_particles_to_effectors(&effectors, eval_ctx, scene, weights, go->ob, psys, psys_src, for_simulation); - } - } + if (base->object->pd && base->object->pd->forcefield) { + add_object_to_effectors(&effectors, eval_ctx, scene, weights, base->object, ob_src, for_simulation); } - } - else { - for (base = FIRSTBASE(view_layer); base; base = base->next) { - if ( base->object->pd && base->object->pd->forcefield ) - add_object_to_effectors(&effectors, eval_ctx, scene, weights, base->object, ob_src, for_simulation); - if ( base->object->particlesystem.first ) { - ParticleSystem *psys= base->object->particlesystem.first; + if (base->object->particlesystem.first) { + ParticleSystem *psys= base->object->particlesystem.first; - for ( ; psys; psys=psys->next ) - add_particles_to_effectors(&effectors, eval_ctx, scene, weights, base->object, psys, psys_src, for_simulation); + for (; psys; psys=psys->next) { + add_particles_to_effectors(&effectors, eval_ctx, scene, weights, base->object, psys, psys_src, for_simulation); } } } - - if (for_simulation) + + if (for_simulation) { pdPrecalculateEffectors(eval_ctx, effectors); - + } + return effectors; } diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index 5e5f8114ead..7c2eefe657c 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -45,32 +45,53 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BKE_collection.h" #include "BKE_global.h" #include "BKE_group.h" #include "BKE_icons.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_scene.h" -static void free_group_object(GroupObject *go) -{ - MEM_freeN(go); -} - /** Free (or release) any data used by this group (does not free the group itself). */ void BKE_group_free(Group *group) { - /* don't free group itself */ - GroupObject *go; - /* No animdata here. */ + BKE_previewimg_free(&group->preview); - while ((go = BLI_pophead(&group->gobject))) { - free_group_object(go); + if (group->view_layer != NULL) { + BKE_view_layer_free(group->view_layer); + group->view_layer = NULL; } - BKE_previewimg_free(&group->preview); + if (group->collection != NULL) { + BKE_collection_master_free(&group->id, false); + MEM_freeN(group->collection); + group->collection = NULL; + } +} + +/** + * Run when adding new groups or during doversion. + */ +void BKE_group_init(Group *group) +{ + group->collection = MEM_callocN(sizeof(SceneCollection), __func__); + BLI_strncpy(group->collection->name, "Master Collection", sizeof(group->collection->name)); + group->view_layer = NULL; /* groups are not calloced. */ + group->view_layer = BKE_view_layer_group_add(group); + + /* Unlink the master collection. */ + BKE_collection_unlink(group->view_layer, group->view_layer->layer_collections.first); + + /* Create and link a new default collection. */ + SceneCollection *defaut_collection = BKE_collection_add(&group->id, + NULL, + COLLECTION_TYPE_GROUP_INTERNAL, + "Default Collection"); + BKE_collection_link(group->view_layer, defaut_collection); } Group *BKE_group_add(Main *bmain, const char *name) @@ -83,7 +104,7 @@ Group *BKE_group_add(Main *bmain, const char *name) group->layer = (1 << 20) - 1; group->preview = NULL; - + BKE_group_init(group); return group; } @@ -97,7 +118,8 @@ Group *BKE_group_add(Main *bmain, const char *name) */ void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *group_src, const int flag) { - BLI_duplicatelist(&group_dst->gobject, &group_src->gobject); + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; /* Do not copy group's preview (same behavior as for objects). */ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ @@ -106,6 +128,18 @@ void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *gro else { group_dst->preview = NULL; } + + group_dst->collection = MEM_dupallocN(group_src->collection); + SceneCollection *master_collection_src = BKE_collection_master(&group_src->id); + SceneCollection *master_collection_dst = BKE_collection_master(&group_dst->id); + + /* Recursively creates a new SceneCollection tree. */ + BKE_collection_copy_data(master_collection_dst, master_collection_src, + flag_subdata); + + BKE_view_layer_copy_data(group_dst->view_layer, group_src->view_layer, + master_collection_dst, master_collection_src, + flag_subdata); } Group *BKE_group_copy(Main *bmain, const Group *group) @@ -123,23 +157,19 @@ void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local) /* external */ static bool group_object_add_internal(Group *group, Object *ob) { - GroupObject *go; - if (group == NULL || ob == NULL) { return false; } - - /* check if the object has been added already */ - if (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob))) { + + /* For now always add to master collection of the group. */ + SceneCollection *scene_collection = GROUP_MASTER_COLLECTION(group); + + /* If the object has been added already it returns false. */ + if (BKE_collection_object_add(&group->id, scene_collection, ob) == false) { return false; } - - go = MEM_callocN(sizeof(GroupObject), "groupobject"); - BLI_addtail(&group->gobject, go); - - go->ob = ob; - id_us_ensure_real(&go->ob->id); - + + id_us_ensure_real(&ob->id); return true; } @@ -157,24 +187,17 @@ bool BKE_group_object_add(Group *group, Object *object) } /* also used for (ob == NULL) */ -static int group_object_unlink_internal(Group *group, Object *ob) +static bool group_object_unlink_internal(Group *group, Object *ob) { - GroupObject *go, *gon; - int removed = 0; - if (group == NULL) return 0; - - go = group->gobject.first; - while (go) { - gon = go->next; - if (go->ob == ob) { - BLI_remlink(&group->gobject, go); - free_group_object(go); - removed = 1; - /* should break here since an object being in a group twice cant happen? */ - } - go = gon; + if (group == NULL) { + return false; + } + + if (BKE_collections_object_remove(NULL, &group->id, ob, false)) { + return true; } - return removed; + + return false; } static bool group_object_cyclic_check_internal(Object *object, Group *group) @@ -191,12 +214,13 @@ static bool group_object_cyclic_check_internal(Object *object, Group *group) if (dup_group == group) return true; else { - GroupObject *gob; - for (gob = dup_group->gobject.first; gob; gob = gob->next) { - if (group_object_cyclic_check_internal(gob->ob, group)) { + FOREACH_GROUP_OBJECT(dup_group, group_object) + { + if (group_object_cyclic_check_internal(group_object, dup_group)) { return true; } } + FOREACH_GROUP_OBJECT_END } /* un-flag the object, it's allowed to have the same group multiple times in parallel */ @@ -234,7 +258,7 @@ bool BKE_group_object_exists(Group *group, Object *ob) return false; } else { - return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL); + return (BLI_findptr(&group->view_layer->object_bases, ob, offsetof(Base, object))); } } @@ -253,31 +277,15 @@ Group *BKE_group_object_find(Group *group, Object *ob) return NULL; } -void BKE_group_tag_recalc(Group *group) -{ - GroupObject *go; - - if (group == NULL) return; - - for (go = group->gobject.first; go; go = go->next) { - if (go->ob) - go->ob->recalc = go->recalc; - } -} - bool BKE_group_is_animated(Group *group, Object *UNUSED(parent)) { - GroupObject *go; - -#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */ - if (parent->nlastrips.first) - return 1; -#endif - - for (go = group->gobject.first; go; go = go->next) - if (go->ob && go->ob->proxy) + FOREACH_GROUP_OBJECT(group, object) + { + if (object->proxy) { return true; - + } + } + FOREACH_GROUP_OBJECT_END return false; } @@ -329,8 +337,6 @@ static void group_replaces_nla(Object *parent, Object *target, char mode) /* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */ void BKE_group_handle_recalc_and_update(const struct EvaluationContext *eval_ctx, Scene *scene, Object *UNUSED(parent), Group *group) { - GroupObject *go; - #if 0 /* warning, isn't clearing the recalc flag on the object which causes it to run all the time, * not just on frame change. * This isn't working because the animation data is only re-evaluated on frame change so commenting for now @@ -364,12 +370,12 @@ void BKE_group_handle_recalc_and_update(const struct EvaluationContext *eval_ctx #endif { /* only do existing tags, as set by regular depsgraph */ - for (go = group->gobject.first; go; go = go->next) { - if (go->ob) { - if (go->ob->recalc) { - BKE_object_handle_update(eval_ctx, scene, go->ob); - } + FOREACH_GROUP_OBJECT(group, object) + { + if (object->id.tag & LIB_TAG_ID_RECALC_ALL) { + BKE_object_handle_update(eval_ctx, scene, object); } } + FOREACH_GROUP_OBJECT_END } } diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 01d8b180344..84eb4ee2e33 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -35,12 +35,14 @@ #include "BKE_collection.h" #include "BKE_freestyle.h" #include "BKE_global.h" +#include "BKE_group.h" #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_workspace.h" +#include "DNA_group_types.h" #include "DNA_ID.h" #include "DNA_layer_types.h" #include "DNA_object_types.h" @@ -89,7 +91,7 @@ ViewLayer *BKE_view_layer_from_workspace_get(const struct Scene *scene, const st return BKE_view_layer_from_scene_get(scene); } else { - return BKE_workspace_view_layer_get(workspace); + return BKE_workspace_view_layer_get(workspace, scene); } } @@ -102,11 +104,7 @@ ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene) return BKE_view_layer_from_scene_get(scene); } -/** - * Add a new renderlayer - * by default, a renderlayer has the master collection - */ -ViewLayer *BKE_view_layer_add(Scene *scene, const char *name) +static ViewLayer *view_layer_add(const char *name, SceneCollection *master_scene_collection) { if (!name) { name = DATA_("View Layer"); @@ -118,15 +116,10 @@ ViewLayer *BKE_view_layer_add(Scene *scene, const char *name) view_layer->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); layer_engine_settings_init(view_layer->properties, false); - - BLI_addtail(&scene->view_layers, view_layer); - - /* unique name */ BLI_strncpy_utf8(view_layer->name, name, sizeof(view_layer->name)); - BLI_uniquename(&scene->view_layers, view_layer, DATA_("ViewLayer"), '.', offsetof(ViewLayer, name), sizeof(view_layer->name)); - SceneCollection *sc = BKE_collection_master(scene); - layer_collection_add(view_layer, NULL, sc); + /* Link the master collection by default. */ + layer_collection_add(view_layer, NULL, master_scene_collection); /* Pure rendering pipeline settings. */ view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */ @@ -138,6 +131,37 @@ ViewLayer *BKE_view_layer_add(Scene *scene, const char *name) } /** + * Add a new view layer + * by default, a view layer has the master collection + */ +ViewLayer *BKE_view_layer_add(Scene *scene, const char *name) +{ + SceneCollection *sc = BKE_collection_master(&scene->id); + ViewLayer *view_layer = view_layer_add(name, sc); + + BLI_addtail(&scene->view_layers, view_layer); + + /* unique name */ + BLI_uniquename( + &scene->view_layers, view_layer, DATA_("ViewLayer"), '.', + offsetof(ViewLayer, name), sizeof(view_layer->name)); + + return view_layer; +} + +/** + * Add a ViewLayer for a Group + * It should be added only once + */ +ViewLayer *BKE_view_layer_group_add(Group *group) +{ + BLI_assert(group->view_layer == NULL); + SceneCollection *sc = BKE_collection_master(&group->id); + ViewLayer *view_layer = view_layer_add(group->id.name + 2, sc); + return view_layer; +} + +/** * Free (or release) any data used by this ViewLayer. */ void BKE_view_layer_free(ViewLayer *view_layer) @@ -204,6 +228,22 @@ void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag) } } +/** + * Return the first ViewLayer for a given id + */ +ViewLayer *BKE_view_layer_first_from_id(const ID *owner_id) +{ + switch (GS(owner_id->name)) { + case ID_SCE: + return ((Scene *)owner_id)->view_layers.first; + case ID_GR: + return ((Group *)owner_id)->view_layer; + default: + BLI_assert(!"ID doesn't support view layers"); + return NULL; + } +} + static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc) { for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) { @@ -238,14 +278,25 @@ Object *BKE_view_layer_camera_find(ViewLayer *view_layer) /** * Find the ViewLayer a LayerCollection belongs to */ -ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc) -{ - for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { - if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) { - return view_layer; +ViewLayer *BKE_view_layer_find_from_collection(const ID *owner_id, LayerCollection *lc) +{ + switch (GS(owner_id->name)) { + case ID_GR: + return ((Group *)owner_id)->view_layer; + case ID_SCE: + { + Scene *scene = (Scene *)owner_id; + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) { + return view_layer; + } + } + return NULL; } + default: + BLI_assert(!"ID doesn't support scene layers"); + return NULL; } - return NULL; } /* Base */ @@ -272,6 +323,114 @@ void BKE_view_layer_base_select(struct ViewLayer *view_layer, Base *selbase) } } +/****************************************************************************/ +/* Copying functions for datablocks that use ViewLayer/SceneCollection */ + +/* Find the equivalent SceneCollection in the new tree */ +static SceneCollection *scene_collection_from_new_tree( + SceneCollection *sc_reference, SceneCollection *sc_dst, SceneCollection *sc_src) +{ + if (sc_src == sc_reference) { + return sc_dst; + } + + for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first; + nsc_src; + nsc_src = nsc_src->next, nsc_dst = nsc_dst->next) + { + SceneCollection *found = scene_collection_from_new_tree(sc_reference, nsc_dst, nsc_src); + if (found != NULL) { + return found; + } + } + return NULL; +} + +static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *layer_collections_src) +{ + LayerCollection *layer_collection_dst = (LayerCollection *)layer_collections_dst->first; + const LayerCollection *layer_collection_src = (const LayerCollection *)layer_collections_src->first; + while (layer_collection_dst != NULL) { + layer_collection_dst->flag = layer_collection_src->flag; + + if (layer_collection_dst->properties != NULL) { + IDP_FreeProperty(layer_collection_dst->properties); + MEM_SAFE_FREE(layer_collection_dst->properties); + } + + if (layer_collection_src->properties != NULL) { + layer_collection_dst->properties = IDP_CopyProperty(layer_collection_src->properties); + } + + layer_collections_sync_flags(&layer_collection_dst->layer_collections, + &layer_collection_src->layer_collections); + + layer_collection_dst = layer_collection_dst->next; + layer_collection_src = layer_collection_src->next; + } +} + +/* recreate the LayerCollection tree */ +static void layer_collections_recreate( + ViewLayer *view_layer_dst, ListBase *lb_src, SceneCollection *mc_dst, SceneCollection *mc_src) +{ + for (LayerCollection *lc_src = lb_src->first; lc_src; lc_src = lc_src->next) { + SceneCollection *sc_dst = scene_collection_from_new_tree(lc_src->scene_collection, mc_dst, mc_src); + BLI_assert(sc_dst); + + /* instead of synchronizing both trees we simply re-create it */ + BKE_collection_link(view_layer_dst, sc_dst); + } +} + +/** + * Only copy internal data of ViewLayer from source to already allocated/initialized destination. + * + * \param mc_src Master Collection the source ViewLayer links in. + * \param mc_dst Master Collection the destination ViewLayer links in. + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_view_layer_copy_data( + ViewLayer *view_layer_dst, ViewLayer *view_layer_src, SceneCollection *mc_dst, SceneCollection *mc_src, + const int flag) +{ + IDPropertyTemplate val = {0}; + + if (view_layer_dst->id_properties != NULL) { + view_layer_dst->id_properties = IDP_CopyProperty_ex(view_layer_dst->id_properties, flag); + } + BKE_freestyle_config_copy(&view_layer_dst->freestyle_config, &view_layer_src->freestyle_config, flag); + + view_layer_dst->stats = NULL; + view_layer_dst->properties_evaluated = NULL; + view_layer_dst->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); + IDP_MergeGroup_ex(view_layer_dst->properties, view_layer_src->properties, true, flag); + + /* we start fresh with no overrides and no visibility flags set + * instead of syncing both trees we simply unlink and relink the scene collection */ + BLI_listbase_clear(&view_layer_dst->layer_collections); + BLI_listbase_clear(&view_layer_dst->object_bases); + BLI_listbase_clear(&view_layer_dst->drawdata); + + layer_collections_recreate(view_layer_dst, &view_layer_src->layer_collections, mc_dst, mc_src); + + /* Now we handle the syncing for visibility, selectability, ... */ + layer_collections_sync_flags(&view_layer_dst->layer_collections, &view_layer_src->layer_collections); + + Object *active_ob = OBACT(view_layer_src); + for (Base *base_src = view_layer_src->object_bases.first, *base_dst = view_layer_dst->object_bases.first; + base_src; + base_src = base_src->next, base_dst = base_dst->next) + { + base_dst->flag = base_src->flag; + base_dst->flag_legacy = base_src->flag_legacy; + + if (base_dst->object == active_ob) { + view_layer_dst->basact = base_dst; + } + } +} + static void view_layer_object_base_unref(ViewLayer *view_layer, Base *base) { base->refcount--; @@ -416,7 +575,7 @@ LayerCollection *BKE_layer_collection_get_active_ensure(Scene *scene, ViewLayer if (lc == NULL) { BLI_assert(BLI_listbase_is_empty(&view_layer->layer_collections)); /* When there is no collection linked to this ViewLayer, create one. */ - SceneCollection *sc = BKE_collection_add(scene, NULL, NULL); + SceneCollection *sc = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL); lc = BKE_collection_link(view_layer, sc); /* New collection has to be the active one. */ BLI_assert(lc == BKE_layer_collection_get_active(view_layer)); @@ -552,15 +711,15 @@ static void layer_collection_swap( } /** - * Move \a lc_src into \a lc_dst. Both have to be stored in \a sl. + * Move \a lc_src into \a lc_dst. Both have to be stored in \a view_layer. * If \a lc_src is directly linked to the ViewLayer it's unlinked */ -bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src) +bool BKE_layer_collection_move_into(const ID *owner_id, LayerCollection *lc_dst, LayerCollection *lc_src) { - ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc_src); + ViewLayer *view_layer = BKE_view_layer_find_from_collection(owner_id, lc_src); bool is_directly_linked = false; - if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(scene, lc_dst))) { + if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(owner_id, lc_dst))) { return false; } @@ -596,7 +755,7 @@ bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_dst, layer_collection_swap(view_layer, &view_layer->layer_collections, NULL, lc_temp, lc_src); } - if (!BKE_collection_move_into(scene, lc_dst->scene_collection, lc_src->scene_collection)) { + if (!BKE_collection_move_into(owner_id, lc_dst->scene_collection, lc_src->scene_collection)) { if (!is_directly_linked) { /* Swap back and remove */ layer_collection_swap(view_layer, NULL, NULL, lc_temp, lc_src); @@ -606,7 +765,8 @@ bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_dst, } } - LayerCollection *lc_new = BLI_findptr(&lc_dst->layer_collections, lc_src->scene_collection, offsetof(LayerCollection, scene_collection)); + LayerCollection *lc_new = BLI_findptr( + &lc_dst->layer_collections, lc_src->scene_collection, offsetof(LayerCollection, scene_collection)); BLI_assert(lc_new); layer_collection_swap(view_layer, &lc_dst->layer_collections, NULL, lc_new, lc_src); @@ -622,13 +782,13 @@ bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_dst, * Move \a lc_src above \a lc_dst. Both have to be stored in \a view_layer. * If \a lc_src is directly linked to the ViewLayer it's unlinked */ -bool BKE_layer_collection_move_above(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src) +bool BKE_layer_collection_move_above(const ID *owner_id, LayerCollection *lc_dst, LayerCollection *lc_src) { - ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc_src); + ViewLayer *view_layer = BKE_view_layer_find_from_collection(owner_id, lc_src); const bool is_directly_linked_src = BLI_findindex(&view_layer->layer_collections, lc_src) != -1; const bool is_directly_linked_dst = BLI_findindex(&view_layer->layer_collections, lc_dst) != -1; - if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(scene, lc_dst))) { + if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(owner_id, lc_dst))) { return false; } @@ -671,7 +831,7 @@ bool BKE_layer_collection_move_above(const Scene *scene, LayerCollection *lc_dst layer_collection_swap(view_layer, &view_layer->layer_collections, NULL, lc_temp, lc_src); } - if (!BKE_collection_move_above(scene, lc_dst->scene_collection, lc_src->scene_collection)) { + if (!BKE_collection_move_above(owner_id, lc_dst->scene_collection, lc_src->scene_collection)) { if (!is_directly_linked_src) { /* Swap back and remove */ layer_collection_swap(view_layer, NULL, NULL, lc_temp, lc_src); @@ -694,16 +854,16 @@ bool BKE_layer_collection_move_above(const Scene *scene, LayerCollection *lc_dst } /** - * Move \a lc_src below \a lc_dst. Both have to be stored in \a sl. + * Move \a lc_src below \a lc_dst. Both have to be stored in \a view_layer. * If \a lc_src is directly linked to the ViewLayer it's unlinked */ -bool BKE_layer_collection_move_below(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src) +bool BKE_layer_collection_move_below(const ID *owner_id, LayerCollection *lc_dst, LayerCollection *lc_src) { - ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc_src); + ViewLayer *view_layer = BKE_view_layer_find_from_collection(owner_id, lc_src); const bool is_directly_linked_src = BLI_findindex(&view_layer->layer_collections, lc_src) != -1; const bool is_directly_linked_dst = BLI_findindex(&view_layer->layer_collections, lc_dst) != -1; - if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(scene, lc_dst))) { + if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(owner_id, lc_dst))) { return false; } @@ -746,7 +906,7 @@ bool BKE_layer_collection_move_below(const Scene *scene, LayerCollection *lc_dst layer_collection_swap(view_layer, &view_layer->layer_collections, NULL, lc_temp, lc_src); } - if (!BKE_collection_move_below(scene, lc_dst->scene_collection, lc_src->scene_collection)) { + if (!BKE_collection_move_below(owner_id, lc_dst->scene_collection, lc_src->scene_collection)) { if (!is_directly_linked_src) { /* Swap back and remove */ layer_collection_swap(view_layer, NULL, NULL, lc_temp, lc_src); @@ -809,9 +969,9 @@ static bool layer_collection_resync(ViewLayer *view_layer, LayerCollection *lc, * Update the scene layers so that any LayerCollection that points * to \a sc is re-synced again */ -void BKE_layer_collection_resync(const Scene *scene, const SceneCollection *sc) +void BKE_layer_collection_resync(const ID *owner_id, const SceneCollection *sc) { - for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { layer_collection_resync(view_layer, lc, sc); } @@ -1025,9 +1185,9 @@ static LayerCollection *find_layer_collection_by_scene_collection(LayerCollectio /** * Add a new LayerCollection for all the ViewLayers that have sc_parent */ -void BKE_layer_sync_new_scene_collection(Scene *scene, const SceneCollection *sc_parent, SceneCollection *sc) +void BKE_layer_sync_new_scene_collection(ID *owner_id, const SceneCollection *sc_parent, SceneCollection *sc) { - for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { LayerCollection *lc_parent = find_layer_collection_by_scene_collection(lc, sc_parent); if (lc_parent) { @@ -1040,9 +1200,9 @@ void BKE_layer_sync_new_scene_collection(Scene *scene, const SceneCollection *sc /** * Add a corresponding ObjectBase to all the equivalent LayerCollection */ -void BKE_layer_sync_object_link(const Scene *scene, SceneCollection *sc, Object *ob) +void BKE_layer_sync_object_link(const ID *owner_id, SceneCollection *sc, Object *ob) { - for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc); if (found) { @@ -1056,9 +1216,9 @@ void BKE_layer_sync_object_link(const Scene *scene, SceneCollection *sc, Object * Remove the equivalent object base to all layers that have this collection * also remove all reference to ob in the filter_objects */ -void BKE_layer_sync_object_unlink(const Scene *scene, SceneCollection *sc, Object *ob) +void BKE_layer_sync_object_unlink(const ID *owner_id, SceneCollection *sc, Object *ob) { - for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc); if (found) { @@ -1074,9 +1234,9 @@ void BKE_layer_sync_object_unlink(const Scene *scene, SceneCollection *sc, Objec /** * Add a new datablock override */ -void BKE_override_view_layer_datablock_add(ViewLayer *view_layer, int id_type, const char *data_path, const ID *id) +void BKE_override_view_layer_datablock_add(ViewLayer *view_layer, int id_type, const char *data_path, const ID *owner_id) { - UNUSED_VARS(view_layer, id_type, data_path, id); + UNUSED_VARS(view_layer, id_type, data_path, owner_id); TODO_LAYER_OVERRIDE; } @@ -1934,32 +2094,43 @@ static void idproperty_reset(IDProperty **props, IDProperty *props_ref) } void BKE_layer_eval_layer_collection_pre(const struct EvaluationContext *UNUSED(eval_ctx), - Scene *scene, ViewLayer *view_layer) + ID *owner_id, ViewLayer *view_layer) { - DEBUG_PRINT("%s on scene:%s %s (%p)\n", __func__, scene->id.name, view_layer->name, view_layer); + DEBUG_PRINT("%s on %s (%p)\n", __func__, view_layer->name, view_layer); + Scene *scene = (GS(owner_id->name) == ID_SCE) ? (Scene *)owner_id : NULL; + for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED); - idproperty_reset(&base->collection_properties, scene->collection_properties); + idproperty_reset(&base->collection_properties, scene ? scene->collection_properties : NULL); } /* Sync properties from scene to scene layer. */ - idproperty_reset(&view_layer->properties_evaluated, scene->layer_properties); + idproperty_reset(&view_layer->properties_evaluated, scene ? scene->layer_properties : NULL); IDP_MergeGroup(view_layer->properties_evaluated, view_layer->properties, true); /* TODO(sergey): Is it always required? */ view_layer->flag |= VIEW_LAYER_ENGINE_DIRTY; } +static const char *collection_type_lookup[] = +{ + "None", /* COLLECTION_TYPE_NONE */ + "Group Internal", /* COLLECTION_TYPE_GROUP_INTERNAL */ +}; + void BKE_layer_eval_layer_collection(const struct EvaluationContext *UNUSED(eval_ctx), LayerCollection *layer_collection, LayerCollection *parent_layer_collection) { - DEBUG_PRINT("%s on %s (%p), parent %s (%p)\n", + DEBUG_PRINT("%s on %s (%p) [%s], parent %s (%p) [%s]\n", __func__, layer_collection->scene_collection->name, layer_collection->scene_collection, + collection_type_lookup[layer_collection->scene_collection->type], (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE", - (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL); + (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL, + (parent_layer_collection != NULL) ? collection_type_lookup[parent_layer_collection->scene_collection->type] : ""); + BLI_assert(layer_collection != parent_layer_collection); /* visibility */ layer_collection->flag_evaluated = layer_collection->flag; diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 99dd6f86549..0ef1fe52994 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -104,6 +104,7 @@ #include "BKE_lamp.h" #include "BKE_lattice.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" #include "BKE_linestyle.h" @@ -674,8 +675,12 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con /* Do not make new copy local in case we are copying outside of main... * XXX TODO: is this behavior OK, or should we need own flag to control that? */ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + BLI_assert((flag & LIB_ID_COPY_KEEP_LIB) == 0); BKE_id_copy_ensure_local(bmain, id, *r_newid); } + else { + (*r_newid)->lib = id->lib; + } return true; } @@ -689,6 +694,75 @@ bool id_copy(Main *bmain, const ID *id, ID **newid, bool test) return BKE_id_copy_ex(bmain, id, newid, 0, test); } +/** Does a mere memory swap over the whole IDs data (including type-specific memory). + * \note Most internal ID data itself is not swapped (only IDProperties are). */ +void BKE_id_swap(Main *bmain, ID *id_a, ID *id_b) +{ + BLI_assert(GS(id_a->name) == GS(id_b->name)); + + const ID id_a_back = *id_a; + const ID id_b_back = *id_b; + +#define CASE_SWAP(_gs, _type) \ + case _gs: \ + SWAP(_type, *(_type *)id_a, *(_type *)id_b); \ + break + + switch ((ID_Type)GS(id_a->name)) { + CASE_SWAP(ID_SCE, Scene); + CASE_SWAP(ID_LI, Library); + CASE_SWAP(ID_OB, Object); + CASE_SWAP(ID_ME, Mesh); + CASE_SWAP(ID_CU, Curve); + CASE_SWAP(ID_MB, MetaBall); + CASE_SWAP(ID_MA, Material); + CASE_SWAP(ID_TE, Tex); + CASE_SWAP(ID_IM, Image); + CASE_SWAP(ID_LT, Lattice); + CASE_SWAP(ID_LA, Lamp); + CASE_SWAP(ID_LP, LightProbe); + CASE_SWAP(ID_CA, Camera); + CASE_SWAP(ID_KE, Key); + CASE_SWAP(ID_WO, World); + CASE_SWAP(ID_SCR, bScreen); + CASE_SWAP(ID_VF, VFont); + CASE_SWAP(ID_TXT, Text); + CASE_SWAP(ID_SPK, Speaker); + CASE_SWAP(ID_SO, bSound); + CASE_SWAP(ID_GR, Group); + CASE_SWAP(ID_AR, bArmature); + CASE_SWAP(ID_AC, bAction); + CASE_SWAP(ID_NT, bNodeTree); + CASE_SWAP(ID_BR, Brush); + CASE_SWAP(ID_PA, ParticleSettings); + CASE_SWAP(ID_WM, wmWindowManager); + CASE_SWAP(ID_WS, WorkSpace); + CASE_SWAP(ID_GD, bGPdata); + CASE_SWAP(ID_MC, MovieClip); + CASE_SWAP(ID_MSK, Mask); + CASE_SWAP(ID_LS, FreestyleLineStyle); + CASE_SWAP(ID_PAL, Palette); + CASE_SWAP(ID_PC, PaintCurve); + CASE_SWAP(ID_CF, CacheFile); + case ID_IP: + break; /* Deprecated. */ + } + +#undef CASE_SWAP + + /* Restore original ID's internal data. */ + *id_a = id_a_back; + *id_b = id_b_back; + + /* Exception: IDProperties. */ + id_a->properties = id_b_back.properties; + id_b->properties = id_a_back.properties; + + /* Swap will have broken internal references to itself, restore them. */ + BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, false); + BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, false); +} + /** Does *not* set ID->newid pointer. */ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) { @@ -1342,6 +1416,15 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla new_id->properties = IDP_CopyProperty_ex(id->properties, flag); } + /* XXX Again... We need a way to control what we copy in a much more refined way. + * We cannot always copy this, some internal copying will die on it! */ + /* For now, upper level code will have to do that itself when required. */ +#if 0 + if (id->override != NULL) { + BKE_override_copy(new_id, id); + } +#endif + /* the duplicate should get a copy of the animdata */ id_copy_animdata(bmain, new_id, (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0); diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c new file mode 100644 index 00000000000..22896cff64a --- /dev/null +++ b/source/blender/blenkernel/intern/library_override.c @@ -0,0 +1,680 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Bastien Montagne. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/library_override.c + * \ingroup bke + */ + +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_ID.h" +#include "DNA_object_types.h" + +#include "DEG_depsgraph.h" +#include "BKE_library.h" +#include "BKE_library_override.h" +#include "BKE_library_remap.h" +#include "BKE_main.h" + +#include "BLI_utildefines.h" +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "RNA_access.h" +#include "RNA_types.h" + +#include "PIL_time.h" +#include "PIL_time_utildefines.h" + +#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */ + +static void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src); +static void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src); + +static void bke_override_property_clear(IDOverrideStaticProperty *op); +static void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop); + +/** Initialize empty overriding of \a reference_id by \a local_id. */ +IDOverrideStatic *BKE_override_static_init(ID *local_id, ID *reference_id) +{ + /* If reference_id is NULL, we are creating an override template for purely local data. + * Else, reference *must* be linked data. */ + BLI_assert(reference_id == NULL || reference_id->lib != NULL); + BLI_assert(local_id->override_static == NULL); + + if (reference_id != NULL && reference_id->override_static != NULL && reference_id->override_static->reference == NULL) { + /* reference ID has an override template, use it! */ + BKE_override_static_copy(local_id, reference_id); + return local_id->override_static; + } + + /* Else, generate new empty override. */ + local_id->override_static = MEM_callocN(sizeof(*local_id->override_static), __func__); + local_id->override_static->reference = reference_id; + id_us_plus(reference_id); + local_id->tag &= ~LIB_TAG_OVERRIDESTATIC_OK; + /* TODO do we want to add tag or flag to referee to mark it as such? */ + return local_id->override_static; +} + +/** Deep copy of a whole override from \a src_id to \a dst_id. */ +void BKE_override_static_copy(ID *dst_id, const ID *src_id) +{ + BLI_assert(src_id->override_static != NULL); + + if (dst_id->override_static != NULL) { + if (src_id->override_static == NULL) { + BKE_override_static_free(&dst_id->override_static); + return; + } + else { + BKE_override_static_clear(dst_id->override_static); + } + } + else if (src_id->override_static == NULL) { + return; + } + else { + BKE_override_static_init(dst_id, NULL); + } + + /* Source is already overriding data, we copy it but reuse its reference for dest ID. + * otherwise, source is only an override template, it then becomes reference of dest ID. */ + dst_id->override_static->reference = src_id->override_static->reference ? src_id->override_static->reference : (ID *)src_id; + id_us_plus(dst_id->override_static->reference); + + BLI_duplicatelist(&dst_id->override_static->properties, &src_id->override_static->properties); + for (IDOverrideStaticProperty *op_dst = dst_id->override_static->properties.first, *op_src = src_id->override_static->properties.first; + op_dst; + op_dst = op_dst->next, op_src = op_src->next) + { + bke_override_property_copy(op_dst, op_src); + } + + dst_id->tag &= ~LIB_TAG_OVERRIDESTATIC_OK; +} + +/** Clear any overriding data from given \a override. */ +void BKE_override_static_clear(IDOverrideStatic *override) +{ + BLI_assert(override != NULL); + + for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) { + bke_override_property_clear(op); + } + BLI_freelistN(&override->properties); + + id_us_min(override->reference); + /* override->storage should never be refcounted... */ +} + +/** Free given \a override. */ +void BKE_override_static_free(struct IDOverrideStatic **override) +{ + BLI_assert(*override != NULL); + + BKE_override_static_clear(*override); + MEM_freeN(*override); + *override = NULL; +} + +/** Create an overriden local copy of linked reference. */ +ID *BKE_override_static_create_from(Main *bmain, ID *reference_id) +{ + BLI_assert(reference_id != NULL); + BLI_assert(reference_id->lib != NULL); + + ID *local_id; + + if (!id_copy(bmain, reference_id, (ID **)&local_id, false)) { + return NULL; + } + id_us_min(local_id); + + BKE_override_static_init(local_id, reference_id); + local_id->flag |= LIB_OVERRIDE_STATIC_AUTO; + + /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overriden ID). */ + BKE_libblock_remap(bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE); + + return local_id; +} + +/** + * Find override property from given RNA path, if it exists. + */ +IDOverrideStaticProperty *BKE_override_static_property_find(IDOverrideStatic *override, const char *rna_path) +{ + /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */ + return BLI_findstring_ptr(&override->properties, rna_path, offsetof(IDOverrideStaticProperty, rna_path)); +} + +/** + * Find override property from given RNA path, or create it if it does not exist. + */ +IDOverrideStaticProperty *BKE_override_static_property_get(IDOverrideStatic *override, const char *rna_path, bool *r_created) +{ + /* XXX TODO we'll most likely want a runtime ghash to store taht mapping at some point. */ + IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path); + + if (op == NULL) { + op = MEM_callocN(sizeof(IDOverrideStaticProperty), __func__); + op->rna_path = BLI_strdup(rna_path); + BLI_addtail(&override->properties, op); + + if (r_created) { + *r_created = true; + } + } + else if (r_created) { + *r_created = false; + } + + return op; +} + +void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src) +{ + op_dst->rna_path = BLI_strdup(op_src->rna_path); + BLI_duplicatelist(&op_dst->operations, &op_src->operations); + + for (IDOverrideStaticPropertyOperation *opop_dst = op_dst->operations.first, *opop_src = op_src->operations.first; + opop_dst; + opop_dst = opop_dst->next, opop_src = opop_src->next) + { + bke_override_property_operation_copy(opop_dst, opop_src); + } +} + +void bke_override_property_clear(IDOverrideStaticProperty *op) +{ + BLI_assert(op->rna_path != NULL); + + MEM_freeN(op->rna_path); + + for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) { + bke_override_property_operation_clear(opop); + } + BLI_freelistN(&op->operations); +} + +/** + * Remove and free given \a override_property from given ID \a override. + */ +void BKE_override_static_property_delete(IDOverrideStatic *override, IDOverrideStaticProperty *override_property) +{ + bke_override_property_clear(override_property); + BLI_freelinkN(&override->properties, override_property); +} + +/** + * Find override property operation from given sub-item(s), if it exists. + */ +IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find( + IDOverrideStaticProperty *override_property, + const char *subitem_refname, const char *subitem_locname, + const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict) +{ + IDOverrideStaticPropertyOperation *opop; + const int subitem_defindex = -1; + + if (r_strict) { + *r_strict = true; + } + + if (subitem_locname && + (opop = BLI_findstring_ptr(&override_property->operations, subitem_locname, + offsetof(IDOverrideStaticPropertyOperation, subitem_local_name)))) + { + return opop; + } + + if (subitem_refname && + (opop = BLI_findstring_ptr(&override_property->operations, subitem_refname, + offsetof(IDOverrideStaticPropertyOperation, subitem_reference_name)))) + { + return opop; + } + + if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_locindex, sizeof(subitem_locindex), + offsetof(IDOverrideStaticPropertyOperation, subitem_local_index)))) + { + return opop; + } + + if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_refindex, sizeof(subitem_refindex), + offsetof(IDOverrideStaticPropertyOperation, subitem_reference_index)))) + { + return opop; + } + + /* index == -1 means all indices, that is valid fallback in case we requested specific index. */ + if (!strict && (subitem_locindex != subitem_defindex) && + (opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_defindex, sizeof(subitem_defindex), + offsetof(IDOverrideStaticPropertyOperation, subitem_local_index)))) + { + if (r_strict) { + *r_strict = false; + } + return opop; + } + + return NULL; +} + +/** + * Find override property operation from given sub-item(s), or create it if it does not exist. + */ +IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get( + IDOverrideStaticProperty *override_property, const short operation, + const char *subitem_refname, const char *subitem_locname, + const int subitem_refindex, const int subitem_locindex, + const bool strict, bool *r_strict, bool *r_created) +{ + IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(override_property, + subitem_refname, subitem_locname, + subitem_refindex, subitem_locindex, + strict, r_strict); + + if (opop == NULL) { + opop = MEM_callocN(sizeof(IDOverrideStaticPropertyOperation), __func__); + opop->operation = operation; + if (subitem_locname) { + opop->subitem_local_name = BLI_strdup(subitem_locname); + } + if (subitem_refname) { + opop->subitem_reference_name = BLI_strdup(subitem_refname); + } + opop->subitem_local_index = subitem_locindex; + opop->subitem_reference_index = subitem_refindex; + + BLI_addtail(&override_property->operations, opop); + + if (r_created) { + *r_created = true; + } + } + else if (r_created) { + *r_created = false; + } + + return opop; +} + +void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src) +{ + if (opop_src->subitem_reference_name) { + opop_dst->subitem_reference_name = BLI_strdup(opop_src->subitem_reference_name); + } + if (opop_src->subitem_local_name) { + opop_dst->subitem_local_name = BLI_strdup(opop_src->subitem_local_name); + } +} + +void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop) +{ + if (opop->subitem_reference_name) { + MEM_freeN(opop->subitem_reference_name); + } + if (opop->subitem_local_name) { + MEM_freeN(opop->subitem_local_name); + } +} + +/** + * Remove and free given \a override_property_operation from given ID \a override_property. + */ +void BKE_override_static_property_operation_delete( + IDOverrideStaticProperty *override_property, IDOverrideStaticPropertyOperation *override_property_operation) +{ + bke_override_property_operation_clear(override_property_operation); + BLI_freelinkN(&override_property->operations, override_property_operation); +} + +/** + * Check that status of local data-block is still valid against current reference one. + * + * It means that all overridable, but not overridden, properties' local values must be equal to reference ones. + * Clears LIB_TAG_OVERRIDE_OK if they do not. + * + * This is typically used to detect whether some property has been changed in local and a new IDOverrideProperty + * (of IDOverridePropertyOperation) has to be added. + * + * \return true if status is OK, false otherwise. */ +bool BKE_override_static_status_check_local(ID *local) +{ + BLI_assert(local->override_static != NULL); + + ID *reference = local->override_static->reference; + + if (reference == NULL) { + /* This is an override template, local status is always OK! */ + return true; + } + + BLI_assert(GS(local->name) == GS(reference->name)); + + /* Note that reference is assumed always valid, caller has to ensure that itself. */ + + PointerRNA rnaptr_local, rnaptr_reference; + RNA_id_pointer_create(local, &rnaptr_local); + RNA_id_pointer_create(reference, &rnaptr_reference); + + if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, true, true)) { + local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK; + return false; + } + + return true; +} + +/** + * Check that status of reference data-block is still valid against current local one. + * + * It means that all non-overridden properties' local values must be equal to reference ones. + * Clears LIB_TAG_OVERRIDE_OK if they do not. + * + * This is typically used to detect whether some reference has changed and local needs to be updated against it. + * + * \return true if status is OK, false otherwise. */ +bool BKE_override_static_status_check_reference(ID *local) +{ + BLI_assert(local->override_static != NULL); + + ID *reference = local->override_static->reference; + + if (reference == NULL) { + /* This is an override template, reference is virtual, so its status is always OK! */ + return true; + } + + BLI_assert(GS(local->name) == GS(reference->name)); + + if (reference->override_static && (reference->tag & LIB_TAG_OVERRIDESTATIC_OK) == 0) { + if (!BKE_override_static_status_check_reference(reference)) { + /* If reference is also override of another data-block, and its status is not OK, + * then this override is not OK either. + * Note that this should only happen when reloading libraries... */ + local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK; + return false; + } + } + + PointerRNA rnaptr_local, rnaptr_reference; + RNA_id_pointer_create(local, &rnaptr_local); + RNA_id_pointer_create(reference, &rnaptr_reference); + + if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, false, true)) { + local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK; + return false; + } + + return true; +} + +/** + * Compares local and reference data-blocks and create new override operations as needed, + * or reset to reference values if overriding is not allowed. + * + * \note Defining override operations is only mandatory before saving a .blend file on disk (not for undo!). + * Knowing that info at runtime is only useful for UI/UX feedback. + * + * \note This is by far the biggest operation (the more time-consuming) of the three so far, since it has to go over + * all properties in depth (all overridable ones at least). Generating diff values and applying overrides + * are much cheaper. + * + * \return true is new overriding op was created, or some local data was reset. */ +bool BKE_override_static_operations_create(ID *local) +{ + BLI_assert(local->override_static != NULL); + const bool is_template = (local->override_static->reference == NULL); + bool ret = false; + + if (!is_template && local->flag & LIB_OVERRIDE_STATIC_AUTO) { + PointerRNA rnaptr_local, rnaptr_reference; + RNA_id_pointer_create(local, &rnaptr_local); + RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference); + + ret = RNA_struct_auto_override(&rnaptr_local, &rnaptr_reference, local->override_static, NULL); +#ifndef NDEBUG + if (ret) { + printf("We did generate static override rules for %s\n", local->name); + } + else { + printf("No new static override rules for %s\n", local->name); + } +#endif + } + return ret; +} + +/** Check all overrides from given \a bmain and create/update overriding operations as needed. */ +void BKE_main_override_static_operations_create(Main *bmain) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int base_count, i; + + base_count = set_listbasepointers(bmain, lbarray); + + for (i = 0; i < base_count; i++) { + ListBase *lb = lbarray[i]; + ID *id; + + for (id = lb->first; id; id = id->next) { + /* TODO Maybe we could also add an 'override update' tag e.g. when tagging for DEG update? */ + if (id->lib == NULL && id->override_static != NULL && id->override_static->reference != NULL && (id->flag & LIB_OVERRIDE_STATIC_AUTO)) { + BKE_override_static_operations_create(id); + } + } + } +} + +/** Update given override from its reference (re-applying overriden properties). */ +void BKE_override_static_update(Main *bmain, ID *local) +{ + if (local->override_static == NULL || local->override_static->reference == NULL) { + return; + } + + /* Recursively do 'ancestors' overrides first, if any. */ + if (local->override_static->reference->override_static && (local->override_static->reference->tag & LIB_TAG_OVERRIDESTATIC_OK) == 0) { + BKE_override_static_update(bmain, local->override_static->reference); + } + + /* We want to avoid having to remap here, however creating up-to-date override is much simpler if based + * on reference than on current override. + * So we work on temp copy of reference, and 'swap' its content with local. */ + + /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)! + * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will do, + * as innefficient as it is. :/ + * Actually, maybe not! Since we are swapping with original ID's local content, we want to keep + * usercount in correct state when freeing tmp_id (and that usercounts of IDs used by 'new' local data + * also remain correct). */ + /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code). + * Not impossible to do, but would rather see first if extra useless usual user handling is actually + * a (performances) issue here. */ + + ID *tmp_id; + id_copy(bmain, local->override_static->reference, &tmp_id, false); + + if (tmp_id == NULL) { + return; + } + + PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL; + RNA_id_pointer_create(local, &rnaptr_src); + RNA_id_pointer_create(tmp_id, &rnaptr_dst); + if (local->override_static->storage) { + rnaptr_storage = &rnaptr_storage_stack; + RNA_id_pointer_create(local->override_static->storage, rnaptr_storage); + } + + RNA_struct_override_apply(&rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_static); + + /* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. So when we'll free tmp_id, + * we'll actually free old, outdated data from local. */ + BKE_id_swap(bmain, local, tmp_id); + + /* Again, horribly innefficient in our case, we need something off-Main (aka moar generic nolib copy/free stuff)! */ + /* XXX And crashing in complex cases (e.g. because depsgraph uses same data...). */ + BKE_libblock_free_ex(bmain, tmp_id, true, false); + + if (local->override_static->storage) { + /* We know this datablock is not used anywhere besides local->override->storage. */ + /* XXX For until we get fully shadow copies, we still need to ensure storage releases + * its usage of any ID pointers it may have. */ + BKE_libblock_free_ex(bmain, local->override_static->storage, true, false); + local->override_static->storage = NULL; + } + + local->tag |= LIB_TAG_OVERRIDESTATIC_OK; + + /* Full rebuild of Depsgraph! */ + DEG_on_visible_update(bmain, true); /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */ +} + +/** Update all overrides from given \a bmain. */ +void BKE_main_override_static_update(Main *bmain) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int base_count, i; + + base_count = set_listbasepointers(bmain, lbarray); + + for (i = 0; i < base_count; i++) { + ListBase *lb = lbarray[i]; + ID *id; + + for (id = lb->first; id; id = id->next) { + if (id->override_static != NULL && id->lib == NULL) { + BKE_override_static_update(bmain, id); + } + } + } +} + +/*********************************************************************************************************************** + * Storage (how to wtore overriding data into .blend files). + * + * Basically: + * I) Only 'differential' storage needs special handling here. All others (replacing values or + * inserting/removing items from a collection) can be handled with simply storing current content of local data-block. + * II) We store the differential value into a second 'ghost' data-block, which is an empty ID of same type as local one, + * where we only define values that need differential data. + * + * This avoids us having to modify 'real' data-block at write time (and retoring it afterwards), which is inneficient, + * and potentially dangerous (in case of concurrent access...), while not using much extra memory in typical cases. + * It also ensures stored data-block always contains exact same data as "desired" ones (kind of "baked" data-blocks). + */ + +/** Initialize an override storage. */ +OverrideStaticStorage *BKE_override_static_operations_store_initialize(void) +{ + return BKE_main_new(); +} + +/** + * Generate suitable 'write' data (this only affects differential override operations). + * + * Note that \a local ID is no more modified by this call, all extra data are stored in its temp \a storage_id copy. */ +ID *BKE_override_static_operations_store_start(OverrideStaticStorage *override_storage, ID *local) +{ + BLI_assert(local->override_static != NULL); + BLI_assert(override_storage != NULL); + const bool is_template = (local->override_static->reference == NULL); + + if (is_template) { + /* This is actually purely local data with an override template, nothing to do here! */ + return NULL; + } + + /* Forcefully ensure we know about all needed override operations. */ + BKE_override_static_operations_create(local); + + ID *storage_id; +#ifdef DEBUG_OVERRIDE_TIMEIT + TIMEIT_START_AVERAGED(BKE_override_operations_store_start); +#endif + + /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy never-overridable + * data (like Mesh geometry etc.)? And also maybe avoid lib refcounting completely (shallow copy...). */ + /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code). + * Not impossible to do, but would rather see first is extra useless usual user handling is actually + * a (performances) issue here, before doing it. */ + id_copy((Main *)override_storage, local, &storage_id, false); + + if (storage_id != NULL) { + PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage; + RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference); + RNA_id_pointer_create(local, &rnaptr_final); + RNA_id_pointer_create(storage_id, &rnaptr_storage); + + if (!RNA_struct_override_store(&rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static)) { + BKE_libblock_free_ex(override_storage, storage_id, true, false); + storage_id = NULL; + } + } + + local->override_static->storage = storage_id; + +#ifdef DEBUG_OVERRIDE_TIMEIT + TIMEIT_END_AVERAGED(BKE_override_operations_store_start); +#endif + return storage_id; +} + +/** Restore given ID modified by \a BKE_override_operations_store_start, to its original state. */ +void BKE_override_static_operations_store_end(OverrideStaticStorage *UNUSED(override_storage), ID *local) +{ + BLI_assert(local->override_static != NULL); + + /* Nothing else to do here really, we need to keep all temp override storage data-blocks in memory until + * whole file is written anyway (otherwise we'd get mem pointers overlap...). */ + local->override_static->storage = NULL; +} + +void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage) +{ + /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' copies of IDs + * without increasing usercount of used data-blocks... */ + ListBase *lbarray[MAX_LIBARRAY]; + int base_count, i; + + base_count = set_listbasepointers(override_storage, lbarray); + + for (i = 0; i < base_count; i++) { + ListBase *lb = lbarray[i]; + ID *id; + + while ((id = lb->first)) { + BKE_libblock_free_ex(override_storage, id, true, false); + } + } + + BKE_main_free(override_storage); +} diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 93bc4be7954..e25a354c8af 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -75,6 +75,7 @@ #include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_fcurve.h" +#include "BKE_group.h" #include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -373,6 +374,10 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call #define CALLBACK_INVOKE(check_id_super, cb_flag) \ FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag) + if (id->override_static != NULL) { + CALLBACK_INVOKE_ID(id->override_static->reference, IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE); + } + for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) { data.self_id = id; data.cb_flag = ID_IS_LINKED(id) ? IDWALK_CB_INDIRECT_USAGE : 0; @@ -768,10 +773,11 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call case ID_GR: { Group *group = (Group *) id; - GroupObject *gob; - for (gob = group->gobject.first; gob; gob = gob->next) { - CALLBACK_INVOKE(gob->ob, IDWALK_CB_USER_ONE); + FOREACH_GROUP_OBJECT(group, object) + { + CALLBACK_INVOKE(object, IDWALK_CB_USER_ONE); } + FOREACH_GROUP_OBJECT_END break; } diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index e897f3c5330..fb672cb8b9f 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -87,6 +87,7 @@ #include "BKE_lattice.h" #include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" #include "BKE_linestyle.h" @@ -181,6 +182,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id } if (*id_p && (*id_p == old_id)) { + const bool is_reference = (cb_flag & IDWALK_CB_STATIC_OVERRIDE_REFERENCE) != 0; const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0; const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct, @@ -191,6 +193,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id)); const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) && (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); + const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_STATIC_OVERRIDE) != 0; const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0; #ifdef DEBUG_PRINT @@ -205,7 +208,8 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */ if ((is_never_null && skip_never_null) || (is_obj_editmode && (((Object *)id)->data == *id_p)) || - (skip_indirect && is_indirect)) + (skip_indirect && is_indirect) || + (is_reference && skip_reference)) { if (is_indirect) { id_remap_data->skipped_indirect++; @@ -218,7 +222,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id } } } - else if (is_never_null || is_obj_editmode) { + else if (is_never_null || is_obj_editmode || is_reference) { id_remap_data->skipped_direct++; } else { @@ -266,7 +270,7 @@ static void libblock_remap_data_preprocess_scene_object_unlink( r_id_remap_data->skipped_refcounted++; } else { - BKE_collections_object_remove(r_id_remap_data->bmain, sce, ob, false); + BKE_collections_object_remove(r_id_remap_data->bmain, &sce->id, ob, false); if (!is_indirect) { r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; } @@ -742,6 +746,10 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user) MEM_freeN(id->properties); } + if (id->override_static) { + BKE_override_static_free(&id->override_static); + } + /* XXX TODO remove animdata handling from each type's freeing func, and do it here, like for copy! */ } diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c index 03bd2344f7b..d5dbbe873a2 100644 --- a/source/blender/blenkernel/intern/lightprobe.c +++ b/source/blender/blenkernel/intern/lightprobe.c @@ -50,6 +50,8 @@ void BKE_lightprobe_init(LightProbe *probe) probe->falloff = 0.2f; probe->clipsta = 0.8f; probe->clipend = 40.0f; + probe->vis_bias = 1.0f; + probe->vis_blur = 0.2f; probe->data_draw_size = 1.0f; probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE | LIGHTPROBE_FLAG_SHOW_DATA; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 8fa4ebb8b3c..bea9e3bdcac 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -467,8 +467,6 @@ void BKE_object_free(Object *ob) } BLI_freelistN(&ob->drawdata); - ob->deg_update_flag = 0; - BKE_sculptsession_free(ob); BLI_freelistN(&ob->pc_ids); @@ -706,6 +704,9 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) ob = BKE_libblock_alloc(bmain, ID_OB, name, 0); + /* We increase object user count when linking to SceneCollections. */ + id_us_min(&ob->id); + /* default object vars */ ob->type = type; @@ -745,7 +746,7 @@ Object *BKE_object_add( ob = object_add_common(bmain, view_layer, type, name); layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer); - BKE_collection_object_add(scene, layer_collection->scene_collection, ob); + BKE_collection_object_add(&scene->id, layer_collection->scene_collection, ob); base = BKE_view_layer_base_find(view_layer, ob); BKE_view_layer_base_select(view_layer, base); @@ -2663,6 +2664,28 @@ bool BKE_object_parent_loop_check(const Object *par, const Object *ob) return BKE_object_parent_loop_check(par->parent, ob); } +static void object_handle_update_proxy(const EvaluationContext *eval_ctx, + Scene *scene, + Object *object, + const bool do_proxy_update) +{ + /* The case when this is a group proxy, object_update is called in group.c */ + if (object->proxy == NULL) { + return; + } + /* set pointer in library proxy target, for copying, but restore it */ + object->proxy->proxy_from = object; + // printf("set proxy pointer for later group stuff %s\n", ob->id.name); + + /* the no-group proxy case, we call update */ + if (object->proxy_group == NULL) { + if (do_proxy_update) { + // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name); + BKE_object_handle_update(eval_ctx, scene, object->proxy); + } + } +} + /* proxy rule: lib_object->proxy_from == the one we borrow from, only set temporal and cleared here */ /* local_object->proxy == pointer to library object, saved in files and read */ @@ -2676,75 +2699,51 @@ void BKE_object_handle_update_ex(const EvaluationContext *eval_ctx, RigidBodyWorld *rbw, const bool do_proxy_update) { - if (ob->recalc & OB_RECALC_ALL) { - /* speed optimization for animation lookups */ - if (ob->pose) { - BKE_pose_channels_hash_make(ob->pose); - if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(ob->pose); - } + const bool recalc_object = (ob->id.tag & LIB_TAG_ID_RECALC) != 0; + const bool recalc_data = (ob->id.tag & LIB_TAG_ID_RECALC_DATA) != 0; + if (!recalc_object && ! recalc_data) { + object_handle_update_proxy(eval_ctx, scene, ob, do_proxy_update); + return; + } + /* Speed optimization for animation lookups. */ + if (ob->pose != NULL) { + BKE_pose_channels_hash_make(ob->pose); + if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(ob->pose); } - - if (ob->recalc & OB_RECALC_DATA) { - if (ob->type == OB_ARMATURE) { - /* this happens for reading old files and to match library armatures - * with poses we do it ahead of BKE_object_where_is_calc to ensure animation - * is evaluated on the rebuilt pose, otherwise we get incorrect poses - * on file load */ - if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) - BKE_pose_rebuild(ob, ob->data); - } + } + if (recalc_data) { + if (ob->type == OB_ARMATURE) { + /* this happens for reading old files and to match library armatures + * with poses we do it ahead of BKE_object_where_is_calc to ensure animation + * is evaluated on the rebuilt pose, otherwise we get incorrect poses + * on file load */ + if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) + BKE_pose_rebuild(ob, ob->data); } - - /* XXX new animsys warning: depsgraph tag OB_RECALC_DATA should not skip drivers, - * which is only in BKE_object_where_is_calc now */ - /* XXX: should this case be OB_RECALC_OB instead? */ - if (ob->recalc & OB_RECALC_ALL) { - - if (G.debug & G_DEBUG_DEPSGRAPH) - printf("recalcob %s\n", ob->id.name + 2); - - /* handle proxy copy for target */ - if (ID_IS_LINKED(ob) && ob->proxy_from) { - // printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name); - if (ob->proxy_from->proxy_group) { /* transform proxy into group space */ - Object *obg = ob->proxy_from->proxy_group; - float imat[4][4]; - invert_m4_m4(imat, obg->obmat); - mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat); - if (obg->dup_group) { /* should always be true */ - add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs); - } - } - else - copy_m4_m4(ob->obmat, ob->proxy_from->obmat); - } - else - BKE_object_where_is_calc_ex(eval_ctx, scene, rbw, ob, NULL); + } + /* XXX new animsys warning: depsgraph tag OB_RECALC_DATA should not skip drivers, + * which is only in BKE_object_where_is_calc now */ + /* XXX: should this case be OB_RECALC_OB instead? */ + if (recalc_object || recalc_data) { + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("recalcob %s\n", ob->id.name + 2); } - - if (ob->recalc & OB_RECALC_DATA) { - BKE_object_handle_data_update(eval_ctx, scene, ob); + /* Handle proxy copy for target. */ + if (!BKE_object_eval_proxy_copy(eval_ctx, ob)) { + BKE_object_where_is_calc_ex(eval_ctx, scene, rbw, ob, NULL); } + } - ob->recalc &= ~OB_RECALC_ALL; + if (recalc_data) { + BKE_object_handle_data_update(eval_ctx, scene, ob); } - /* the case when this is a group proxy, object_update is called in group.c */ - if (ob->proxy) { - /* set pointer in library proxy target, for copying, but restore it */ - ob->proxy->proxy_from = ob; - // printf("set proxy pointer for later group stuff %s\n", ob->id.name); + ob->id.tag &= ~LIB_TAG_ID_RECALC_ALL; - /* the no-group proxy case, we call update */ - if (ob->proxy_group == NULL) { - if (do_proxy_update) { - // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name); - BKE_object_handle_update(eval_ctx, scene, ob->proxy); - } - } - } + object_handle_update_proxy(eval_ctx, scene, ob, do_proxy_update); } + /* WARNING: "scene" here may not be the scene object actually resides in. * When dealing with background-sets, "scene" is actually the active scene. * e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n @@ -3722,7 +3721,8 @@ bool BKE_object_modifier_update_subframe( } /* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */ - ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME; + /* TODO(sergey): What about animation? */ + ob->id.tag |= LIB_TAG_ID_RECALC_ALL; BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM); if (update_mesh) { /* ignore cache clear during subframe updates diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 85635cb7d77..a16acd9d564 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -50,8 +50,9 @@ #include "BKE_animsys.h" #include "BKE_DerivedMesh.h" #include "BKE_font.h" -#include "BKE_group.h" #include "BKE_global.h" +#include "BKE_group.h" +#include "BKE_idprop.h" #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_mesh.h" @@ -143,7 +144,8 @@ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Obj */ static DupliObject *make_dupli(const DupliContext *ctx, Object *ob, float mat[4][4], int index, - bool animated, bool hide) + bool animated, bool hide, + IDProperty *collection_properties) { DupliObject *dob; int i; @@ -198,6 +200,10 @@ static DupliObject *make_dupli(const DupliContext *ctx, dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2)); } + if (collection_properties) { + dob->collection_properties = IDP_CopyProperty(collection_properties); + } + return dob; } @@ -238,23 +244,23 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild Object *obedit = ctx->scene->obedit; if (ctx->group) { - unsigned int lay = ctx->group->layer; int groupid = 0; - GroupObject *go; - for (go = ctx->group->gobject.first; go; go = go->next, groupid++) { - Object *ob = go->ob; - - if ((ob->lay & lay) && ob != obedit && is_child(ob, parent)) { + FOREACH_GROUP_BASE(ctx->group, base) + { + Object *ob = base->object; + if ((base->flag & BASE_VISIBLED) && ob != obedit && is_child(ob, parent)) { DupliContext pctx; copy_dupli_context(&pctx, ctx, ctx->object, NULL, groupid, false); /* mballs have a different dupli handling */ - if (ob->type != OB_MBALL) + if (ob->type != OB_MBALL) { ob->flag |= OB_DONE; /* doesnt render */ - + } make_child_duplis_cb(&pctx, userdata, ob); } + groupid++; } + FOREACH_GROUP_BASE_END } else { int baseid = 0; @@ -281,13 +287,12 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild /* OB_DUPLIGROUP */ static void make_duplis_group(const DupliContext *ctx) { - bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER); Object *ob = ctx->object; Group *group; - GroupObject *go; + Base *base; float group_mat[4][4]; int id; - bool animated, hide; + bool animated; if (ob->dup_group == NULL) return; group = ob->dup_group; @@ -309,34 +314,18 @@ static void make_duplis_group(const DupliContext *ctx) animated = BKE_group_is_animated(group, ob); - for (go = group->gobject.first, id = 0; go; go = go->next, id++) { - /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ - if (go->ob != ob) { + for (base = group->view_layer->object_bases.first, id = 0; base; base = base->next, id++) { + if (base->object != ob && (base->flag & BASE_VISIBLED)) { float mat[4][4]; - /* Special case for instancing dupli-groups, see: T40051 - * this object may be instanced via dupli-verts/faces, in this case we don't want to render - * (blender convention), but _do_ show in the viewport. - * - * Regular objects work fine but not if we're instancing dupli-groups, - * because the rules for rendering aren't applied to objects they instance. - * We could recursively pass down the 'hide' flag instead, but that seems unnecessary. - */ - if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) { - continue; - } - /* group dupli offset, should apply after everything else */ - mul_m4_m4m4(mat, group_mat, go->ob->obmat); + mul_m4_m4m4(mat, group_mat, base->object->obmat); - /* check the group instance and object layers match, also that the object visible flags are ok. */ - hide = (go->ob->lay & group->layer) == 0 || - (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW); - - make_dupli(ctx, go->ob, mat, id, animated, hide); + BLI_assert(base->collection_properties != NULL); + make_dupli(ctx, base->object, mat, id, animated, false, base->collection_properties); /* recursion */ - make_recursive_duplis(ctx, go->ob, group_mat, id, animated); + make_recursive_duplis(ctx, base->object, group_mat, id, animated); } } } @@ -399,7 +388,7 @@ static void make_duplis_frames(const DupliContext *ctx) BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ BKE_object_where_is_calc_time(ctx->eval_ctx, scene, ob, (float)scene->r.cfra); - make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false); + make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false, NULL); } } @@ -484,7 +473,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], */ mul_m4_m4m4(space_mat, obmat, inst_ob->imat); - dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false); + dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false, NULL); if (vdd->orco) copy_v3_v3(dob->orco, vdd->orco[index]); @@ -669,7 +658,7 @@ static void make_duplis_font(const DupliContext *ctx) copy_v3_v3(obmat[3], vec); - make_dupli(ctx, ob, obmat, a, false, false); + make_dupli(ctx, ob, obmat, a, false, false, NULL); } } @@ -775,7 +764,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj */ mul_m4_m4m4(space_mat, obmat, inst_ob->imat); - dob = make_dupli(ctx, inst_ob, obmat, a, false, false); + dob = make_dupli(ctx, inst_ob, obmat, a, false, false, NULL); if (use_texcoords) { float w = 1.0f / (float)mp->totloop; @@ -858,7 +847,6 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER; bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); - GroupObject *go; Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; DupliObject *dob; ParticleDupliWeight *dw; @@ -912,10 +900,10 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem return; } else { /*PART_DRAW_GR */ - if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->gobject)) + if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->view_layer->object_bases)) return; - if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) { + if (BLI_findptr(&part->dup_group->view_layer->object_bases, par, offsetof(Base, object))) { return; } } @@ -947,8 +935,12 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem totgroup += dw->count; } else { - for (go = part->dup_group->gobject.first; go; go = go->next) + FOREACH_GROUP_OBJECT(part->dup_group, object) + { + (void) object; totgroup++; + } + FOREACH_GROUP_OBJECT_END } /* we also copy the actual objects to restore afterwards, since @@ -967,11 +959,18 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem } } else { - go = part->dup_group->gobject.first; - for (a = 0; a < totgroup; a++, go = go->next) { - oblist[a] = go->ob; - obcopylist[a] = *go->ob; + a = 0; + FOREACH_GROUP_OBJECT(part->dup_group, object) + { + oblist[a] = object; + obcopylist[a] = *object; + a++; + + if (a >= totgroup) { + continue; + } } + FOREACH_GROUP_OBJECT_END } } else { @@ -1060,23 +1059,33 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem } if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { - for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) { - + b = 0; + FOREACH_GROUP_OBJECT(part->dup_group, object) + { copy_m4_m4(tmat, oblist[b]->obmat); + /* apply particle scale */ mul_mat3_m4_fl(tmat, size * scale); mul_v3_fl(tmat[3], size * scale); + /* group dupli offset, should apply after everything else */ - if (!is_zero_v3(part->dup_group->dupli_ofs)) + if (!is_zero_v3(part->dup_group->dupli_ofs)) { sub_v3_v3(tmat[3], part->dup_group->dupli_ofs); + } + /* individual particle transform */ mul_m4_m4m4(mat, pamat, tmat); - dob = make_dupli(ctx, go->ob, mat, a, false, false); + dob = make_dupli(ctx, object, mat, a, false, false, NULL); dob->particle_system = psys; - if (use_texcoords) + + if (use_texcoords) { psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); + } + + b++; } + FOREACH_GROUP_OBJECT_END } else { /* to give ipos in object correct offset */ @@ -1121,7 +1130,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); - dob = make_dupli(ctx, ob, mat, a, false, false); + dob = make_dupli(ctx, ob, mat, a, false, false, NULL); dob->particle_system = psys; if (use_texcoords) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); @@ -1238,6 +1247,14 @@ ListBase *object_duplilist(const EvaluationContext *eval_ctx, Scene *sce, Object void free_object_duplilist(ListBase *lb) { + + for (DupliObject *dob = lb->first; dob; dob = dob->next) { + if (dob->collection_properties) { + IDP_FreeProperty(dob->collection_properties); + MEM_freeN(dob->collection_properties); + } + } + BLI_freelistN(lb); MEM_freeN(lb); } diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 1e8de416ea9..71d8c1981af 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -68,7 +68,6 @@ #define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf void BKE_object_eval_local_transform(const EvaluationContext *UNUSED(eval_ctx), - Scene *UNUSED(scene), Object *ob) { DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob); @@ -273,34 +272,33 @@ void BKE_object_handle_data_update( /* quick cache removed */ } -void BKE_object_eval_uber_transform(const EvaluationContext *UNUSED(eval_ctx), - Scene *UNUSED(scene), - Object *ob) +bool BKE_object_eval_proxy_copy(const EvaluationContext *UNUSED(eval_ctx), + Object *object) { - /* TODO(sergey): Currently it's a duplicate of logic in BKE_object_handle_update_ex(). */ - // XXX: it's almost redundant now... - /* Handle proxy copy for target, */ - if (ID_IS_LINKED(ob) && ob->proxy_from) { - if (ob->proxy_from->proxy_group) { + if (ID_IS_LINKED(object) && object->proxy_from) { + if (object->proxy_from->proxy_group) { /* Transform proxy into group space. */ - Object *obg = ob->proxy_from->proxy_group; + Object *obg = object->proxy_from->proxy_group; float imat[4][4]; invert_m4_m4(imat, obg->obmat); - mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat); + mul_m4_m4m4(object->obmat, imat, object->proxy_from->obmat); /* Should always be true. */ if (obg->dup_group) { - add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs); + add_v3_v3(object->obmat[3], obg->dup_group->dupli_ofs); } } - else - copy_m4_m4(ob->obmat, ob->proxy_from->obmat); + else { + copy_m4_m4(object->obmat, object->proxy_from->obmat); + } + return true; } + return false; +} - ob->recalc &= ~(OB_RECALC_OB | OB_RECALC_TIME); - if (ob->data == NULL) { - ob->recalc &= ~OB_RECALC_DATA; - } +void BKE_object_eval_uber_transform(const EvaluationContext *eval_ctx, Object *object) +{ + BKE_object_eval_proxy_copy(eval_ctx, object); } void BKE_object_eval_uber_data(const EvaluationContext *eval_ctx, @@ -379,8 +377,6 @@ void BKE_object_eval_uber_data(const EvaluationContext *eval_ctx, #endif } } - - ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME); } void BKE_object_eval_cloth(const EvaluationContext *UNUSED(eval_ctx), @@ -391,6 +387,22 @@ void BKE_object_eval_cloth(const EvaluationContext *UNUSED(eval_ctx), BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH); } +void BKE_object_eval_transform_all(const EvaluationContext *eval_ctx, + Scene *scene, + Object *object) +{ + /* This mimics full transform update chain from new depsgraph. */ + BKE_object_eval_local_transform(eval_ctx, object); + if (object->parent != NULL) { + BKE_object_eval_parent(eval_ctx, scene, object); + } + if (!BLI_listbase_is_empty(&object->constraints)) { + BKE_object_eval_constraints(eval_ctx, scene, object); + } + BKE_object_eval_uber_transform(eval_ctx, object); + BKE_object_eval_done(eval_ctx, object); +} + void BKE_object_eval_update_shading(const EvaluationContext *UNUSED(eval_ctx), Object *object) { diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 209c7398d38..7d1c80dca41 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -327,18 +327,17 @@ bool psys_check_edited(ParticleSystem *psys) void psys_check_group_weights(ParticleSettings *part) { ParticleDupliWeight *dw, *tdw; - GroupObject *go; int current = 0; - if (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first) { + if (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->view_layer->object_bases.first) { /* First try to find NULL objects from their index, * and remove all weights that don't have an object in the group. */ dw = part->dupliweights.first; while (dw) { if (dw->ob == NULL || !BKE_group_object_exists(part->dup_group, dw->ob)) { - go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index); - if (go) { - dw->ob = go->ob; + Base *base = BLI_findlink(&part->dup_group->view_layer->object_bases, dw->index); + if (base != NULL) { + dw->ob = base->object; } else { tdw = dw->next; @@ -352,21 +351,21 @@ void psys_check_group_weights(ParticleSettings *part) } /* then add objects in the group to new list */ - go = part->dup_group->gobject.first; - while (go) { + FOREACH_GROUP_OBJECT(part->dup_group, object) + { dw = part->dupliweights.first; - while (dw && dw->ob != go->ob) + while (dw && dw->ob != object) { dw = dw->next; - + } + if (!dw) { dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight"); - dw->ob = go->ob; + dw->ob = object; dw->count = 1; BLI_addtail(&part->dupliweights, dw); } - - go = go->next; } + FOREACH_GROUP_OBJECT_END dw = part->dupliweights.first; for (; dw; dw = dw->next) { diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index f75b14579c7..bd4b817c8cd 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -57,6 +57,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_effect.h" #include "BKE_global.h" +#include "BKE_group.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_mesh.h" @@ -90,26 +91,30 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw) if (rbw->physics_world) { /* free physics references, we assume that all physics objects in will have been added to the world */ - GroupObject *go; if (rbw->constraints) { - for (go = rbw->constraints->gobject.first; go; go = go->next) { - if (go->ob && go->ob->rigidbody_constraint) { - RigidBodyCon *rbc = go->ob->rigidbody_constraint; - - if (rbc->physics_constraint) + FOREACH_GROUP_OBJECT(rbw->constraints, object) + { + if (object->rigidbody_constraint) { + RigidBodyCon *rbc = object->rigidbody_constraint; + if (rbc->physics_constraint) { RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); + } } } + FOREACH_GROUP_OBJECT_END } - if (rbw->group) { - for (go = rbw->group->gobject.first; go; go = go->next) { - if (go->ob && go->ob->rigidbody_object) { - RigidBodyOb *rbo = go->ob->rigidbody_object; - if (rbo->physics_object) + if (rbw->group) { + FOREACH_GROUP_OBJECT(rbw->group, object) + { + if (object->rigidbody_object) { + RigidBodyOb *rbo = object->rigidbody_object; + if (rbo->physics_object) { RB_dworld_remove_body(rbw->physics_world, rbo->physics_object); + } } } + FOREACH_GROUP_OBJECT_END } /* free dynamics world */ RB_dworld_delete(rbw->physics_world); @@ -1124,7 +1129,6 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob) RigidBodyWorld *rbw = scene->rigidbody_world; RigidBodyOb *rbo = ob->rigidbody_object; RigidBodyCon *rbc; - GroupObject *go; int i; if (rbw) { @@ -1144,8 +1148,8 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob) /* remove object from rigid body constraints */ if (rbw->constraints) { - for (go = rbw->constraints->gobject.first; go; go = go->next) { - Object *obt = go->ob; + FOREACH_GROUP_OBJECT(rbw->constraints, obt) + { if (obt && obt->rigidbody_constraint) { rbc = obt->rigidbody_constraint; if (ELEM(ob, rbc->ob1, rbc->ob2)) { @@ -1153,6 +1157,7 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob) } } } + FOREACH_GROUP_OBJECT_END } } @@ -1186,20 +1191,22 @@ void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) /* Update object array and rigid body count so they're in sync with the rigid body group */ static void rigidbody_update_ob_array(RigidBodyWorld *rbw) { - GroupObject *go; int i, n; - n = BLI_listbase_count(&rbw->group->gobject); + n = BLI_listbase_count(&rbw->group->view_layer->object_bases); if (rbw->numbodies != n) { rbw->numbodies = n; rbw->objects = realloc(rbw->objects, sizeof(Object *) * rbw->numbodies); } - for (go = rbw->group->gobject.first, i = 0; go; go = go->next, i++) { - Object *ob = go->ob; - rbw->objects[i] = ob; + i = 0; + FOREACH_GROUP_OBJECT(rbw->group, object) + { + rbw->objects[i] = object; + i++; } + FOREACH_GROUP_OBJECT_END } static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw) @@ -1313,8 +1320,6 @@ static void rigidbody_update_sim_ob(const struct EvaluationContext *eval_ctx, Sc */ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx, Scene *scene, RigidBodyWorld *rbw, bool rebuild) { - GroupObject *go; - /* update world */ if (rebuild) BKE_rigidbody_validate_sim_world(scene, rbw, true); @@ -1327,24 +1332,22 @@ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx * Memory management needs redesign here, this is just a dirty workaround. */ if (rebuild && rbw->constraints) { - for (go = rbw->constraints->gobject.first; go; go = go->next) { - Object *ob = go->ob; - if (ob) { - RigidBodyCon *rbc = ob->rigidbody_constraint; - if (rbc && rbc->physics_constraint) { - RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); - RB_constraint_delete(rbc->physics_constraint); - rbc->physics_constraint = NULL; - } + FOREACH_GROUP_OBJECT(rbw->constraints, ob) + { + RigidBodyCon *rbc = ob->rigidbody_constraint; + if (rbc && rbc->physics_constraint) { + RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); + RB_constraint_delete(rbc->physics_constraint); + rbc->physics_constraint = NULL; } } + FOREACH_GROUP_OBJECT_END } /* update objects */ - for (go = rbw->group->gobject.first; go; go = go->next) { - Object *ob = go->ob; - - if (ob && ob->type == OB_MESH) { + FOREACH_GROUP_OBJECT(rbw->group, ob) + { + if (ob->type == OB_MESH) { /* validate that we've got valid object set up here... */ RigidBodyOb *rbo = ob->rigidbody_object; /* update transformation matrix of the object so we don't get a frame of lag for simple animations */ @@ -1385,62 +1388,59 @@ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx rigidbody_update_sim_ob(eval_ctx, scene, rbw, ob, rbo); } } + FOREACH_GROUP_OBJECT_END /* update constraints */ if (rbw->constraints == NULL) /* no constraints, move on */ return; - for (go = rbw->constraints->gobject.first; go; go = go->next) { - Object *ob = go->ob; - if (ob) { - /* validate that we've got valid object set up here... */ - RigidBodyCon *rbc = ob->rigidbody_constraint; - /* update transformation matrix of the object so we don't get a frame of lag for simple animations */ - BKE_object_where_is_calc(eval_ctx, scene, ob); + FOREACH_GROUP_OBJECT(rbw->constraints, ob) + { + /* validate that we've got valid object set up here... */ + RigidBodyCon *rbc = ob->rigidbody_constraint; + /* update transformation matrix of the object so we don't get a frame of lag for simple animations */ + BKE_object_where_is_calc(eval_ctx, scene, ob); - if (rbc == NULL) { - /* Since this object is included in the group but doesn't have - * constraint settings (perhaps it was added manually), add! - */ - ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED); - rigidbody_validate_sim_constraint(rbw, ob, true); + if (rbc == NULL) { + /* Since this object is included in the group but doesn't have + * constraint settings (perhaps it was added manually), add! + */ + ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED); + rigidbody_validate_sim_constraint(rbw, ob, true); - rbc = ob->rigidbody_constraint; + rbc = ob->rigidbody_constraint; + } + else { + /* perform simulation data updates as tagged */ + if (rebuild) { + /* World has been rebuilt so rebuild constraint */ + rigidbody_validate_sim_constraint(rbw, ob, true); } - else { - /* perform simulation data updates as tagged */ - if (rebuild) { - /* World has been rebuilt so rebuild constraint */ - rigidbody_validate_sim_constraint(rbw, ob, true); - } - else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) { - rigidbody_validate_sim_constraint(rbw, ob, false); - } - rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE; + else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) { + rigidbody_validate_sim_constraint(rbw, ob, false); } + rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE; } } + FOREACH_GROUP_OBJECT_END } static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw) { - GroupObject *go; - - for (go = rbw->group->gobject.first; go; go = go->next) { - Object *ob = go->ob; - - if (ob) { - RigidBodyOb *rbo = ob->rigidbody_object; - /* reset kinematic state for transformed objects */ - if (rbo && (ob->flag & SELECT) && (G.moving & G_TRANSFORM_OBJ)) { - RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); - RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); - /* deactivate passive objects so they don't interfere with deactivation of active objects */ - if (rbo->type == RBO_TYPE_PASSIVE) - RB_body_deactivate(rbo->physics_object); - } + FOREACH_GROUP_BASE(rbw->group, base) + { + Object *ob = base->object; + RigidBodyOb *rbo = ob->rigidbody_object; + /* Reset kinematic state for transformed objects. */ + if (rbo && (base->flag & BASE_SELECTED) && (G.moving & G_TRANSFORM_OBJ)) { + RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); + RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); + /* Deactivate passive objects so they don't interfere with deactivation of active objects. */ + if (rbo->type == RBO_TYPE_PASSIVE) + RB_body_deactivate(rbo->physics_object); } } + FOREACH_GROUP_BASE_END } bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime) @@ -1567,7 +1567,7 @@ void BKE_rigidbody_rebuild_world(const struct EvaluationContext *eval_ctx, Scene cache = rbw->pointcache; /* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */ - if (rbw->physics_world == NULL || rbw->numbodies != BLI_listbase_count(&rbw->group->gobject)) { + if (rbw->physics_world == NULL || rbw->numbodies != BLI_listbase_count(&rbw->group->view_layer->object_bases)) { cache->flag |= PTCACHE_OUTDATED; } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 7fa7aa71eae..c095236733f 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -151,79 +151,6 @@ static void remove_sequencer_fcurves(Scene *sce) } } -/* copy SceneCollection tree but keep pointing to the same objects */ -static void scene_collection_copy(SceneCollection *sc_dst, SceneCollection *sc_src, const int flag) -{ - BLI_duplicatelist(&sc_dst->objects, &sc_src->objects); - if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - for (LinkData *link = sc_dst->objects.first; link; link = link->next) { - id_us_plus(link->data); - } - } - - BLI_duplicatelist(&sc_dst->filter_objects, &sc_src->filter_objects); - if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - for (LinkData *link = sc_dst->filter_objects.first; link; link = link->next) { - id_us_plus(link->data); - } - } - - BLI_duplicatelist(&sc_dst->scene_collections, &sc_src->scene_collections); - for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first; - nsc_src; - nsc_src = nsc_src->next, nsc_dst = nsc_dst->next) - { - scene_collection_copy(nsc_dst, nsc_src, flag); - } -} - -/* Find the equivalent SceneCollection in the new tree */ -static SceneCollection *scene_collection_from_new_tree(SceneCollection *sc_reference, SceneCollection *sc_dst, SceneCollection *sc_src) -{ - if (sc_src == sc_reference) { - return sc_dst; - } - - for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first; - nsc_src; - nsc_src = nsc_src->next, nsc_dst = nsc_dst->next) - { - SceneCollection *found = scene_collection_from_new_tree(sc_reference, nsc_dst, nsc_src); - if (found != NULL) { - return found; - } - } - return NULL; -} - -static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *layer_collections_src) -{ - LayerCollection *layer_collection_dst = (LayerCollection *)layer_collections_dst->first; - const LayerCollection *layer_collection_src = (const LayerCollection *)layer_collections_src->first; - while (layer_collection_dst != NULL) { - layer_collection_dst->flag = layer_collection_src->flag; - layer_collections_sync_flags(&layer_collection_dst->layer_collections, - &layer_collection_src->layer_collections); - /* TODO(sergey/dfelinto): Overrides. */ - layer_collection_dst = layer_collection_dst->next; - layer_collection_src = layer_collection_src->next; - } -} - - -/* recreate the LayerCollection tree */ -static void layer_collections_recreate( - ViewLayer *view_layer_dst, ListBase *lb_src, SceneCollection *mc_dst, SceneCollection *mc_src) -{ - for (LayerCollection *lc_src = lb_src->first; lc_src; lc_src = lc_src->next) { - SceneCollection *sc_dst = scene_collection_from_new_tree(lc_src->scene_collection, mc_dst, mc_src); - BLI_assert(sc_dst); - - /* instead of synchronizing both trees we simply re-create it */ - BKE_collection_link(view_layer_dst, sc_dst); - } -} - /** * Only copy internal data of Scene ID from source to already allocated/initialized destination. * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. @@ -244,11 +171,11 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons /* layers and collections */ sce_dst->collection = MEM_dupallocN(sce_src->collection); - SceneCollection *mc_src = BKE_collection_master(sce_src); - SceneCollection *mc_dst = BKE_collection_master(sce_dst); + SceneCollection *mc_src = BKE_collection_master(&sce_src->id); + SceneCollection *mc_dst = BKE_collection_master(&sce_dst->id); - /* recursively creates a new SceneCollection tree */ - scene_collection_copy(mc_dst, mc_src, flag_subdata); + /* Recursively creates a new SceneCollection tree. */ + BKE_collection_copy_data(mc_dst, mc_src, flag_subdata); IDPropertyTemplate val = {0}; BLI_duplicatelist(&sce_dst->view_layers, &sce_src->view_layers); @@ -256,39 +183,7 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons view_layer_src; view_layer_src = view_layer_src->next, view_layer_dst = view_layer_dst->next) { - if (view_layer_dst->id_properties != NULL) { - view_layer_dst->id_properties = IDP_CopyProperty_ex(view_layer_dst->id_properties, flag_subdata); - } - BKE_freestyle_config_copy(&view_layer_dst->freestyle_config, &view_layer_src->freestyle_config, flag_subdata); - - view_layer_dst->stats = NULL; - view_layer_dst->properties_evaluated = NULL; - view_layer_dst->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); - IDP_MergeGroup_ex(view_layer_dst->properties, view_layer_src->properties, true, flag_subdata); - - /* we start fresh with no overrides and no visibility flags set - * instead of syncing both trees we simply unlink and relink the scene collection */ - BLI_listbase_clear(&view_layer_dst->layer_collections); - BLI_listbase_clear(&view_layer_dst->object_bases); - BLI_listbase_clear(&view_layer_dst->drawdata); - - layer_collections_recreate(view_layer_dst, &view_layer_src->layer_collections, mc_dst, mc_src); - - /* Now we handle the syncing for visibility, selectability, ... */ - layer_collections_sync_flags(&view_layer_dst->layer_collections, &view_layer_src->layer_collections); - - Object *active_ob = OBACT(view_layer_src); - for (Base *base_src = view_layer_src->object_bases.first, *base_dst = view_layer_dst->object_bases.first; - base_src; - base_src = base_src->next, base_dst = base_dst->next) - { - base_dst->flag = base_src->flag; - base_dst->flag_legacy = base_src->flag_legacy; - - if (base_dst->object == active_ob) { - view_layer_dst->basact = base_dst; - } - } + BKE_view_layer_copy_data(view_layer_dst, view_layer_src, mc_dst, mc_src, flag_subdata); } sce_dst->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); @@ -649,7 +544,7 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user) } /* Master Collection */ - BKE_collection_master_free(sce, do_id_user); + BKE_collection_master_free(&sce->id, do_id_user); MEM_freeN(sce->collection); sce->collection = NULL; @@ -1082,7 +977,6 @@ void BKE_scene_set_background(Main *bmain, Scene *scene) { Object *ob; Group *group; - GroupObject *go; /* check for cyclic sets, for reading old files but also for definite security (py?) */ BKE_scene_validate_setscene(bmain, scene); @@ -1097,11 +991,11 @@ void BKE_scene_set_background(Main *bmain, Scene *scene) /* group flags again */ for (group = bmain->group.first; group; group = group->id.next) { - for (go = group->gobject.first; go; go = go->next) { - if (go->ob) { - go->ob->flag |= OB_FROMGROUP; - } + FOREACH_GROUP_OBJECT(group, object) + { + object->flag |= OB_FROMGROUP; } + FOREACH_GROUP_OBJECT_END } /* copy layers and flags from bases to objects */ @@ -1541,7 +1435,7 @@ void BKE_scene_graph_update_tagged(EvaluationContext *eval_ctx, /* Update sound system animation (TODO, move to depsgraph). */ BKE_sound_update_scene(bmain, scene); /* Inform editors about possible changes. */ - DEG_ids_check_recalc(bmain, scene, false); + DEG_ids_check_recalc(bmain, scene, view_layer, false); /* Clear recalc flags. */ DEG_ids_clear_recalc(bmain); } @@ -1562,11 +1456,7 @@ void BKE_scene_graph_update_for_newframe(EvaluationContext *eval_ctx, * for example, clearing update tags from bmain. */ const float ctime = BKE_scene_frame_get(scene); - /* Inform editors we are starting scene update. */ - DEG_editors_update_pre(bmain, scene, true); - /* Keep this first. - * TODO(sergey): Should it be after the editors update? - */ + /* Keep this first. */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_PRE); /* Update animated image textures for particles, modifiers, gpu, etc, * call this at the start so modifiers with textures don't lag 1 frame. @@ -1592,7 +1482,7 @@ void BKE_scene_graph_update_for_newframe(EvaluationContext *eval_ctx, /* Notify editors and python about recalc. */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST); /* Inform editors about possible changes. */ - DEG_ids_check_recalc(bmain, scene, true); + DEG_ids_check_recalc(bmain, scene, view_layer, true); /* clear recalc flags */ DEG_ids_clear_recalc(bmain); } @@ -2322,8 +2212,8 @@ Depsgraph *BKE_scene_get_depsgraph(Scene *scene, Depsgraph **depsgraph_ptr; if (!BLI_ghash_ensure_p_ex(scene->depsgraph_hash, &key, - (void***)&key_ptr, - (void***)&depsgraph_ptr)) + (void ***)&key_ptr, + (void ***)&depsgraph_ptr)) { *key_ptr = MEM_mallocN(sizeof(DepsgraphKey), __func__); **key_ptr = key; diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index a2c45057bf7..ee80438db64 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -53,15 +53,18 @@ #include "IMB_imbuf.h" #include "IMB_colormanagement.h" +#include "BLI_math_color_blend.h" + #include "RNA_access.h" #include "RE_pipeline.h" #include "BLF_api.h" -static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2, - const ImBuf *ibuf3, const ImBuf *out, int start_line, unsigned char **rect1, - unsigned char **rect2, unsigned char **rect3, unsigned char **rect_out) +static void slice_get_byte_buffers( + const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2, + const ImBuf *ibuf3, const ImBuf *out, int start_line, unsigned char **rect1, + unsigned char **rect2, unsigned char **rect3, unsigned char **rect_out) { int offset = 4 * start_line * context->rectx; @@ -75,9 +78,10 @@ static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ib *rect3 = (unsigned char *)ibuf3->rect + offset; } -static void slice_get_float_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2, - const ImBuf *ibuf3, const ImBuf *out, int start_line, - float **rect1, float **rect2, float **rect3, float **rect_out) +static void slice_get_float_buffers( + const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2, + const ImBuf *ibuf3, const ImBuf *out, int start_line, + float **rect1, float **rect2, float **rect3, float **rect_out) { int offset = 4 * start_line * context->rectx; @@ -171,7 +175,9 @@ static void init_alpha_over_or_under(Sequence *seq) seq->seq1 = seq2; } -static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) +static void do_alphaover_effect_byte( + float facf0, float facf1, int x, int y, + unsigned char *rect1, unsigned char *rect2, unsigned char *out) { float fac2, mfac, fac, fac4; int xo; @@ -236,7 +242,9 @@ static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y, un } } -static void do_alphaover_effect_float(float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) +static void do_alphaover_effect_float( + float facf0, float facf1, int x, int y, + float *rect1, float *rect2, float *out) { float fac2, mfac, fac, fac4; int xo; @@ -299,9 +307,10 @@ static void do_alphaover_effect_float(float facf0, float facf1, int x, int y, f } } -static void do_alphaover_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, - float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), - int start_line, int total_lines, ImBuf *out) +static void do_alphaover_effect( + const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, + float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), + int start_line, int total_lines, ImBuf *out) { if (out->rect_float) { float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -321,7 +330,9 @@ static void do_alphaover_effect(const SeqRenderData *context, Sequence *UNUSED(s /*********************** Alpha Under *************************/ -static void do_alphaunder_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) +static void do_alphaunder_effect_byte( + float facf0, float facf1, int x, int y, + unsigned char *rect1, unsigned char *rect2, unsigned char *out) { float fac2, fac, fac4; int xo; @@ -393,7 +404,9 @@ static void do_alphaunder_effect_byte(float facf0, float facf1, int x, int y, un } } -static void do_alphaunder_effect_float(float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) +static void do_alphaunder_effect_float( + float facf0, float facf1, int x, int y, + float *rect1, float *rect2, float *out) { float fac2, fac, fac4; int xo; @@ -467,9 +480,10 @@ static void do_alphaunder_effect_float(float facf0, float facf1, int x, int y, } } -static void do_alphaunder_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), - float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), - int start_line, int total_lines, ImBuf *out) +static void do_alphaunder_effect( + const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), + float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), + int start_line, int total_lines, ImBuf *out) { if (out->rect_float) { float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -489,7 +503,9 @@ static void do_alphaunder_effect(const SeqRenderData *context, Sequence *UNUSED( /*********************** Cross *************************/ -static void do_cross_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) +static void do_cross_effect_byte( + float facf0, float facf1, int x, int y, + unsigned char *rect1, unsigned char *rect2, unsigned char *out) { int fac1, fac2, fac3, fac4; int xo; @@ -577,9 +593,10 @@ static void do_cross_effect_float(float facf0, float facf1, int x, int y, float } } -static void do_cross_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), - float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), - int start_line, int total_lines, ImBuf *out) +static void do_cross_effect( + const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), + float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), + int start_line, int total_lines, ImBuf *out) { if (out->rect_float) { float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -737,8 +754,9 @@ static void free_gammacross(Sequence *UNUSED(seq)) { } -static void do_gammacross_effect_byte(float facf0, float UNUSED(facf1), int x, int y, unsigned char *rect1, - unsigned char *rect2, unsigned char *out) +static void do_gammacross_effect_byte( + float facf0, float UNUSED(facf1), int x, int y, unsigned char *rect1, + unsigned char *rect2, unsigned char *out) { float fac1, fac2; int xo; @@ -788,8 +806,9 @@ static void do_gammacross_effect_byte(float facf0, float UNUSED(facf1), int x, } } -static void do_gammacross_effect_float(float facf0, float UNUSED(facf1), int x, int y, float *rect1, - float *rect2, float *out) +static void do_gammacross_effect_float( + float facf0, float UNUSED(facf1), int x, int y, float *rect1, + float *rect2, float *out) { float fac1, fac2; int xo; @@ -831,9 +850,10 @@ static struct ImBuf *gammacross_init_execution(const SeqRenderData *context, ImB return out; } -static void do_gammacross_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), - float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), - int start_line, int total_lines, ImBuf *out) +static void do_gammacross_effect( + const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), + float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), + int start_line, int total_lines, ImBuf *out) { if (out->rect_float) { float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -853,8 +873,9 @@ static void do_gammacross_effect(const SeqRenderData *context, Sequence *UNUSED( /*********************** Add *************************/ -static void do_add_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, - unsigned char *out) +static void do_add_effect_byte( + float facf0, float facf1, int x, int y, + unsigned char *rect1, unsigned char *rect2, unsigned char *out) { int xo, fac1, fac3; unsigned char *cp1, *cp2, *rt; @@ -940,8 +961,9 @@ static void do_add_effect_float(float facf0, float facf1, int x, int y, float *r } } -static void do_add_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1, - ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out) +static void do_add_effect( + const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1, + ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out) { if (out->rect_float) { float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -961,7 +983,9 @@ static void do_add_effect(const SeqRenderData *context, Sequence *UNUSED(seq), f /*********************** Sub *************************/ -static void do_sub_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) +static void do_sub_effect_byte( + float facf0, float facf1, int x, int y, + unsigned char *rect1, unsigned char *rect2, unsigned char *out) { int xo, fac1, fac3; unsigned char *cp1, *cp2, *rt; @@ -1003,7 +1027,9 @@ static void do_sub_effect_byte(float facf0, float facf1, int x, int y, unsigned } } -static void do_sub_effect_float(float UNUSED(facf0), float facf1, int x, int y, float *rect1, float *rect2, float *out) +static void do_sub_effect_float( + float UNUSED(facf0), float facf1, int x, int y, + float *rect1, float *rect2, float *out) { int xo; float /* fac1, */ fac3_inv; @@ -1047,8 +1073,9 @@ static void do_sub_effect_float(float UNUSED(facf0), float facf1, int x, int y, } } -static void do_sub_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1, - ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out) +static void do_sub_effect( + const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1, + ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out) { if (out->rect_float) { float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -1072,7 +1099,9 @@ static void do_sub_effect(const SeqRenderData *context, Sequence *UNUSED(seq), f #define XOFF 8 #define YOFF 8 -static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi) +static void do_drop_effect_byte( + float facf0, float facf1, int x, int y, + unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi) { int temp, fac, fac1, fac2; unsigned char *rt1, *rt2, *out; @@ -1112,7 +1141,9 @@ static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned memcpy(out, rt1, sizeof(*out) * yoff * 4 * width); } -static void do_drop_effect_float(float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi) +static void do_drop_effect_float( + float facf0, float facf1, int x, int y, + float *rect2i, float *rect1i, float *outi) { float temp, fac, fac1, fac2; float *rt1, *rt2, *out; @@ -1154,8 +1185,9 @@ static void do_drop_effect_float(float facf0, float facf1, int x, int y, float * /*********************** Mul *************************/ -static void do_mul_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, - unsigned char *out) +static void do_mul_effect_byte( + float facf0, float facf1, int x, int y, + unsigned char *rect1, unsigned char *rect2, unsigned char *out) { int xo, fac1, fac3; unsigned char *rt1, *rt2, *rt; @@ -1202,7 +1234,9 @@ static void do_mul_effect_byte(float facf0, float facf1, int x, int y, unsigned } } -static void do_mul_effect_float(float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) +static void do_mul_effect_float( + float facf0, float facf1, int x, int y, + float *rect1, float *rect2, float *out) { int xo; float fac1, fac3; @@ -1247,8 +1281,9 @@ static void do_mul_effect_float(float facf0, float facf1, int x, int y, float *r } } -static void do_mul_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1, - ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out) +static void do_mul_effect( + const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1, + ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out) { if (out->rect_float) { float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -1266,6 +1301,284 @@ static void do_mul_effect(const SeqRenderData *context, Sequence *UNUSED(seq), f } } +/*********************** Blend Mode ***************************************/ +typedef void (*IMB_blend_func_byte)(unsigned char *dst, const unsigned char *src1, const unsigned char *src2); +typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2); + +BLI_INLINE void apply_blend_function_byte( + float facf0, float facf1, int x, int y, + unsigned char *rect1, unsigned char *rect2, unsigned char *out, IMB_blend_func_byte blend_function) +{ + int xo; + unsigned char *rt1, *rt2, *rt; + unsigned int achannel; + xo = x; + rt1 = rect1; + rt2 = rect2; + rt = out; + while (y--) { + for (x = xo; x > 0; x--) { + achannel = rt2[3]; + rt2[3] = (unsigned int) achannel * facf0; + blend_function(rt, rt1, rt2); + rt2[3] = achannel; + rt[3] = rt2[3]; + rt1 += 4; + rt2 += 4; + rt += 4; + } + if (y == 0) { + break; + } + y--; + for (x = xo; x > 0; x--) { + achannel = rt2[3]; + rt2[3] = (unsigned int) achannel * facf1; + blend_function(rt, rt1, rt2); + rt2[3] = achannel; + rt[3] = rt2[3]; + rt1 += 4; + rt2 += 4; + rt += 4; + } + } +} + +BLI_INLINE void apply_blend_function_float( + float facf0, float facf1, int x, int y, + float *rect1, float *rect2, float *out, IMB_blend_func_float blend_function) +{ + int xo; + float *rt1, *rt2, *rt; + float achannel; + xo = x; + rt1 = rect1; + rt2 = rect2; + rt = out; + while (y--) { + for (x = xo; x > 0; x--) { + achannel = rt2[3]; + rt2[3] = achannel * facf0; + blend_function(rt, rt1, rt2); + rt2[3] = achannel; + rt[3] = rt2[3]; + rt1 += 4; + rt2 += 4; + rt += 4; + } + if (y == 0) { + break; + } + y--; + for (x = xo; x > 0; x--) { + achannel = rt2[3]; + rt2[3] = achannel * facf1; + blend_function(rt, rt1, rt2); + rt2[3] = achannel; + rt[3] = rt2[3]; + rt1 += 4; + rt2 += 4; + rt += 4; + } + } +} + +static void do_blend_effect_float( + float facf0, float facf1, int x, int y, + float *rect1, float *rect2, int btype, float *out) +{ + switch (btype) { + case SEQ_TYPE_ADD: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_float); + break; + case SEQ_TYPE_SUB: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_float); + break; + case SEQ_TYPE_MUL: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_float); + break; + case SEQ_TYPE_DARKEN: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_float); + break; + case SEQ_TYPE_BURN: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_float); + break; + case SEQ_TYPE_LINEAR_BURN: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_float); + break; + case SEQ_TYPE_SCREEN: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_float); + break; + case SEQ_TYPE_LIGHTEN: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_float); + break; + case SEQ_TYPE_DODGE: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_float); + break; + case SEQ_TYPE_OVERLAY: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_float); + break; + case SEQ_TYPE_SOFT_LIGHT: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_float); + break; + case SEQ_TYPE_HARD_LIGHT: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_float); + break; + case SEQ_TYPE_PIN_LIGHT: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_float); + break; + case SEQ_TYPE_LIN_LIGHT: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_float); + break; + case SEQ_TYPE_VIVID_LIGHT: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_float); + break; + case SEQ_TYPE_BLEND_COLOR: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_float); + break; + case SEQ_TYPE_HUE: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_float); + break; + case SEQ_TYPE_SATURATION: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_float); + break; + case SEQ_TYPE_VALUE: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_float); + break; + case SEQ_TYPE_DIFFERENCE: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_float); + break; + case SEQ_TYPE_EXCLUSION: + apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_float); + break; + default: + break; + } +} + +static void do_blend_effect_byte( + float facf0, float facf1, int x, int y, + unsigned char *rect1, unsigned char *rect2, int btype, unsigned char *out) +{ + switch (btype) { + case SEQ_TYPE_ADD: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_byte); + break; + case SEQ_TYPE_SUB: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_byte); + break; + case SEQ_TYPE_MUL: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_byte); + break; + case SEQ_TYPE_DARKEN: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_byte); + break; + case SEQ_TYPE_BURN: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_byte); + break; + case SEQ_TYPE_LINEAR_BURN: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_byte); + break; + case SEQ_TYPE_SCREEN: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_byte); + break; + case SEQ_TYPE_LIGHTEN: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_byte); + break; + case SEQ_TYPE_DODGE: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_byte); + break; + case SEQ_TYPE_OVERLAY: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_byte); + break; + case SEQ_TYPE_SOFT_LIGHT: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_byte); + break; + case SEQ_TYPE_HARD_LIGHT: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_byte); + break; + case SEQ_TYPE_PIN_LIGHT: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_byte); + break; + case SEQ_TYPE_LIN_LIGHT: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_byte); + break; + case SEQ_TYPE_VIVID_LIGHT: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_byte); + break; + case SEQ_TYPE_BLEND_COLOR: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_byte); + break; + case SEQ_TYPE_HUE: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_byte); + break; + case SEQ_TYPE_SATURATION: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_byte); + break; + case SEQ_TYPE_VALUE: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_byte); + break; + case SEQ_TYPE_DIFFERENCE: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_byte); + break; + case SEQ_TYPE_EXCLUSION: + apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_byte); + break; + default: + break; + } +} + +static void do_blend_mode_effect( + const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1, + ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out) +{ + if (out->rect_float) { + float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; + slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); + do_blend_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out); + } + else { + unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; + slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); + do_blend_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out); + } +} +/*********************** Color Mix Effect *************************/ +static void init_colormix_effect(Sequence *seq) +{ + ColorMixVars *data; + + if (seq->effectdata) { + MEM_freeN(seq->effectdata); + } + seq->effectdata = MEM_callocN(sizeof(ColorMixVars), "colormixvars"); + data = (ColorMixVars *) seq->effectdata; + data->blend_effect = SEQ_TYPE_OVERLAY; + data->factor = 1.0f; +} + +static void do_colormix_effect( + const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float UNUSED(facf0), float UNUSED(facf1), + ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out) +{ + float facf; + + ColorMixVars *data = seq->effectdata; + facf = data->factor; + + if (out->rect_float) { + float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; + slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); + do_blend_effect_float(facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out); + } + else { + unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; + slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); + do_blend_effect_byte(facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out); + } +} + /*********************** Wipe *************************/ typedef struct WipeZone { @@ -1570,8 +1883,9 @@ static void copy_wipe_effect(Sequence *dst, Sequence *src) dst->effectdata = MEM_dupallocN(src->effectdata); } -static void do_wipe_effect_byte(Sequence *seq, float facf0, float UNUSED(facf1), int x, int y, unsigned char *rect1, - unsigned char *rect2, unsigned char *out) +static void do_wipe_effect_byte( + Sequence *seq, float facf0, float UNUSED(facf1), int x, int y, + unsigned char *rect1, unsigned char *rect2, unsigned char *out) { WipeZone wipezone; WipeVars *wipe = (WipeVars *)seq->effectdata; @@ -1636,8 +1950,9 @@ static void do_wipe_effect_byte(Sequence *seq, float facf0, float UNUSED(facf1), } } -static void do_wipe_effect_float(Sequence *seq, float facf0, float UNUSED(facf1), int x, int y, float *rect1, - float *rect2, float *out) +static void do_wipe_effect_float( + Sequence *seq, float facf0, float UNUSED(facf1), int x, int y, + float *rect1, float *rect2, float *out) { WipeZone wipezone; WipeVars *wipe = (WipeVars *)seq->effectdata; @@ -1695,18 +2010,21 @@ static void do_wipe_effect_float(Sequence *seq, float facf0, float UNUSED(facf1) } } -static ImBuf *do_wipe_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1, - ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) +static ImBuf *do_wipe_effect( + const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1, + ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) { ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); if (out->rect_float) { - do_wipe_effect_float(seq, facf0, facf1, context->rectx, context->recty, ibuf1->rect_float, - ibuf2->rect_float, out->rect_float); + do_wipe_effect_float( + seq, facf0, facf1, context->rectx, context->recty, ibuf1->rect_float, + ibuf2->rect_float, out->rect_float); } else { - do_wipe_effect_byte(seq, facf0, facf1, context->rectx, context->recty, (unsigned char *) ibuf1->rect, - (unsigned char *) ibuf2->rect, (unsigned char *) out->rect); + do_wipe_effect_byte( + seq, facf0, facf1, context->rectx, context->recty, (unsigned char *) ibuf1->rect, + (unsigned char *) ibuf2->rect, (unsigned char *) out->rect); } return out; @@ -1754,8 +2072,9 @@ static void copy_transform_effect(Sequence *dst, Sequence *src) dst->effectdata = MEM_dupallocN(src->effectdata); } -static void transform_image(int x, int y, ImBuf *ibuf1, ImBuf *out, float scale_x, float scale_y, - float translate_x, float translate_y, float rotate, int interpolation) +static void transform_image( + int x, int y, ImBuf *ibuf1, ImBuf *out, float scale_x, float scale_y, + float translate_x, float translate_y, float rotate, int interpolation) { int xo, yo, xi, yi; float xt, yt, xr, yr; @@ -1835,8 +2154,9 @@ static void do_transform(Scene *scene, Sequence *seq, float UNUSED(facf0), int x } -static ImBuf *do_transform_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, - float UNUSED(facf1), ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) +static ImBuf *do_transform_effect( + const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, + float UNUSED(facf1), ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) { ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); @@ -2007,7 +2327,9 @@ static void RVAddBitmaps_float(float *a, float *b, float *c, int width, int heig } } -static void RVIsolateHighlights_float(float *in, float *out, int width, int height, float threshold, float boost, float clamp) +static void RVIsolateHighlights_float( + float *in, float *out, int width, int height, + float threshold, float boost, float clamp) { int x, y, index; float intensity; @@ -2070,8 +2392,9 @@ static void copy_glow_effect(Sequence *dst, Sequence *src) dst->effectdata = MEM_dupallocN(src->effectdata); } -static void do_glow_effect_byte(Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y, - unsigned char *rect1, unsigned char *UNUSED(rect2), unsigned char *out) +static void do_glow_effect_byte( + Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y, + unsigned char *rect1, unsigned char *UNUSED(rect2), unsigned char *out) { float *outbuf, *inbuf; GlowVars *glow = (GlowVars *)seq->effectdata; @@ -2094,8 +2417,9 @@ static void do_glow_effect_byte(Sequence *seq, int render_size, float facf0, flo MEM_freeN(outbuf); } -static void do_glow_effect_float(Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y, - float *rect1, float *UNUSED(rect2), float *out) +static void do_glow_effect_float( + Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y, + float *rect1, float *UNUSED(rect2), float *out) { float *outbuf = out; float *inbuf = rect1; @@ -2107,20 +2431,23 @@ static void do_glow_effect_float(Sequence *seq, int render_size, float facf0, fl RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y); } -static ImBuf *do_glow_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1, - ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) +static ImBuf *do_glow_effect( + const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1, + ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) { ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); int render_size = 100 * context->rectx / context->scene->r.xsch; if (out->rect_float) { - do_glow_effect_float(seq, render_size, facf0, facf1, context->rectx, context->recty, - ibuf1->rect_float, ibuf2->rect_float, out->rect_float); + do_glow_effect_float( + seq, render_size, facf0, facf1, context->rectx, context->recty, + ibuf1->rect_float, ibuf2->rect_float, out->rect_float); } else { - do_glow_effect_byte(seq, render_size, facf0, facf1, context->rectx, context->recty, - (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect); + do_glow_effect_byte( + seq, render_size, facf0, facf1, context->rectx, context->recty, + (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect); } return out; @@ -2164,8 +2491,9 @@ static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNU return EARLY_NO_INPUT; } -static ImBuf *do_solid_color(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1, - ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) +static ImBuf *do_solid_color( + const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1, + ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) { ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); @@ -2257,8 +2585,9 @@ static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float return EARLY_NO_INPUT; } -static ImBuf *do_multicam(const SeqRenderData *context, Sequence *seq, float cfra, float UNUSED(facf0), float UNUSED(facf1), - ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3)) +static ImBuf *do_multicam( + const SeqRenderData *context, Sequence *seq, float cfra, float UNUSED(facf0), float UNUSED(facf1), + ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3)) { ImBuf *i; ImBuf *out; @@ -2339,8 +2668,9 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl return i; } -static ImBuf *do_adjustment(const SeqRenderData *context, Sequence *seq, float cfra, float UNUSED(facf0), float UNUSED(facf1), - ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3)) +static ImBuf *do_adjustment( + const SeqRenderData *context, Sequence *seq, float cfra, float UNUSED(facf0), float UNUSED(facf1), + ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3)) { ImBuf *i = NULL; ImBuf *out; @@ -2555,26 +2885,30 @@ void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool for } } -static ImBuf *do_speed_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), - float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) +static ImBuf *do_speed_effect( + const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), + float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) { ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); if (out->rect_float) { - do_cross_effect_float(facf0, facf1, context->rectx, context->recty, - ibuf1->rect_float, ibuf2->rect_float, out->rect_float); + do_cross_effect_float( + facf0, facf1, context->rectx, context->recty, + ibuf1->rect_float, ibuf2->rect_float, out->rect_float); } else { - do_cross_effect_byte(facf0, facf1, context->rectx, context->recty, - (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect); + do_cross_effect_byte( + facf0, facf1, context->rectx, context->recty, + (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect); } return out; } /*********************** overdrop *************************/ -static void do_overdrop_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1, - ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out) +static void do_overdrop_effect( + const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1, + ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out) { int x = context->rectx; int y = total_lines; @@ -2668,13 +3002,14 @@ static float *make_gaussian_blur_kernel(float rad, int size) return gausstab; } -static void do_gaussian_blur_effect_byte_x(Sequence *seq, - int start_line, - int x, int y, - int frame_width, - int UNUSED(frame_height), - unsigned char *rect, - unsigned char *out) +static void do_gaussian_blur_effect_byte_x( + Sequence *seq, + int start_line, + int x, int y, + int frame_width, + int UNUSED(frame_height), + unsigned char *rect, + unsigned char *out) { #define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4) GaussianBlurVars *data = seq->effectdata; @@ -2720,13 +3055,14 @@ static void do_gaussian_blur_effect_byte_x(Sequence *seq, #undef INDEX } -static void do_gaussian_blur_effect_byte_y(Sequence *seq, - int start_line, - int x, int y, - int UNUSED(frame_width), - int frame_height, - unsigned char *rect, - unsigned char *out) +static void do_gaussian_blur_effect_byte_y( + Sequence *seq, + int start_line, + int x, int y, + int UNUSED(frame_width), + int frame_height, + unsigned char *rect, + unsigned char *out) { #define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4) GaussianBlurVars *data = seq->effectdata; @@ -2772,13 +3108,14 @@ static void do_gaussian_blur_effect_byte_y(Sequence *seq, #undef INDEX } -static void do_gaussian_blur_effect_float_x(Sequence *seq, - int start_line, - int x, int y, - int frame_width, - int UNUSED(frame_height), - float *rect, - float *out) +static void do_gaussian_blur_effect_float_x( + Sequence *seq, + int start_line, + int x, int y, + int frame_width, + int UNUSED(frame_height), + float *rect, + float *out) { #define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4) GaussianBlurVars *data = seq->effectdata; @@ -2815,13 +3152,14 @@ static void do_gaussian_blur_effect_float_x(Sequence *seq, #undef INDEX } -static void do_gaussian_blur_effect_float_y(Sequence *seq, - int start_line, - int x, int y, - int UNUSED(frame_width), - int frame_height, - float *rect, - float *out) +static void do_gaussian_blur_effect_float_y( + Sequence *seq, + int start_line, + int x, int y, + int UNUSED(frame_width), + int frame_height, + float *rect, + float *out) { #define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4) GaussianBlurVars *data = seq->effectdata; @@ -2860,113 +3198,123 @@ static void do_gaussian_blur_effect_float_y(Sequence *seq, #undef INDEX } -static void do_gaussian_blur_effect_x_cb(const SeqRenderData *context, - Sequence *seq, - ImBuf *ibuf, - int start_line, - int total_lines, - ImBuf *out) +static void do_gaussian_blur_effect_x_cb( + const SeqRenderData *context, + Sequence *seq, + ImBuf *ibuf, + int start_line, + int total_lines, + ImBuf *out) { if (out->rect_float) { float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; - slice_get_float_buffers(context, - ibuf, - NULL, - NULL, - out, - start_line, - &rect1, - &rect2, - NULL, - &rect_out); - - do_gaussian_blur_effect_float_x(seq, - start_line, - context->rectx, - total_lines, - context->rectx, - context->recty, - ibuf->rect_float, - rect_out); + slice_get_float_buffers( + context, + ibuf, + NULL, + NULL, + out, + start_line, + &rect1, + &rect2, + NULL, + &rect_out); + + do_gaussian_blur_effect_float_x( + seq, + start_line, + context->rectx, + total_lines, + context->rectx, + context->recty, + ibuf->rect_float, + rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; - slice_get_byte_buffers(context, - ibuf, - NULL, - NULL, - out, - start_line, - &rect1, - &rect2, - NULL, - &rect_out); - - do_gaussian_blur_effect_byte_x(seq, - start_line, - context->rectx, - total_lines, - context->rectx, - context->recty, - (unsigned char *) ibuf->rect, - rect_out); - } -} - -static void do_gaussian_blur_effect_y_cb(const SeqRenderData *context, - Sequence *seq, - ImBuf *ibuf, - int start_line, - int total_lines, - ImBuf *out) + slice_get_byte_buffers( + context, + ibuf, + NULL, + NULL, + out, + start_line, + &rect1, + &rect2, + NULL, + &rect_out); + + do_gaussian_blur_effect_byte_x( + seq, + start_line, + context->rectx, + total_lines, + context->rectx, + context->recty, + (unsigned char *) ibuf->rect, + rect_out); + } +} + +static void do_gaussian_blur_effect_y_cb( + const SeqRenderData *context, + Sequence *seq, + ImBuf *ibuf, + int start_line, + int total_lines, + ImBuf *out) { if (out->rect_float) { float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; - slice_get_float_buffers(context, - ibuf, - NULL, - NULL, - out, - start_line, - &rect1, - &rect2, - NULL, - &rect_out); - - do_gaussian_blur_effect_float_y(seq, - start_line, - context->rectx, - total_lines, - context->rectx, - context->recty, - ibuf->rect_float, - rect_out); + slice_get_float_buffers( + context, + ibuf, + NULL, + NULL, + out, + start_line, + &rect1, + &rect2, + NULL, + &rect_out); + + do_gaussian_blur_effect_float_y( + seq, + start_line, + context->rectx, + total_lines, + context->rectx, + context->recty, + ibuf->rect_float, + rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; - slice_get_byte_buffers(context, - ibuf, - NULL, - NULL, - out, - start_line, - &rect1, - &rect2, - NULL, - &rect_out); - - do_gaussian_blur_effect_byte_y(seq, - start_line, - context->rectx, - total_lines, - context->rectx, - context->recty, - (unsigned char *) ibuf->rect, - rect_out); + slice_get_byte_buffers( + context, + ibuf, + NULL, + NULL, + out, + start_line, + &rect1, + &rect2, + NULL, + &rect_out); + + do_gaussian_blur_effect_byte_y( + seq, + start_line, + context->rectx, + total_lines, + context->rectx, + context->recty, + (unsigned char *) ibuf->rect, + rect_out); } } @@ -2985,10 +3333,11 @@ typedef struct RenderGaussianBlurEffectThread { int start_line, tot_line; } RenderGaussianBlurEffectThread; -static void render_effect_execute_init_handle(void *handle_v, - int start_line, - int tot_line, - void *init_data_v) +static void render_effect_execute_init_handle( + void *handle_v, + int start_line, + int tot_line, + void *init_data_v) { RenderGaussianBlurEffectThread *handle = (RenderGaussianBlurEffectThread *) handle_v; RenderGaussianBlurEffectInitData *init_data = (RenderGaussianBlurEffectInitData *) init_data_v; @@ -3005,36 +3354,39 @@ static void render_effect_execute_init_handle(void *handle_v, static void *render_effect_execute_do_x_thread(void *thread_data_v) { RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *) thread_data_v; - do_gaussian_blur_effect_x_cb(thread_data->context, - thread_data->seq, - thread_data->ibuf, - thread_data->start_line, - thread_data->tot_line, - thread_data->out); + do_gaussian_blur_effect_x_cb( + thread_data->context, + thread_data->seq, + thread_data->ibuf, + thread_data->start_line, + thread_data->tot_line, + thread_data->out); return NULL; } static void *render_effect_execute_do_y_thread(void *thread_data_v) { RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *) thread_data_v; - do_gaussian_blur_effect_y_cb(thread_data->context, - thread_data->seq, - thread_data->ibuf, - thread_data->start_line, - thread_data->tot_line, - thread_data->out); + do_gaussian_blur_effect_y_cb( + thread_data->context, + thread_data->seq, + thread_data->ibuf, + thread_data->start_line, + thread_data->tot_line, + thread_data->out); return NULL; } -static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context, - Sequence *seq, - float UNUSED(cfra), - float UNUSED(facf0), - float UNUSED(facf1), - ImBuf *ibuf1, - ImBuf *UNUSED(ibuf2), - ImBuf *UNUSED(ibuf3)) +static ImBuf *do_gaussian_blur_effect( + const SeqRenderData *context, + Sequence *seq, + float UNUSED(cfra), + float UNUSED(facf0), + float UNUSED(facf1), + ImBuf *ibuf1, + ImBuf *UNUSED(ibuf2), + ImBuf *UNUSED(ibuf3)) { ImBuf *out = prepare_effect_imbufs(context, ibuf1, NULL, NULL); @@ -3045,22 +3397,24 @@ static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context, init_data.ibuf = ibuf1; init_data.out = out; - IMB_processor_apply_threaded(out->y, - sizeof(RenderGaussianBlurEffectThread), - &init_data, - render_effect_execute_init_handle, - render_effect_execute_do_x_thread); + IMB_processor_apply_threaded( + out->y, + sizeof(RenderGaussianBlurEffectThread), + &init_data, + render_effect_execute_init_handle, + render_effect_execute_do_x_thread); ibuf1 = out; init_data.ibuf = ibuf1; out = prepare_effect_imbufs(context, ibuf1, NULL, NULL); init_data.out = out; - IMB_processor_apply_threaded(out->y, - sizeof(RenderGaussianBlurEffectThread), - &init_data, - render_effect_execute_init_handle, - render_effect_execute_do_y_thread); + IMB_processor_apply_threaded( + out->y, + sizeof(RenderGaussianBlurEffectThread), + &init_data, + render_effect_execute_init_handle, + render_effect_execute_do_y_thread); IMB_freeImBuf(ibuf1); @@ -3104,8 +3458,9 @@ static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1 return EARLY_NO_INPUT; } -static ImBuf *do_text_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float UNUSED(facf0), float UNUSED(facf1), - ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) +static ImBuf *do_text_effect( + const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float UNUSED(facf0), float UNUSED(facf1), + ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) { ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); TextVars *data = seq->effectdata; @@ -3336,6 +3691,36 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.execute_slice = do_mul_effect; rval.early_out = early_out_mul_input2; break; + case SEQ_TYPE_SCREEN: + case SEQ_TYPE_OVERLAY: + case SEQ_TYPE_BURN: + case SEQ_TYPE_LINEAR_BURN: + case SEQ_TYPE_DARKEN: + case SEQ_TYPE_LIGHTEN: + case SEQ_TYPE_DODGE: + case SEQ_TYPE_SOFT_LIGHT: + case SEQ_TYPE_HARD_LIGHT: + case SEQ_TYPE_PIN_LIGHT: + case SEQ_TYPE_LIN_LIGHT: + case SEQ_TYPE_VIVID_LIGHT: + case SEQ_TYPE_BLEND_COLOR: + case SEQ_TYPE_HUE: + case SEQ_TYPE_SATURATION: + case SEQ_TYPE_VALUE: + case SEQ_TYPE_DIFFERENCE: + case SEQ_TYPE_EXCLUSION: + rval.multithreaded = true; + rval.execute_slice = do_blend_mode_effect; + rval.early_out = early_out_mul_input2; + break; + case SEQ_TYPE_COLORMIX: + rval.multithreaded = true; + rval.init = init_colormix_effect; + rval.free = free_effect_default; + rval.copy = copy_effect_default; + rval.execute_slice = do_colormix_effect; + rval.early_out = early_out_mul_input2; + break; case SEQ_TYPE_ALPHAOVER: rval.multithreaded = true; rval.init = init_alpha_over_or_under; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index ced94af26d2..2319d36ab16 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -1164,6 +1164,7 @@ static const char *give_seqname_by_type(int type) case SEQ_TYPE_ALPHAOVER: return "Alpha Over"; case SEQ_TYPE_ALPHAUNDER: return "Alpha Under"; case SEQ_TYPE_OVERDROP: return "Over Drop"; + case SEQ_TYPE_COLORMIX: return "Color Mix"; case SEQ_TYPE_WIPE: return "Wipe"; case SEQ_TYPE_GLOW: return "Glow"; case SEQ_TYPE_TRANSFORM: return "Transform"; @@ -3321,7 +3322,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq context->scene->r.seq_prev_type = 3 /* == OB_SOLID */; /* opengl offscreen render */ - context->eval_ctx->engine = RE_engines_find(scene->view_render.engine_id); + context->eval_ctx->engine_type = RE_engines_find(scene->view_render.engine_id); BKE_scene_graph_update_for_newframe(context->eval_ctx, depsgraph, context->bmain, scene, view_layer); ibuf = sequencer_view3d_cb( /* set for OpenGL render (NULL when scrubbing) */ diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index d7d274f32b5..e3af77166a9 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -74,6 +74,7 @@ variables on the UI for now #include "BKE_curve.h" #include "BKE_effect.h" #include "BKE_global.h" +#include "BKE_group.h" #include "BKE_modifier.h" #include "BKE_softbody.h" #include "BKE_pointcache.h" @@ -520,29 +521,20 @@ static void ccd_build_deflector_hash(ViewLayer *view_layer, Group *group, Object if (!hash) return; + /* Explicit collision group. */ if (group) { - /* Explicit collision group */ - for (GroupObject *go = group->gobject.first; go; go = go->next) { - ob = go->ob; - - if (ob == vertexowner || ob->type != OB_MESH) - continue; - - ccd_build_deflector_hash_single(hash, ob); - } + view_layer = group->view_layer; } - else { - for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { - /*Only proceed for mesh object in same layer */ - if (base->object->type == OB_MESH) { - ob = base->object; - if ((vertexowner) && (ob == vertexowner)) { - /* if vertexowner is given we don't want to check collision with owner object */ - continue; - } - ccd_build_deflector_hash_single(hash, ob); + for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { + /* Only proceed for mesh object in same layer. */ + if (base->object->type == OB_MESH) { + ob = base->object; + if (ob == vertexowner) { + /* If vertexowner is given we don't want to check collision with owner object. */ + continue; } + ccd_build_deflector_hash_single(hash, ob); } } } @@ -566,31 +558,23 @@ static void ccd_update_deflector_hash(ViewLayer *view_layer, Group *group, Objec if ((!hash) || (!vertexowner)) return; + /* Explicit collision group. */ if (group) { - /* Explicit collision group */ - for (GroupObject *go = group->gobject.first; go; go = go->next) { - ob = go->ob; + view_layer = group->view_layer; + } - if (ob == vertexowner || ob->type != OB_MESH) + for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { + /* Only proceed for mesh object in same layer. */ + if (base->object->type == OB_MESH) { + ob = base->object; + if (ob == vertexowner) { + /* If vertexowner is given we don't want to check collision with owner object. */ continue; + } ccd_update_deflector_hash_single(hash, ob); } } - else { - for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { - /*Only proceed for mesh object in same layer */ - if (base->object->type == OB_MESH) { - ob = base->object; - if (ob == vertexowner) { - /* if vertexowner is given we don't want to check collision with owner object */ - continue; - } - - ccd_update_deflector_hash_single(hash, ob); - } - } - } } @@ -979,29 +963,21 @@ static void free_softbody_intern(SoftBody *sb) /** * \note group overrides scene when not NULL. */ -static bool are_there_deflectors(ViewLayer *view_layer, Group *group) +static bool are_there_deflectors(ViewLayer *view_layer) { - if (group) { - for (GroupObject *go = group->gobject.first; go; go = go->next) { - if (go->ob->pd && go->ob->pd->deflect) + for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { + if (base->object->pd) { + if (base->object->pd->deflect) return 1; } } - else { - for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { - if (base->object->pd) { - if (base->object->pd->deflect) - return 1; - } - } - } return 0; } static int query_external_colliders(ViewLayer *view_layer, Group *group) { - return(are_there_deflectors(view_layer, group)); + return(are_there_deflectors(group != NULL ? group->view_layer : view_layer)); } /* --- dependency information functions*/ diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 50bb3a5f10d..122b605f160 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -1165,6 +1165,10 @@ void set_current_material_texture(Material *ma, Tex *newtex) ma->mtex[act] = BKE_texture_mtex_add(); /* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */ ma->septex &= ~(1 << act); + /* For volumes the default UV texture coordinates are not available. */ + if (ma->material_type == MA_TYPE_VOLUME) { + ma->mtex[act]->texco = TEXCO_ORCO; + } } ma->mtex[act]->tex = newtex; diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index b8dfb217c16..edddeb41cc8 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -41,13 +41,14 @@ #include "BLI_utildefines.h" #include "BLI_sort_utils.h" +#include "BLI_ghash.h" #include "BLI_math_vector.h" #include "BLI_math.h" +#include "BLI_task.h" #include "BKE_tracking.h" #include "BKE_movieclip.h" #include "BKE_fcurve.h" -#include "BLI_ghash.h" #include "MEM_guardedalloc.h" #include "IMB_imbuf_types.h" @@ -1491,6 +1492,35 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip, discard_stabilization_working_context(ctx); } + +typedef void (*interpolation_func)(struct ImBuf *, struct ImBuf *, float, float, int, int); + +typedef struct TrackingStabilizeFrameInterpolationData { + ImBuf *ibuf; + ImBuf *tmpibuf; + float (*mat)[4]; + + interpolation_func interpolation; +} TrackingStabilizeFrameInterpolationData; + +static void tracking_stabilize_frame_interpolation_cb(void *userdata, int j) +{ + TrackingStabilizeFrameInterpolationData *data = userdata; + ImBuf *ibuf = data->ibuf; + ImBuf *tmpibuf = data->tmpibuf; + float (*mat)[4] = data->mat; + + interpolation_func interpolation = data->interpolation; + + for (int i = 0; i < tmpibuf->x; i++) { + float vec[3] = {i, j, 0.0f}; + + mul_v3_m4v3(vec, mat, vec); + + interpolation(ibuf, tmpibuf, vec[0], vec[1], i, j); + } +} + /* Stabilize given image buffer using stabilization data for a specified * frame number. * @@ -1511,8 +1541,8 @@ ImBuf *BKE_tracking_stabilize_frame(MovieClip *clip, int width = ibuf->x, height = ibuf->y; float pixel_aspect = tracking->camera.pixel_aspect; float mat[4][4]; - int j, filter = tracking->stabilization.filter; - void (*interpolation)(struct ImBuf *, struct ImBuf *, float, float, int, int) = NULL; + int filter = tracking->stabilization.filter; + interpolation_func interpolation = NULL; int ibuf_flags; if (translation) @@ -1563,24 +1593,14 @@ ImBuf *BKE_tracking_stabilize_frame(MovieClip *clip, /* fallback to default interpolation method */ interpolation = nearest_interpolation; - /* This function is only used for display in clip editor and - * sequencer only, which would only benefit of using threads - * here. - * - * But need to keep an eye on this if the function will be - * used in other cases. - */ -#pragma omp parallel for if (tmpibuf->y > 128) - for (j = 0; j < tmpibuf->y; j++) { - int i; - for (i = 0; i < tmpibuf->x; i++) { - float vec[3] = {i, j, 0.0f}; - - mul_v3_m4v3(vec, mat, vec); - - interpolation(ibuf, tmpibuf, vec[0], vec[1], i, j); - } - } + TrackingStabilizeFrameInterpolationData data = { + .ibuf = ibuf, .tmpibuf = tmpibuf, .mat = mat, + .interpolation = interpolation + }; + BLI_task_parallel_range(0, tmpibuf->y, + &data, + tracking_stabilize_frame_interpolation_cb, + tmpibuf->y > 128); if (tmpibuf->rect_float) tmpibuf->userflags |= IB_RECT_INVALID; diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 785fd71df69..8554cf0fb28 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -113,6 +113,18 @@ static void *workspace_relation_get_data_matching_parent( } } +static void workspace_relation_remove_from_value( + ListBase *relation_list, const void *value) +{ + for (WorkSpaceDataRelation *relation = relation_list->first, *relation_next; relation; relation = relation_next) { + relation_next = relation->next; + + if (relation->value == value) { + workspace_relation_remove(relation_list, relation); + } + } +} + /** * Checks if \a screen is already used within any workspace. A screen should never be assigned to multiple * WorkSpaceLayouts, but that should be ensured outside of the BKE_workspace module and without such checks. @@ -151,15 +163,12 @@ WorkSpace *BKE_workspace_add(Main *bmain, const char *name) */ void BKE_workspace_free(WorkSpace *workspace) { - for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next; - relation; - relation = relation_next) - { - relation_next = relation->next; - workspace_relation_remove(&workspace->hook_layout_relations, relation); - } + BKE_workspace_relations_free(&workspace->hook_layout_relations); + BKE_workspace_relations_free(&workspace->scene_viewlayer_relations); + BLI_freelistN(&workspace->layouts); BLI_freelistN(&workspace->transform_orientations); + BKE_viewrender_free(&workspace->view_render); } @@ -237,9 +246,28 @@ void BKE_workspace_layout_remove( BLI_freelinkN(&workspace->layouts, layout); } +void BKE_workspace_relations_free( + ListBase *relation_list) +{ + for (WorkSpaceDataRelation *relation = relation_list->first, *relation_next; relation; relation = relation_next) { + relation_next = relation->next; + workspace_relation_remove(relation_list, relation); + } +} + + /* -------------------------------------------------------------------- */ /* General Utils */ +void BKE_workspace_view_layer_remove_references( + const Main *bmain, + const ViewLayer *view_layer) +{ + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + workspace_relation_remove_from_value(&workspace->scene_viewlayer_relations, view_layer); + } +} + void BKE_workspace_transform_orientation_remove( WorkSpace *workspace, TransformOrientation *orientation) { @@ -386,23 +414,24 @@ void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, WorkSpace *wor } #ifdef USE_WORKSPACE_MODE -eObjectMode BKE_workspace_object_mode_get(const WorkSpace *workspace) +eObjectMode BKE_workspace_object_mode_get(const WorkSpace *workspace, const Scene *scene) { - Base *active_base = BKE_workspace_active_base_get(workspace); + Base *active_base = BKE_workspace_active_base_get(workspace, scene); return active_base ? active_base->object->mode : OB_MODE_OBJECT; } -void BKE_workspace_object_mode_set(WorkSpace *workspace, const eObjectMode mode) +void BKE_workspace_object_mode_set(WorkSpace *workspace, Scene *scene, const eObjectMode mode) { - Base *active_base = BKE_workspace_active_base_get(workspace); + Base *active_base = BKE_workspace_active_base_get(workspace, scene); if (active_base) { active_base->object->mode = mode; } } #endif -Base *BKE_workspace_active_base_get(const WorkSpace *workspace) +Base *BKE_workspace_active_base_get(const WorkSpace *workspace, const Scene *scene) { - return workspace->view_layer->basact; + ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene); + return view_layer->basact; } ListBase *BKE_workspace_transform_orientations_get(WorkSpace *workspace) @@ -410,13 +439,13 @@ ListBase *BKE_workspace_transform_orientations_get(WorkSpace *workspace) return &workspace->transform_orientations; } -ViewLayer *BKE_workspace_view_layer_get(const WorkSpace *workspace) +ViewLayer *BKE_workspace_view_layer_get(const WorkSpace *workspace, const Scene *scene) { - return workspace->view_layer; + return workspace_relation_get_data_matching_parent(&workspace->scene_viewlayer_relations, scene); } -void BKE_workspace_view_layer_set(WorkSpace *workspace, ViewLayer *layer) +void BKE_workspace_view_layer_set(WorkSpace *workspace, ViewLayer *layer, Scene *scene) { - workspace->view_layer = layer; + workspace_relation_ensure_updated(&workspace->scene_viewlayer_relations, scene, layer); } ListBase *BKE_workspace_layouts_get(WorkSpace *workspace) @@ -486,7 +515,7 @@ void BKE_workspace_update_tagged(struct EvaluationContext *eval_ctx, WorkSpace *workspace, Scene *scene) { - ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace); + ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene); struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index 2720c0058b7..b4819ff4e55 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -20,16 +20,18 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. - * * ***** END GPL LICENSE BLOCK ***** */ - + #ifndef __BLI_GHASH_H__ #define __BLI_GHASH_H__ /** \file BLI_ghash.h * \ingroup bli + * + * GHash is a hash-map implementation (unordered key, value pairs). + * + * This is also used to implement a 'set' (see #GSet below). */ #include "BLI_sys_types.h" /* for bool */ @@ -81,11 +83,14 @@ enum { /* *** */ -GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, - const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; -GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; -GHash *BLI_ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp, - GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_new_ex( + GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_new( + GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_copy( + GHash *gh, GHashKeyCopyFP keycopyfp, + GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve); void BLI_ghash_insert(GHash *gh, void *key, void *val); @@ -97,9 +102,11 @@ void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT; bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val) ATTR_WARN_UNUSED_RESULT; bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); -void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); -void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, - const unsigned int nentries_reserve); +void BLI_ghash_clear( + GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); +void BLI_ghash_clear_ex( + GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, + const unsigned int nentries_reserve); void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT; bool BLI_ghash_haskey(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); @@ -193,18 +200,26 @@ bool BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b); /** \} */ -GHash *BLI_ghash_ptr_new_ex(const char *info, - const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; -GHash *BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; -GHash *BLI_ghash_str_new_ex(const char *info, - const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; -GHash *BLI_ghash_str_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; -GHash *BLI_ghash_int_new_ex(const char *info, - const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; -GHash *BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; -GHash *BLI_ghash_pair_new_ex(const char *info, - const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; -GHash *BLI_ghash_pair_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_ptr_new_ex( + const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_ptr_new( + const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_str_new_ex( + const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_str_new( + const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_int_new_ex( + const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_int_new( + const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_pair_new_ex( + const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_pair_new( + const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; typedef struct GHashPair { const void *first; @@ -216,8 +231,12 @@ unsigned int BLI_ghashutil_pairhash(const void *ptr); bool BLI_ghashutil_paircmp(const void *a, const void *b); void BLI_ghashutil_pairfree(void *ptr); - -/* *** */ +/** + * GSet is a 'set' implementation (unordered collection of unique elements). + * + * Internally this is a 'GHash' without any keys, + * which is why this API's are in the same header & source file. + */ typedef struct GSet GSet; @@ -237,8 +256,9 @@ typedef struct GSetIterator { ; } GSetIterator; -GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, - const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GSet *BLI_gset_new_ex( + GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; GSet *BLI_gset_copy(GSet *gs, GSetKeyCopyFP keycopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; unsigned int BLI_gset_size(GSet *gs) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h index 9477f61713c..80ee50621ca 100644 --- a/source/blender/blenlib/BLI_sys_types.h +++ b/source/blender/blenlib/BLI_sys_types.h @@ -47,7 +47,9 @@ extern "C" { #endif -#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__) +#if defined(__linux__) || defined(__GNU__) || \ + defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD_kernel__) || \ + defined(__HAIKU__) /* Linux-i386, Linux-Alpha, Linux-ppc */ #include <stdint.h> diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index 36a0d1c1641..ad53457f863 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -621,7 +621,21 @@ static int recursive_operation(const char *startfrom, const char *startto, if (to) join_dirfile_alloc(&to_path, &to_alloc_len, to, dirent->d_name); - if (dirent->d_type == DT_DIR) { + bool is_dir; + +#ifdef __HAIKU__ + { + struct stat st_dir; + char filename[FILE_MAX]; + BLI_path_join(filename, sizeof(filename), startfrom, dirent->d_name, NULL); + lstat(filename, &st_dir); + is_dir = S_ISDIR(st_dir.st_mode); + } +#else + is_dir = (dirent->d_type == DT_DIR); +#endif + + if (is_dir) { /* recursively dig into a subfolder */ ret = recursive_operation(from_path, to_path, callback_dir_pre, callback_file, callback_dir_post); } diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c index dc3874f83a2..1af2a0cd6a2 100644 --- a/source/blender/blenlib/intern/math_color_blend_inline.c +++ b/source/blender/blenlib/intern/math_color_blend_inline.c @@ -439,10 +439,10 @@ MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const ch int temp; if (src2[i] == 255) { - temp = 255; + temp = (src1[i] == 0) ? 127 : 255; } else if (src2[i] == 0) { - temp = 0; + temp = (src1[i] == 255) ? 127 : 0; } else if (src2[i] > 127) { temp = min_ii(((src1[i]) * 255) / (2 * (255 - src2[i])), 255); @@ -784,7 +784,7 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons MINLINE void blend_color_overlay_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; int i = 3; @@ -810,7 +810,7 @@ MINLINE void blend_color_overlay_float(float dst[4], const float src1[4], const MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; int i = 3; @@ -835,7 +835,7 @@ MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], cons MINLINE void blend_color_burn_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; int i = 3; @@ -853,7 +853,7 @@ MINLINE void blend_color_burn_float(float dst[4], const float src1[4], const flo MINLINE void blend_color_linearburn_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; int i = 3; @@ -872,7 +872,7 @@ MINLINE void blend_color_linearburn_float(float dst[4], const float src1[4], con MINLINE void blend_color_dodge_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; int i = 3; @@ -890,7 +890,7 @@ MINLINE void blend_color_dodge_float(float dst[4], const float src1[4], const fl MINLINE void blend_color_screen_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; int i = 3; @@ -908,7 +908,7 @@ MINLINE void blend_color_screen_float(float dst[4], const float src1[4], const f MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; int i = 3; @@ -933,7 +933,7 @@ MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], cons MINLINE void blend_color_pinlight_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; int i = 3; @@ -959,7 +959,7 @@ MINLINE void blend_color_pinlight_float(float dst[4], const float src1[4], const MINLINE void blend_color_linearlight_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; int i = 3; @@ -985,7 +985,7 @@ MINLINE void blend_color_linearlight_float(float dst[4], const float src1[4], co MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; int i = 3; @@ -993,10 +993,10 @@ MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], con float temp; if (src2[i] == 1.0f) { - temp = 1.0f; + temp = (src1[i] == 0.0f) ? 0.5f : 1.0f; } else if (src2[i] == 0.0f) { - temp = 0.0f; + temp = (src1[i] == 1.0f) ? 0.5f : 0.0f; } else if (src2[i] > 0.5f) { temp = min_ff(((src1[i]) * 1.0f) / (2.0f * (1.0f - src2[i])), 1.0f); @@ -1016,7 +1016,7 @@ MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], con MINLINE void blend_color_difference_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; int i = 3; @@ -1034,7 +1034,7 @@ MINLINE void blend_color_difference_float(float dst[4], const float src1[4], con MINLINE void blend_color_exclusion_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; int i = 3; @@ -1053,7 +1053,7 @@ MINLINE void blend_color_exclusion_float(float dst[4], const float src1[4], cons MINLINE void blend_color_color_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; float h1, s1, v1; float h2, s2, v2; @@ -1081,7 +1081,7 @@ MINLINE void blend_color_color_float(float dst[4], const float src1[4], const fl MINLINE void blend_color_hue_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; float h1, s1, v1; float h2, s2, v2; @@ -1107,7 +1107,7 @@ MINLINE void blend_color_hue_float(float dst[4], const float src1[4], const floa MINLINE void blend_color_saturation_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; float h1, s1, v1; float h2, s2, v2; @@ -1134,7 +1134,7 @@ MINLINE void blend_color_saturation_float(float dst[4], const float src1[4], con MINLINE void blend_color_luminosity_float(float dst[4], const float src1[4], const float src2[4]) { const float fac = src2[3]; - if (fac != 0.0f && fac < 1.0f) { + if (fac != 0.0f) { const float mfac = 1.0f - fac; float h1, s1, v1; float h2, s2, v2; diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index e31659c35d9..c08329ef34f 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -37,7 +37,7 @@ #include <sys/stat.h> -#if defined(__NetBSD__) || defined(__DragonFly__) +#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__HAIKU__) /* Other modern unix os's should probably use this also */ # include <sys/statvfs.h> # define USE_STATFS_STATVFS diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 00d00e98c84..0da15fe5bbc 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -119,14 +119,24 @@ void BLO_blendhandle_close(BlendHandle *bh); bool BLO_has_bfile_extension(const char *str); bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name); +/* Options controlling behavior of append/link code. + * Note: merged with 'user-level' options from operators etc. in 16 lower bits + * (see eFileSel_Params_Flag in DNA_space_types.h). */ +typedef enum BLO_LibLinkFlags { + /* Generate a placeholder (empty ID) if not found in current lib file. */ + BLO_LIBLINK_USE_PLACEHOLDERS = 1 << 16, + /* Force loaded ID to be tagged as LIB_TAG_INDIRECT (used in reload context only). */ + BLO_LIBLINK_FORCE_INDIRECT = 1 << 17, +} BLO_LinkFlags; + struct Main *BLO_library_link_begin(struct Main *mainvar, BlendHandle **bh, const char *filepath); struct ID *BLO_library_link_named_part(struct Main *mainl, BlendHandle **bh, const short idcode, const char *name); struct ID *BLO_library_link_named_part_ex( struct Main *mainl, BlendHandle **bh, - const short idcode, const char *name, const short flag, - struct Scene *scene, struct ViewLayer *view_layer, - const bool use_placeholders, const bool force_indirect); -void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct ViewLayer *view_layer); + const short idcode, const char *name, const int flag, + struct Scene *scene, struct ViewLayer *view_layer); +void BLO_library_link_end( + struct Main *mainl, BlendHandle **bh, int flag, struct Scene *scene, struct ViewLayer *view_layer); void BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 861952ff181..94f5f790f1c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -136,6 +136,7 @@ #include "BKE_layer.h" #include "BKE_library.h" // for which_libbase #include "BKE_library_idmap.h" +#include "BKE_library_override.h" #include "BKE_library_query.h" #include "BKE_idcode.h" #include "BKE_idprop.h" @@ -252,7 +253,9 @@ static void *read_struct(FileData *fd, BHead *bh, const char *blockname); static void direct_link_modifiers(FileData *fd, ListBase *lb); static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name); static BHead *find_bhead_from_idname(FileData *fd, const char *idname); -static SceneCollection *get_scene_collection_active_or_create(struct Scene *scene, struct ViewLayer *view_layer, const short flag); +static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection *sc); +static SceneCollection *get_scene_collection_active_or_create( + struct Scene *scene, struct ViewLayer *view_layer, const int flag); /* this function ensures that reports are printed, * in the case of libraray linking errors this is important! @@ -2214,6 +2217,42 @@ static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_p /* ************ READ ID *************** */ +static void lib_link_id(FileData *fd, Main *main) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int base_count, i; + + base_count = set_listbasepointers(main, lbarray); + + for (i = 0; i < base_count; i++) { + ListBase *lb = lbarray[i]; + ID *id; + + for (id = lb->first; id; id = id->next) { + if (id->override_static) { + id->override_static->reference = newlibadr_us(fd, id->lib, id->override_static->reference); + id->override_static->storage = newlibadr_us(fd, id->lib, id->override_static->storage); + } + } + } +} + +static void direct_link_id_override_property_operation_cb(FileData *fd, void *data) +{ + IDOverrideStaticPropertyOperation *opop = data; + + opop->subitem_reference_name = newdataadr(fd, opop->subitem_reference_name); + opop->subitem_local_name = newdataadr(fd, opop->subitem_local_name); +} + +static void direct_link_id_override_property_cb(FileData *fd, void *data) +{ + IDOverrideStaticProperty *op = data; + + op->rna_path = newdataadr(fd, op->rna_path); + link_list_ex(fd, &op->operations, direct_link_id_override_property_operation_cb); +} + static void direct_link_id(FileData *fd, ID *id) { /*link direct data of ID properties*/ @@ -2223,6 +2262,12 @@ static void direct_link_id(FileData *fd, ID *id) IDP_DirectLinkGroup_OrFree(&id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); } id->py_instance = NULL; + + /* Link direct data of overrides. */ + if (id->override_static) { + id->override_static = newdataadr(fd, id->override_static); + link_list_ex(fd, &id->override_static->properties, direct_link_id_override_property_cb); + } } /* ************ READ CurveMapping *************** */ @@ -2800,6 +2845,14 @@ static void lib_link_workspaces(FileData *fd, Main *bmain) IDP_LibLinkProperty(id->properties, fd); id_us_ensure_real(id); + for (WorkSpaceDataRelation *relation = workspace->scene_viewlayer_relations.first; + relation != NULL; + relation = relation->next) + { + relation->parent = newlibadr(fd, id->lib, relation->parent); + /* relation->value is set in direct_link_workspace_link_scene_data */ + } + for (WorkSpaceLayout *layout = layouts->first, *layout_next; layout; layout = layout_next) { bScreen *screen = newlibadr(fd, id->lib, BKE_workspace_layout_screen_get(layout)); @@ -2825,6 +2878,7 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main { link_list(fd, BKE_workspace_layouts_get(workspace)); link_list(fd, &workspace->hook_layout_relations); + link_list(fd, &workspace->scene_viewlayer_relations); link_list(fd, BKE_workspace_transform_orientations_get(workspace)); for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first; @@ -2838,7 +2892,7 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main if (ID_IS_LINKED(&workspace->id)) { /* Appending workspace so render layer is likely from a different scene. Unset * now, when activating workspace later we set a valid one from current scene. */ - BKE_workspace_view_layer_set(workspace, NULL); + BKE_workspace_relations_free(&workspace->scene_viewlayer_relations); } /* Same issue/fix as in direct_link_workspace_link_scene_data: Can't read workspace data @@ -5466,11 +5520,6 @@ static void direct_link_object(FileData *fd, Object *ob) /* weak weak... this was only meant as draw flag, now is used in give_base_to_objects too */ ob->flag &= ~OB_FROMGROUP; - /* This is a transient flag; clear in order to avoid unneeded object update pending from - * time when file was saved. - */ - ob->recalc = 0; - /* XXX This should not be needed - but seems like it can happen in some cases, so for now play safe... */ ob->proxy_from = NULL; @@ -5785,6 +5834,28 @@ static void lib_link_scene_collection(FileData *fd, Library *lib, SceneCollectio } } +static void lib_link_view_layer(FileData *fd, Library *lib, ViewLayer *view_layer) +{ + /* tag scene layer to update for collection tree evaluation */ + view_layer->flag |= VIEW_LAYER_ENGINE_DIRTY; + + for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) { + fmc->script = newlibadr(fd, lib, fmc->script); + } + + for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) { + fls->linestyle = newlibadr_us(fd, lib, fls->linestyle); + fls->group = newlibadr_us(fd, lib, fls->group); + } + + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + /* we only bump the use count for the collection objects */ + base->object = newlibadr(fd, lib, base->object); + base->flag |= BASE_DIRTY_ENGINE_SETTINGS; + base->collection_properties = NULL; + } +} + static void lib_link_scene(FileData *fd, Main *main) { #ifdef USE_SETSCENE_CHECK @@ -5933,24 +6004,7 @@ static void lib_link_scene(FileData *fd, Main *main) lib_link_scene_collection(fd, sce->id.lib, sce->collection); for (ViewLayer *view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { - /* tag scene layer to update for collection tree evaluation */ - view_layer->flag |= VIEW_LAYER_ENGINE_DIRTY; - - for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) { - fmc->script = newlibadr(fd, sce->id.lib, fmc->script); - } - - for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) { - fls->linestyle = newlibadr_us(fd, sce->id.lib, fls->linestyle); - fls->group = newlibadr_us(fd, sce->id.lib, fls->group); - } - - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - /* we only bump the use count for the collection objects */ - base->object = newlibadr(fd, sce->id.lib, base->object); - base->flag |= BASE_DIRTY_ENGINE_SETTINGS; - base->collection_properties = NULL; - } + lib_link_view_layer(fd, sce->id.lib, view_layer); } #ifdef USE_SETSCENE_CHECK @@ -6092,17 +6146,56 @@ static void direct_link_layer_collections(FileData *fd, ListBase *lb) } } +static void direct_link_view_layer(FileData *fd, ViewLayer *view_layer) +{ + view_layer->stats = NULL; + link_list(fd, &view_layer->object_bases); + view_layer->basact = newdataadr(fd, view_layer->basact); + direct_link_layer_collections(fd, &view_layer->layer_collections); + + if (view_layer->properties != NULL) { + view_layer->properties = newdataadr(fd, view_layer->properties); + BLI_assert(view_layer->properties != NULL); + IDP_DirectLinkGroup_OrFree(&view_layer->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + BKE_view_layer_engine_settings_validate_layer(view_layer); + } + + view_layer->id_properties = newdataadr(fd, view_layer->id_properties); + IDP_DirectLinkGroup_OrFree(&view_layer->id_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + + link_list(fd, &(view_layer->freestyle_config.modules)); + link_list(fd, &(view_layer->freestyle_config.linesets)); + + view_layer->properties_evaluated = NULL; + + BLI_listbase_clear(&view_layer->drawdata); +} + /** * Workspaces store a render layer pointer which can only be read after scene is read. */ static void direct_link_workspace_link_scene_data( - FileData *fd, const Scene *scene, const ListBase *workspaces) + FileData *fd, Scene *scene, const ListBase *workspaces) { for (WorkSpace *workspace = workspaces->first; workspace; workspace = workspace->id.next) { - ViewLayer *layer = newdataadr(fd, BKE_workspace_view_layer_get(workspace)); - /* only set when layer is from the scene we read */ - if (layer && (BLI_findindex(&scene->view_layers, layer) != -1)) { - BKE_workspace_view_layer_set(workspace, layer); + for (WorkSpaceDataRelation *relation = workspace->scene_viewlayer_relations.first; + relation != NULL; + relation = relation->next) + { + ViewLayer *layer = newdataadr(fd, relation->value); + if (layer) { + BLI_assert(BLI_findindex(&scene->view_layers, layer) != -1); + /* relation->parent is set in lib_link_workspaces */ + relation->value = layer; + } + } + + if (workspace->view_layer) { /* this was temporariliy used during 2.8 project. Keep files compatible */ + ViewLayer *layer = newdataadr(fd, workspace->view_layer); + /* only set when layer is from the scene we read */ + if (layer && (BLI_findindex(&scene->view_layers, layer) != -1)) { + workspace->view_layer = layer; + } } } } @@ -6363,27 +6456,7 @@ static void direct_link_scene(FileData *fd, Scene *sce, Main *bmain) /* insert into global old-new map for reading without UI (link_global accesses it again) */ link_glob_list(fd, &sce->view_layers); for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { - view_layer->stats = NULL; - link_list(fd, &view_layer->object_bases); - view_layer->basact = newdataadr(fd, view_layer->basact); - direct_link_layer_collections(fd, &view_layer->layer_collections); - - if (view_layer->properties != NULL) { - view_layer->properties = newdataadr(fd, view_layer->properties); - BLI_assert(view_layer->properties != NULL); - IDP_DirectLinkGroup_OrFree(&view_layer->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - BKE_view_layer_engine_settings_validate_layer(view_layer); - } - - view_layer->id_properties = newdataadr(fd, view_layer->id_properties); - IDP_DirectLinkGroup_OrFree(&view_layer->id_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - - link_list(fd, &(view_layer->freestyle_config.modules)); - link_list(fd, &(view_layer->freestyle_config.linesets)); - - view_layer->properties_evaluated = NULL; - - BLI_listbase_clear(&view_layer->drawdata); + direct_link_view_layer(fd, view_layer); } sce->collection_properties = newdataadr(fd, sce->collection_properties); @@ -7046,6 +7119,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm) wm->addonconf = NULL; wm->userconf = NULL; + wm->message_bus = NULL; + BLI_listbase_clear(&wm->jobs); BLI_listbase_clear(&wm->drags); @@ -7476,7 +7551,7 @@ void blo_lib_link_restore(Main *newmain, wmWindowManager *curwm, Scene *curscene for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) { lib_link_workspace_layout_restore(id_map, newmain, layout); } - BKE_workspace_view_layer_set(workspace, cur_view_layer); + BKE_workspace_view_layer_set(workspace, cur_view_layer, curscene); } for (wmWindow *win = curwm->windows.first; win; win = win->next) { @@ -7753,30 +7828,61 @@ static void direct_link_group(FileData *fd, Group *group) link_list(fd, &group->gobject); group->preview = direct_link_preview_image(fd, group->preview); + + /* This runs before the very first doversion. */ + if (group->collection != NULL) { + group->collection = newdataadr(fd, group->collection); + direct_link_scene_collection(fd, group->collection); + } + + if (group->view_layer != NULL) { + group->view_layer = newdataadr(fd, group->view_layer); + direct_link_view_layer(fd, group->view_layer); + } } static void lib_link_group(FileData *fd, Main *main) { for (Group *group = main->group.first; group; group = group->id.next) { if (group->id.tag & LIB_TAG_NEED_LINK) { + group->id.tag &= ~LIB_TAG_NEED_LINK; IDP_LibLinkProperty(group->id.properties, fd); - - bool add_us = false; - - for (GroupObject *go = group->gobject.first; go; go = go->next) { - go->ob = newlibadr_real_us(fd, group->id.lib, go->ob); - if (go->ob) { - go->ob->flag |= OB_FROMGROUP; - /* if group has an object, it increments user... */ - add_us = true; + + if (group->view_layer == NULL) { + /* Old file, this is required for doversion. */ + bool add_us = false; + + GroupObject *go, *gon; + go = group->gobject.first; + while (go) { + gon = go->next; + go->ob = newlibadr_real_us(fd, group->id.lib, go->ob); + if (go->ob != NULL) { + go->ob->flag |= OB_FROMGROUP; + /* If group has an object, it increments user... */ + add_us = true; + } + else { + /* Remove NULL objects. */ + BLI_remlink(&group->gobject, go); + MEM_freeN(go); + } + go = gon; } + + if (add_us) { + id_us_ensure_real(&group->id); + } + /* The rest of the read code is only for new files, skip it. */ + continue; } - if (add_us) { + + lib_link_scene_collection(fd, group->id.lib, group->collection); + lib_link_view_layer(fd, group->id.lib, group->view_layer); + + if (!BLI_listbase_is_empty(&group->view_layer->object_bases)) { id_us_ensure_real(&group->id); } - BKE_group_object_unlink(group, NULL); /* removes NULL entries */ - - group->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -8708,6 +8814,8 @@ static void lib_link_all(FileData *fd, Main *main) { oldnewmap_sort(fd); + lib_link_id(fd, main); + /* No load UI for undo memfiles */ if (fd->memfile == NULL) { lib_link_windowmanager(fd, main); @@ -8933,6 +9041,12 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false); + /* Now that all our data-blocks are loaded, we can re-generate overrides from their references. */ + if (fd->memfile == NULL) { + /* Do not apply in undo case! */ + BKE_main_override_static_update(bfd->main); + } + lib_verify_nodetree(bfd->main, true); fix_relpaths_library(fd->relabase, bfd->main); /* make all relative paths, relative to the open blend file */ @@ -9371,6 +9485,11 @@ static void expand_group(FileData *fd, Main *mainvar, Group *group) for (go = group->gobject.first; go; go = go->next) { expand_doit(fd, mainvar, go->ob); } + + if (group->collection != NULL) { + expand_scene_collection(fd, mainvar, group->collection); + } + } static void expand_key(FileData *fd, Main *mainvar, Key *key) @@ -10197,7 +10316,7 @@ static void give_base_to_objects( scene_collection = get_scene_collection_active_or_create(scene, view_layer, FILE_ACTIVE_COLLECTION); } - BKE_collection_object_add(scene, scene_collection, ob); + BKE_collection_object_add(&scene->id, scene_collection, ob); base = BKE_view_layer_base_find(view_layer, ob); BKE_scene_object_base_flag_sync_from_base(base); @@ -10239,7 +10358,7 @@ static void give_base_to_groups( ob = BKE_object_add_only_object(mainvar, OB_EMPTY, group->id.name + 2); ob->type = OB_EMPTY; - BKE_collection_object_add(scene, scene_collection, ob); + BKE_collection_object_add(&scene->id, scene_collection, ob); base = BKE_view_layer_base_find(view_layer, ob); if (base->flag & BASE_SELECTABLED) { @@ -10280,12 +10399,14 @@ static ID *create_placeholder(Main *mainvar, const short idcode, const char *idn /* returns true if the item was found * but it may already have already been appended/linked */ static ID *link_named_part( - Main *mainl, FileData *fd, const short idcode, const char *name, - const bool use_placeholders, const bool force_indirect) + Main *mainl, FileData *fd, const short idcode, const char *name, const int flag) { BHead *bhead = find_bhead_from_code_name(fd, idcode, name); ID *id; + const bool use_placeholders = (flag & BLO_LIBLINK_USE_PLACEHOLDERS) != 0; + const bool force_indirect = (flag & BLO_LIBLINK_FORCE_INDIRECT) != 0; + BLI_assert(BKE_idcode_is_linkable(idcode) && BKE_idcode_is_valid(idcode)); if (bhead) { @@ -10325,7 +10446,8 @@ static ID *link_named_part( return id; } -static SceneCollection *get_scene_collection_active_or_create(struct Scene *scene, struct ViewLayer *view_layer, const short flag) +static SceneCollection *get_scene_collection_active_or_create( + struct Scene *scene, struct ViewLayer *view_layer, const int flag) { LayerCollection *lc = NULL; @@ -10333,14 +10455,14 @@ static SceneCollection *get_scene_collection_active_or_create(struct Scene *scen lc = BKE_layer_collection_get_active_ensure(scene, view_layer); } else { - SceneCollection *sc = BKE_collection_add(scene, NULL, NULL); + SceneCollection *sc = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL); lc = BKE_collection_link(view_layer, sc); } return lc->scene_collection; } -static void link_object_postprocess(ID *id, Scene *scene, ViewLayer *view_layer, const short flag) +static void link_object_postprocess(ID *id, Scene *scene, ViewLayer *view_layer, const int flag) { if (scene) { /* link to scene */ @@ -10352,7 +10474,7 @@ static void link_object_postprocess(ID *id, Scene *scene, ViewLayer *view_layer, ob->mode = OB_MODE_OBJECT; sc = get_scene_collection_active_or_create(scene, view_layer, flag); - BKE_collection_object_add(scene, sc, ob); + BKE_collection_object_add(&scene->id, sc, ob); base = BKE_view_layer_base_find(view_layer, ob); BKE_scene_object_base_flag_sync_from_base(base); @@ -10402,10 +10524,10 @@ void BLO_library_link_copypaste(Main *mainl, BlendHandle *bh) } static ID *link_named_part_ex( - Main *mainl, FileData *fd, const short idcode, const char *name, const short flag, - Scene *scene, ViewLayer *view_layer, const bool use_placeholders, const bool force_indirect) + Main *mainl, FileData *fd, const short idcode, const char *name, const int flag, + Scene *scene, ViewLayer *view_layer) { - ID *id = link_named_part(mainl, fd, idcode, name, use_placeholders, force_indirect); + ID *id = link_named_part(mainl, fd, idcode, name, flag); if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */ link_object_postprocess(id, scene, view_layer, flag); @@ -10431,7 +10553,7 @@ static ID *link_named_part_ex( ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name) { FileData *fd = (FileData*)(*bh); - return link_named_part(mainl, fd, idcode, name, false, false); + return link_named_part(mainl, fd, idcode, name, 0); } /** @@ -10445,18 +10567,15 @@ ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcod * \param flag Options for linking, used for instantiating. * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done). * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL). - * \param use_placeholders If true, generate a placeholder (empty ID) if not found in current lib file. - * \param force_indirect If true, force loaded ID to be tagged as LIB_TAG_INDIRECT (used in reload context only). * \return the linked ID when found. */ ID *BLO_library_link_named_part_ex( Main *mainl, BlendHandle **bh, - const short idcode, const char *name, const short flag, - Scene *scene, ViewLayer *view_layer, - const bool use_placeholders, const bool force_indirect) + const short idcode, const char *name, const int flag, + Scene *scene, ViewLayer *view_layer) { FileData *fd = (FileData*)(*bh); - return link_named_part_ex(mainl, fd, idcode, name, flag, scene, view_layer, use_placeholders, force_indirect); + return link_named_part_ex(mainl, fd, idcode, name, flag, scene, view_layer); } static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id) @@ -10656,7 +10775,7 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done). * \param view_layer The scene layer in which to instantiate objects/groups (if NULL, no instantiation is done). */ -void BLO_library_link_end(Main *mainl, BlendHandle **bh, short flag, Scene *scene, ViewLayer *view_layer) +void BLO_library_link_end(Main *mainl, BlendHandle **bh, int flag, Scene *scene, ViewLayer *view_layer) { FileData *fd = (FileData*)(*bh); library_link_end(mainl, &fd, flag, scene, view_layer); diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index b945f5bdcd3..bf2d5c8e326 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -62,6 +62,8 @@ #include "BKE_animsys.h" #include "BKE_brush.h" #include "BKE_colortools.h" +#include "BKE_fcurve.h" +#include "BKE_gpencil.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_mask.h" @@ -71,7 +73,6 @@ #include "BKE_sequencer.h" #include "BKE_screen.h" #include "BKE_tracking.h" -#include "BKE_gpencil.h" #include "BLI_math.h" #include "BLI_listbase.h" @@ -285,6 +286,67 @@ static void do_versions_compositor_render_passes(bNodeTree *ntree) } } + +static char *replace_bbone_easing_rnapath(char *old_path) +{ + char *new_path = NULL; + + /* NOTE: This will break paths for any bones/custom-properties + * which happen be named after the bbone property id's + */ + if (strstr(old_path, "bbone_in")) + new_path = BLI_str_replaceN(old_path, "bbone_in", "bbone_easein"); + else if (strstr(old_path, "bbone_out")) + new_path = BLI_str_replaceN(old_path, "bbone_out", "bbone_easeout"); + + if (new_path) { + MEM_freeN(old_path); + return new_path; + } + else { + return old_path; + } +} + +static void do_version_bbone_easing_fcurve_fix(ID *UNUSED(id), FCurve *fcu, void *UNUSED(user_data)) +{ + /* F-Curve's path (for bbone_in/out) */ + if (fcu->rna_path) { + fcu->rna_path = replace_bbone_easing_rnapath(fcu->rna_path); + } + + /* Driver -> Driver Vars (for bbone_in/out) */ + if (fcu->driver) { + for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) { + DRIVER_TARGETS_LOOPER(dvar) + { + if (dtar->rna_path) { + dtar->rna_path = replace_bbone_easing_rnapath(dtar->rna_path); + } + } + DRIVER_TARGETS_LOOPER_END; + } + } + + /* FModifiers -> Stepped (for frame_start/end) */ + if (fcu->modifiers.first) { + for (FModifier *fcm = fcu->modifiers.first; fcm; fcm = fcm->next) { + if (fcm->type == FMODIFIER_TYPE_STEPPED) { + FMod_Stepped *data = fcm->data; + + /* Modifier doesn't work if the modifier's copy of start/end frame are both 0 + * as those were only getting written to the fcm->data copy (T52009) + */ + if ((fcm->sfra == fcm->efra) && (fcm->sfra == 0)) { + fcm->sfra = data->start_frame; + fcm->efra = data->end_frame; + } + } + } + } +} + + void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) { if (!MAIN_VERSION_ATLEAST(main, 270, 0)) { @@ -1742,4 +1804,10 @@ void do_versions_after_linking_270(Main *main) } } FOREACH_NODETREE_END } + + if (!MAIN_VERSION_ATLEAST(main, 279, 2)) { + /* B-Bones (bbone_in/out -> bbone_easein/out) + Stepped FMod Frame Start/End fix */ + /* if (!DNA_struct_elem_find(fd->filesdna, "Bone", "float", "bbone_easein")) */ + BKE_fcurves_main_cb(main, do_version_bbone_easing_fcurve_fix, NULL); + } } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 00d578918fa..84aab78ff18 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -39,8 +39,10 @@ #include "DNA_object_types.h" #include "DNA_camera_types.h" #include "DNA_gpu_types.h" +#include "DNA_group_types.h" #include "DNA_lamp_types.h" #include "DNA_layer_types.h" +#include "DNA_lightprobe_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_scene_types.h" @@ -52,6 +54,7 @@ #include "BKE_collection.h" #include "BKE_customdata.h" #include "BKE_freestyle.h" +#include "BKE_group.h" #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_main.h" @@ -87,8 +90,9 @@ static void do_version_workspaces_create_from_screens(Main *bmain) { for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { const bScreen *screen_parent = screen_parent_find(screen); + Scene *scene = screen->scene; WorkSpace *workspace; - ViewLayer *layer = BKE_view_layer_from_scene_get(screen->scene); + ViewLayer *layer = BKE_view_layer_from_scene_get(scene); ListBase *transform_orientations; if (screen_parent) { @@ -101,7 +105,7 @@ static void do_version_workspaces_create_from_screens(Main *bmain) workspace = BKE_workspace_add(bmain, screen->id.name + 2); } BKE_workspace_layout_add(workspace, screen, screen->id.name + 2); - BKE_workspace_view_layer_set(workspace, layer); + BKE_workspace_view_layer_set(workspace, layer, scene); #ifdef WITH_CLAY_ENGINE BLI_strncpy(workspace->view_render.engine_id, RE_engine_id_BLENDER_CLAY, @@ -112,7 +116,7 @@ static void do_version_workspaces_create_from_screens(Main *bmain) #endif transform_orientations = BKE_workspace_transform_orientations_get(workspace); - BLI_duplicatelist(transform_orientations, &screen->scene->transform_spaces); + BLI_duplicatelist(transform_orientations, &scene->transform_spaces); } } @@ -171,7 +175,7 @@ void do_versions_after_linking_280(Main *main) for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { /* since we don't have access to FileData we check the (always valid) first render layer instead */ if (scene->view_layers.first == NULL) { - SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc_master = BKE_collection_master(&scene->id); BLI_strncpy(sc_master->name, "Master Collection", sizeof(sc_master->name)); struct DoVersionSceneCollections { @@ -217,7 +221,7 @@ void do_versions_after_linking_280(Main *main) if (base->lay & (1 << layer)) { int collection_index = -1; if ((base->object->restrictflag & OB_RESTRICT_VIEW) && - (base->object->restrictflag & OB_RESTRICT_RENDER)) + (base->object->restrictflag & OB_RESTRICT_RENDER)) { collection_index = DO_VERSION_COLLECTION_HIDE_ALL; } @@ -242,7 +246,7 @@ void do_versions_after_linking_280(Main *main) layer + 1, collections[DO_VERSION_COLLECTION_VISIBLE].suffix); collections[DO_VERSION_COLLECTION_VISIBLE].collections[layer] = - BKE_collection_add(scene, sc_master, name); + BKE_collection_add(&scene->id, sc_master, COLLECTION_TYPE_NONE, name); collections[DO_VERSION_COLLECTION_VISIBLE].created |= (1 << layer); } @@ -254,12 +258,17 @@ void do_versions_after_linking_280(Main *main) "Collection %d%s", layer + 1, collections[collection_index].suffix); - collections[collection_index].collections[layer] = BKE_collection_add(scene, sc_parent, name); + collections[collection_index].collections[layer] = BKE_collection_add( + &scene->id, + sc_parent, + COLLECTION_TYPE_NONE, + name); collections[collection_index].created |= (1 << layer); } } - BKE_collection_object_add(scene, collections[collection_index].collections[layer], base->object); + BKE_collection_object_add( + &scene->id, collections[collection_index].collections[layer], base->object); } if (base->flag & SELECT) { @@ -281,18 +290,20 @@ void do_versions_after_linking_280(Main *main) (collections[DO_VERSION_COLLECTION_HIDE].collections[layer] != scene_collection_parent->scene_collections.first)) { - BLI_listbase_swaplinks(&scene_collection_parent->scene_collections, - collections[DO_VERSION_COLLECTION_HIDE].collections[layer], - scene_collection_parent->scene_collections.first); + BLI_listbase_swaplinks( + &scene_collection_parent->scene_collections, + collections[DO_VERSION_COLLECTION_HIDE].collections[layer], + scene_collection_parent->scene_collections.first); } if ((collections[DO_VERSION_COLLECTION_HIDE_ALL].created & (1 << layer)) && (collections[DO_VERSION_COLLECTION_HIDE_ALL].collections[layer] != scene_collection_parent->scene_collections.last)) { - BLI_listbase_swaplinks(&scene_collection_parent->scene_collections, - collections[DO_VERSION_COLLECTION_HIDE_ALL].collections[layer], - scene_collection_parent->scene_collections.last); + BLI_listbase_swaplinks( + &scene_collection_parent->scene_collections, + collections[DO_VERSION_COLLECTION_HIDE_ALL].collections[layer], + scene_collection_parent->scene_collections.last); } scene_collection_parent = scene_collection_parent->next; @@ -312,18 +323,18 @@ void do_versions_after_linking_280(Main *main) /* It is up to the external engine to handle * its own doversion in this case. */ BKE_override_view_layer_int_add( - view_layer, - ID_SCE, - "samples", - srl->samples); + view_layer, + ID_SCE, + "samples", + srl->samples); } if (srl->mat_override) { BKE_override_view_layer_datablock_add( - view_layer, - ID_MA, - "self", - (ID *)srl->mat_override); + view_layer, + ID_MA, + "self", + (ID *)srl->mat_override); } if (srl->layflag & SCE_LAY_DISABLE) { @@ -351,28 +362,29 @@ void do_versions_after_linking_280(Main *main) /* Add new collection bases. */ for (int layer = 0; layer < 20; layer++) { if ((scene->lay & srl->lay & ~(srl->lay_exclude) & (1 << layer)) || - (srl->lay_zmask & (scene->lay | srl->lay_exclude) & (1 << layer))) + (srl->lay_zmask & (scene->lay | srl->lay_exclude) & (1 << layer))) { if (collections[DO_VERSION_COLLECTION_VISIBLE].created & (1 << layer)) { LayerCollection *layer_collection_parent; - layer_collection_parent = BKE_collection_link(view_layer, - collections[DO_VERSION_COLLECTION_VISIBLE].collections[layer]); + layer_collection_parent = BKE_collection_link( + view_layer, + collections[DO_VERSION_COLLECTION_VISIBLE].collections[layer]); if (srl->lay_zmask & (1 << layer)) { BKE_override_layer_collection_boolean_add( - layer_collection_parent, - ID_OB, - "cycles.is_holdout", - true); + layer_collection_parent, + ID_OB, + "cycles.is_holdout", + true); } if ((srl->lay & (1 << layer)) == 0) { BKE_override_layer_collection_boolean_add( - layer_collection_parent, - ID_OB, - "cycles_visibility.camera", - false); + layer_collection_parent, + ID_OB, + "cycles_visibility.camera", + false); } LayerCollection *layer_collection_child; @@ -380,7 +392,8 @@ void do_versions_after_linking_280(Main *main) for (int j = 1; j < 4; j++) { if (collections[j].created & (1 << layer)) { - layer_collection_child->flag = collections[j].flag_render & (~COLLECTION_DISABLED); + layer_collection_child->flag = + collections[j].flag_render & (~COLLECTION_DISABLED); if (collections[j].flag_render & COLLECTION_DISABLED) { BKE_collection_disable(view_layer, layer_collection_child); @@ -429,7 +442,8 @@ void do_versions_after_linking_280(Main *main) /* If layer was not set, disable it. */ LayerCollection *layer_collection_parent; - layer_collection_parent = ((LayerCollection *)view_layer->layer_collections.first)->layer_collections.first; + layer_collection_parent = + ((LayerCollection *)view_layer->layer_collections.first)->layer_collections.first; for (int layer = 0; layer < 20; layer++) { if (collections[DO_VERSION_COLLECTION_VISIBLE].created & (1 << layer)) { @@ -475,7 +489,7 @@ void do_versions_after_linking_280(Main *main) } /* Fallback name if only one layer was found in the original file */ - if (BLI_listbase_count_ex(&sc_master->scene_collections, 2) == 1) { + if (BLI_listbase_is_single(&sc_master->scene_collections)) { BKE_collection_rename(scene, sc_master->scene_collections.first, "Default Collection"); } @@ -553,6 +567,59 @@ void do_versions_after_linking_280(Main *main) } } } + + { + for (WorkSpace *workspace = main->workspaces.first; workspace; workspace = workspace->id.next) { + if (workspace->view_layer) { + /* During 2.8 work we temporarly stored view-layer in the + * workspace directly, but should be stored there per-scene. */ + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + if (BLI_findindex(&scene->view_layers, workspace->view_layer) != -1) { + BKE_workspace_view_layer_set(workspace, workspace->view_layer, scene); + workspace->view_layer = NULL; + } + } + } + BLI_assert(workspace->view_layer == NULL); + } + } + + { + /* Since we don't have access to FileData we check the (always valid) master collection of the group. */ + for (Group *group = main->group.first; group; group = group->id.next) { + if (group->collection == NULL) { + BKE_group_init(group); + SceneCollection *sc = GROUP_MASTER_COLLECTION(group); + SceneCollection *sc_hidden = NULL; + + for (GroupObject *go = group->gobject.first; go; go = go->next) { + if (go->ob->lay & group->layer) { + BKE_collection_object_add(&group->id, sc, go->ob); + } + else { + if (sc_hidden == NULL) { + sc_hidden = BKE_collection_add(&group->id, sc, COLLECTION_TYPE_GROUP_INTERNAL, "Hidden"); + } + BKE_collection_object_add(&group->id, sc_hidden, go->ob); + } + } + + if (sc_hidden != NULL) { + LayerCollection *layer_collection_master, *layer_collection_hidden; + + layer_collection_master = group->view_layer->layer_collections.first; + layer_collection_hidden = layer_collection_master->layer_collections.first; + + layer_collection_hidden->flag &= ~COLLECTION_VISIBLE; + } + } + + GroupObject *go; + while ((go = BLI_pophead(&group->gobject))) { + MEM_freeN(go); + } + } + } } static void do_version_layer_collections_idproperties(ListBase *lb) @@ -682,6 +749,13 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } + if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "vis_bias")) { + for (LightProbe *probe = main->lightprobe.first; probe; probe = probe->id.next) { + probe->vis_bias = 1.0f; + probe->vis_blur = 0.2f; + } + } + typedef enum eNTreeDoVersionErrors { NTREE_DOVERSION_NO_ERROR = 0, NTREE_DOVERSION_NEED_OUTPUT = (1 << 0), diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 36c524796ce..156a6e3d1c0 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -1871,7 +1871,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) BKE_pose_tag_recalc(main, ob->pose); /* cannot call stuff now (pointers!), done in setup_app_data */ - ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME; + ob->id.tag |= LIB_TAG_ID_RECALC_ALL; /* new generic xray option */ arm = blo_do_versions_newlibadr(fd, lib, ob->data); diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 90f15d41408..0f9f509bfde 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -168,8 +168,10 @@ #include "BKE_curve.h" #include "BKE_constraint.h" #include "BKE_global.h" // for G +#include "BKE_group.h" #include "BKE_idcode.h" #include "BKE_library.h" // for set_listbasepointers +#include "BKE_library_override.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_report.h" @@ -683,6 +685,25 @@ static void write_iddata(void *wd, const ID *id) if (id->properties && !ELEM(GS(id->name), ID_WM)) { IDP_WriteProperty(id->properties, wd); } + + if (id->override_static) { + writestruct(wd, DATA, IDOverrideStatic, 1, id->override_static); + + writelist(wd, DATA, IDOverrideStaticProperty, &id->override_static->properties); + for (IDOverrideStaticProperty *op = id->override_static->properties.first; op; op = op->next) { + writedata(wd, DATA, strlen(op->rna_path) + 1, op->rna_path); + + writelist(wd, DATA, IDOverrideStaticPropertyOperation, &op->operations); + for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) { + if (opop->subitem_reference_name) { + writedata(wd, DATA, strlen(opop->subitem_reference_name) + 1, opop->subitem_reference_name); + } + if (opop->subitem_local_name) { + writedata(wd, DATA, strlen(opop->subitem_local_name) + 1, opop->subitem_local_name); + } + } + } + } } static void write_previews(WriteData *wd, const PreviewImage *prv_orig) @@ -1118,7 +1139,7 @@ static void current_screen_compat( *r_screen = (window) ? BKE_workspace_active_screen_get(window->workspace_hook) : NULL; *r_scene = (window) ? window->scene : NULL; - *r_render_layer = (window) ? BKE_workspace_view_layer_get(workspace) : NULL; + *r_render_layer = (window) ? BKE_workspace_view_layer_get(workspace, *r_scene) : NULL; } typedef struct RenderInfo { @@ -1328,9 +1349,13 @@ static void write_particlesettings(WriteData *wd, ParticleSettings *part) if (dw->ob != NULL) { dw->index = 0; if (part->dup_group) { /* can be NULL if lining fails or set to None */ - for (GroupObject *go = part->dup_group->gobject.first; - go && go->ob != dw->ob; - go = go->next, dw->index++); + FOREACH_GROUP_OBJECT(part->dup_group, object) + { + if (object != dw->ob) { + dw->index++; + } + } + FOREACH_GROUP_OBJECT_END } } writestruct(wd, DATA, ParticleDupliWeight, 1, dw); @@ -2592,6 +2617,28 @@ static void write_layer_collections(WriteData *wd, ListBase *lb) } } +static void write_view_layer(WriteData *wd, ViewLayer *view_layer) +{ + writestruct(wd, DATA, ViewLayer, 1, view_layer); + writelist(wd, DATA, Base, &view_layer->object_bases); + if (view_layer->properties) { + IDP_WriteProperty(view_layer->properties, wd); + } + + if (view_layer->id_properties) { + IDP_WriteProperty(view_layer->id_properties, wd); + } + + for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) { + writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc); + } + + for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) { + writestruct(wd, DATA, FreestyleLineSet, 1, fls); + } + write_layer_collections(wd, &view_layer->layer_collections); +} + static void write_scene(WriteData *wd, Scene *sce) { /* write LibData */ @@ -2688,6 +2735,9 @@ static void write_scene(WriteData *wd, Scene *sce) case SEQ_TYPE_TEXT: writestruct(wd, DATA, TextVars, 1, seq->effectdata); break; + case SEQ_TYPE_COLORMIX: + writestruct(wd, DATA, ColorMixVars, 1, seq->effectdata); + break; } } @@ -2772,26 +2822,7 @@ static void write_scene(WriteData *wd, Scene *sce) write_scene_collection(wd, sce->collection); for (ViewLayer *view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { - writestruct(wd, DATA, ViewLayer, 1, view_layer); - writelist(wd, DATA, Base, &view_layer->object_bases); - - if (view_layer->properties) { - IDP_WriteProperty(view_layer->properties, wd); - } - - if (view_layer->id_properties) { - IDP_WriteProperty(view_layer->id_properties, wd); - } - - for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) { - writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc); - } - - for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) { - writestruct(wd, DATA, FreestyleLineSet, 1, fls); - } - - write_layer_collections(wd, &view_layer->layer_collections); + write_view_layer(wd, view_layer); } if (sce->layer_properties) { @@ -3225,10 +3256,8 @@ static void write_group(WriteData *wd, Group *group) write_iddata(wd, &group->id); write_previews(wd, group->preview); - - for (GroupObject *go = group->gobject.first; go; go = go->next) { - writestruct(wd, DATA, GroupObject, 1, go); - } + write_scene_collection(wd, group->collection); + write_view_layer(wd, group->view_layer); } } @@ -3770,6 +3799,7 @@ static void write_workspace(WriteData *wd, WorkSpace *workspace) writestruct(wd, ID_WS, WorkSpace, 1, workspace); writelist(wd, DATA, WorkSpaceLayout, layouts); writelist(wd, DATA, WorkSpaceDataRelation, &workspace->hook_layout_relations); + writelist(wd, DATA, WorkSpaceDataRelation, &workspace->scene_viewlayer_relations); writelist(wd, DATA, TransformOrientation, transform_orientations); } @@ -3804,6 +3834,8 @@ static void write_libraries(WriteData *wd, Main *main) /* XXX needs rethink, just like save UI in undo files now - would be nice to append things only for the] * quit.blend and temp saves */ if (found_one) { + /* Not overridable. */ + writestruct(wd, ID_LI, Library, 1, main->curlib); write_iddata(wd, &main->curlib->id); @@ -3938,137 +3970,159 @@ static bool write_file_handle( * avoid thumbnail detecting changes because of this. */ mywrite_flush(wd); - ListBase *lbarray[MAX_LIBARRAY]; - int a = set_listbasepointers(mainvar, lbarray); - while (a--) { - ID *id = lbarray[a]->first; + OverrideStaticStorage *override_storage = !wd->current ? BKE_override_static_operations_store_initialize() : NULL; - if (id && GS(id->name) == ID_LI) { - continue; /* Libraries are handled separately below. */ - } + /* This outer loop allows to save first datablocks from real mainvar, then the temp ones from override process, + * if needed, without duplicating whole code. */ + Main *bmain = mainvar; + do { + ListBase *lbarray[MAX_LIBARRAY]; + int a = set_listbasepointers(bmain, lbarray); + while (a--) { + ID *id = lbarray[a]->first; - for (; id; id = id->next) { - /* We should never attempt to write non-regular IDs (i.e. all kind of temp/runtime ones). */ - BLI_assert((id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0); + if (id && GS(id->name) == ID_LI) { + continue; /* Libraries are handled separately below. */ + } - switch ((ID_Type)GS(id->name)) { - case ID_WM: - write_windowmanager(wd, (wmWindowManager *)id); - break; - case ID_WS: - write_workspace(wd, (WorkSpace *)id); - break; - case ID_SCR: - write_screen(wd, (bScreen *)id); - break; - case ID_MC: - write_movieclip(wd, (MovieClip *)id); - break; - case ID_MSK: - write_mask(wd, (Mask *)id); - break; - case ID_SCE: - write_scene(wd, (Scene *)id); - break; - case ID_CU: - write_curve(wd, (Curve *)id); - break; - case ID_MB: - write_mball(wd, (MetaBall *)id); - break; - case ID_IM: - write_image(wd, (Image *)id); - break; - case ID_CA: - write_camera(wd, (Camera *)id); - break; - case ID_LA: - write_lamp(wd, (Lamp *)id); - break; - case ID_LT: - write_lattice(wd, (Lattice *)id); - break; - case ID_VF: - write_vfont(wd, (VFont *)id); - break; - case ID_KE: - write_key(wd, (Key *)id); - break; - case ID_WO: - write_world(wd, (World *)id); - break; - case ID_TXT: - write_text(wd, (Text *)id); - break; - case ID_SPK: - write_speaker(wd, (Speaker *)id); - break; - case ID_LP: - write_probe(wd, (LightProbe *)id); - break; - case ID_SO: - write_sound(wd, (bSound *)id); - break; - case ID_GR: - write_group(wd, (Group *)id); - break; - case ID_AR: - write_armature(wd, (bArmature *)id); - break; - case ID_AC: - write_action(wd, (bAction *)id); - break; - case ID_OB: - write_object(wd, (Object *)id); - break; - case ID_MA: - write_material(wd, (Material *)id); - break; - case ID_TE: - write_texture(wd, (Tex *)id); - break; - case ID_ME: - write_mesh(wd, (Mesh *)id); - break; - case ID_PA: - write_particlesettings(wd, (ParticleSettings *)id); - break; - case ID_NT: - write_nodetree(wd, (bNodeTree *)id); - break; - case ID_BR: - write_brush(wd, (Brush *)id); - break; - case ID_PAL: - write_palette(wd, (Palette *)id); - break; - case ID_PC: - write_paintcurve(wd, (PaintCurve *)id); - break; - case ID_GD: - write_gpencil(wd, (bGPdata *)id); - break; - case ID_LS: - write_linestyle(wd, (FreestyleLineStyle *)id); - break; - case ID_CF: - write_cachefile(wd, (CacheFile *)id); - break; - case ID_LI: - /* Do nothing, handled below - and should never be reached. */ - BLI_assert(0); - break; - case ID_IP: - /* Do nothing, deprecated. */ - break; - default: - /* Should never be reached. */ - BLI_assert(0); - break; + for (; id; id = id->next) { + /* We should never attempt to write non-regular IDs (i.e. all kind of temp/runtime ones). */ + BLI_assert((id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0); + + const bool do_override = !ELEM(override_storage, NULL, bmain) && id->override_static; + + if (do_override) { + BKE_override_static_operations_store_start(override_storage, id); + } + + switch ((ID_Type)GS(id->name)) { + case ID_WM: + write_windowmanager(wd, (wmWindowManager *)id); + break; + case ID_WS: + write_workspace(wd, (WorkSpace *)id); + break; + case ID_SCR: + write_screen(wd, (bScreen *)id); + break; + case ID_MC: + write_movieclip(wd, (MovieClip *)id); + break; + case ID_MSK: + write_mask(wd, (Mask *)id); + break; + case ID_SCE: + write_scene(wd, (Scene *)id); + break; + case ID_CU: + write_curve(wd, (Curve *)id); + break; + case ID_MB: + write_mball(wd, (MetaBall *)id); + break; + case ID_IM: + write_image(wd, (Image *)id); + break; + case ID_CA: + write_camera(wd, (Camera *)id); + break; + case ID_LA: + write_lamp(wd, (Lamp *)id); + break; + case ID_LT: + write_lattice(wd, (Lattice *)id); + break; + case ID_VF: + write_vfont(wd, (VFont *)id); + break; + case ID_KE: + write_key(wd, (Key *)id); + break; + case ID_WO: + write_world(wd, (World *)id); + break; + case ID_TXT: + write_text(wd, (Text *)id); + break; + case ID_SPK: + write_speaker(wd, (Speaker *)id); + break; + case ID_LP: + write_probe(wd, (LightProbe *)id); + break; + case ID_SO: + write_sound(wd, (bSound *)id); + break; + case ID_GR: + write_group(wd, (Group *)id); + break; + case ID_AR: + write_armature(wd, (bArmature *)id); + break; + case ID_AC: + write_action(wd, (bAction *)id); + break; + case ID_OB: + write_object(wd, (Object *)id); + break; + case ID_MA: + write_material(wd, (Material *)id); + break; + case ID_TE: + write_texture(wd, (Tex *)id); + break; + case ID_ME: + write_mesh(wd, (Mesh *)id); + break; + case ID_PA: + write_particlesettings(wd, (ParticleSettings *)id); + break; + case ID_NT: + write_nodetree(wd, (bNodeTree *)id); + break; + case ID_BR: + write_brush(wd, (Brush *)id); + break; + case ID_PAL: + write_palette(wd, (Palette *)id); + break; + case ID_PC: + write_paintcurve(wd, (PaintCurve *)id); + break; + case ID_GD: + write_gpencil(wd, (bGPdata *)id); + break; + case ID_LS: + write_linestyle(wd, (FreestyleLineStyle *)id); + break; + case ID_CF: + write_cachefile(wd, (CacheFile *)id); + break; + case ID_LI: + /* Do nothing, handled below - and should never be reached. */ + BLI_assert(0); + break; + case ID_IP: + /* Do nothing, deprecated. */ + break; + default: + /* Should never be reached. */ + BLI_assert(0); + break; + } + + if (do_override) { + BKE_override_static_operations_store_end(override_storage, id); + } } + + mywrite_flush(wd); } + } while ((bmain != override_storage) && (bmain = override_storage)); - mywrite_flush(wd); + if (override_storage) { + BKE_override_static_operations_store_finalize(override_storage); + override_storage = NULL; } /* Special handling, operating over split Mains... */ diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index 432c82afe4a..1b96237e262 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -254,8 +254,8 @@ void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode) /* both loops only set edge/face flags and read off verts */ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) && - BM_elem_flag_test(e->v2, BM_ELEM_SELECT) && - !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + BM_elem_flag_test(e->v2, BM_ELEM_SELECT) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { BM_elem_flag_enable(e, BM_ELEM_SELECT); } @@ -366,8 +366,8 @@ void BM_mesh_select_flush(BMesh *bm) BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) && - BM_elem_flag_test(e->v2, BM_ELEM_SELECT) && - !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + BM_elem_flag_test(e->v2, BM_ELEM_SELECT) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { BM_elem_flag_enable(e, BM_ELEM_SELECT); } diff --git a/source/blender/bmesh/operators/bmo_rotate_edges.c b/source/blender/bmesh/operators/bmo_rotate_edges.c index dd6bf77dd3c..9832fdb57d3 100644 --- a/source/blender/bmesh/operators/bmo_rotate_edges.c +++ b/source/blender/bmesh/operators/bmo_rotate_edges.c @@ -18,7 +18,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/bmesh/operators/bmo_rotate_edge.c +/** \file blender/bmesh/operators/bmo_rotate_edges.c * \ingroup bmesh * * Rotate edges topology that share two faces. diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 51a0fa4b2cc..2c6213dacce 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -117,7 +117,7 @@ typedef struct Profile { float *prof_co; /* seg+1 profile coordinates (triples of floats) */ float *prof_co_2; /* like prof_co, but for seg power of 2 >= seg */ } Profile; -#define PRO_SQUARE_R 4.0f +#define PRO_SQUARE_R 1e4f #define PRO_CIRCLE_R 2.0f #define PRO_LINE_R 1.0f #define PRO_SQUARE_IN_R 0.0f @@ -126,8 +126,10 @@ typedef struct Profile { * get even spacing on superellipse for current BevelParams seg * and pro_super_r. */ typedef struct ProfileSpacing { - float *uvals; /* seg+1 u values */ - float *uvals_2; /* seg_2+1 u values, seg_2 = power of 2 >= seg */ + double *xvals; /* seg+1 x values */ + double *xvals_2; /* seg_2+1 x values, seg_2 = power of 2 >= seg */ + double *yvals; /* seg+1 y values */ + double *yvals_2; /* seg_2+1 y values, seg_2 = power of 2 >= seg */ int seg_2; /* the seg_2 value */ } ProfileSpacing; @@ -1383,56 +1385,21 @@ static void make_unit_cube_map( r_mat[3][3] = 1.0f; } -/* Get the coordinate on the superellipse (exponent r), - * at parameter value u. u goes from u to 2 as the - * superellipse moves on the quadrant (0,1) to (1,0). */ -static void superellipse_co(float u, float r, float r_co[2]) +/* Get the coordinate on the superellipse (x^r + y^r = 1), + * at parameter value x (or, if !rbig, mirrored (y=x)-line). + * rbig should be true if r > 1.0 and false if <= 1.0. + * Assume r > 0.0 */ +static double superellipse_co(double x, float r, bool rbig) { - float t; - - if (u <= 0.0f) { - r_co[0] = 0.0f; - r_co[1] = 1.0f; - } - else if (u >= 2.0f) { - r_co[0] = 1.0f; - r_co[1] = 0.0f; - } - else if (r == PRO_LINE_R) { - t = u / 2.0f; - r_co[0] = t; - r_co[1] = 1.0f - t; - - } - else if (r == PRO_SQUARE_IN_R) { - if (u < 1.0f) { - r_co[0] = 0.0f; - r_co[1] = 1.0f - u; - } - else { - r_co[0] = u - 1.0f; - r_co[1] = 0.0f; - } - } - else if (r == PRO_SQUARE_R) { - if (u < 1.0f) { - r_co[0] = u; - r_co[1] = 1.0f; - } - else { - r_co[0] = 1.0f; - r_co[1] = 2.0f - u; - } - + BLI_assert(r > 0.0f); + + /* If r<1, mirror the superellipse function by (y=x)-line to get a numerically stable range + * Possible because of symmetry, later mirror back. */ + if (rbig) { + return pow((1.0 - pow(x, r)), (1.0 / r)); } else { - t = u * (float)M_PI / 4.0f; /* angle from y axis */ - r_co[0] = sinf(t); - r_co[1] = cosf(t); - if (r != PRO_SQUARE_R) { - r_co[0] = pow(r_co[0], 2.0f / r); - r_co[1] = pow(r_co[1], 2.0f / r); - } + return 1.0 - pow((1.0 - pow(1.0 - x, r)), (1.0 / r)); } } @@ -1478,7 +1445,7 @@ static void get_profile_point(BevelParams *bp, const Profile *pro, int i, int n, static void calculate_profile(BevelParams *bp, BoundVert *bndv) { int i, k, ns; - const float *uvals; + const double *xvals, *yvals; float co[3], co2[3], p[3], m[4][4]; float *prof_co, *prof_co_k; float r; @@ -1504,17 +1471,19 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv) for (i = 0; i < 2; i++) { if (i == 0) { ns = bp->seg; - uvals = bp->pro_spacing.uvals; + xvals = bp->pro_spacing.xvals; + yvals = bp->pro_spacing.yvals; prof_co = pro->prof_co; } else { if (!need_2) break; /* shares coords with pro->prof_co */ ns = bp->pro_spacing.seg_2; - uvals = bp->pro_spacing.uvals_2; + xvals = bp->pro_spacing.xvals_2; + yvals = bp->pro_spacing.yvals_2; prof_co = pro->prof_co_2; } - BLI_assert((r == PRO_LINE_R || uvals != NULL) && prof_co != NULL); + BLI_assert((r == PRO_LINE_R || (xvals != NULL && yvals != NULL)) && prof_co != NULL); for (k = 0; k <= ns; k++) { if (k == 0) copy_v3_v3(co, pro->coa); @@ -1522,7 +1491,8 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv) copy_v3_v3(co, pro->cob); else { if (map_ok) { - superellipse_co(uvals[k], r, p); + p[0] = xvals[k]; + p[1] = yvals[k]; p[2] = 0.0f; mul_v3_m4v3(co, m, p); } @@ -2581,9 +2551,8 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm0) return vm1; } -/* Special case for cube corner, when r is PRO_SQUARE_R, - * meaning straight sides */ -static VMesh *make_cube_corner_straight(MemArena *mem_arena, int nseg) +/* Special case for cube corner, when r is PRO_SQUARE_R, meaning straight sides */ +static VMesh *make_cube_corner_square(MemArena *mem_arena, int nseg) { VMesh *vm; float co[3]; @@ -2613,6 +2582,46 @@ static VMesh *make_cube_corner_straight(MemArena *mem_arena, int nseg) return vm; } +/* Special case for cube corner, when r is PRO_SQUARE_IN_R, meaning inward + * straight sides. + * We mostly don't want a VMesh at all for this case -- just a three-way weld + * with a triangle in the middle for odd nseg */ +static VMesh *make_cube_corner_square_in(MemArena *mem_arena, int nseg) +{ + VMesh *vm; + float co[3]; + float b; + int i, k, ns2, odd; + + ns2 = nseg / 2; + odd = nseg % 2; + vm = new_adj_vmesh(mem_arena, 3, nseg, NULL); + vm->count = 0; // reset, so following loop will end up with correct count + for (i = 0; i < 3; i++) { + zero_v3(co); + co[i] = 1.0f; + add_new_bound_vert(mem_arena, vm, co); + } + if (odd) + b = 2.0f / (2.0f * (float)ns2 + (float)M_SQRT2); + else + b = 2.0f / (float)nseg; + for (i = 0; i < 3; i++) { + for (k = 0; k <= ns2; k++) { + co[i] = 1.0f - (float)k * b; + co[(i + 1) % 3] = 0.0f; + co[(i + 2) % 3] = 0.0f; + copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co); + co[(i + 1) % 3] = 1.0f - (float)k * b; + co[(i + 2) % 3] = 0.0f; + co[i] = 0.0f; + copy_v3_v3(mesh_vert(vm, i, 0, nseg - k)->co, co); + } + } + return vm; +} + + /* Make a VMesh with nseg segments that covers the unit radius sphere octant * with center at (0,0,0). * This has BoundVerts at (1,0,0), (0,1,0) and (0,0,1), with quarter circle arcs @@ -2629,7 +2638,9 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) float co[3], coc[3]; if (r == PRO_SQUARE_R) - return make_cube_corner_straight(mem_arena, nseg); + return make_cube_corner_square(mem_arena, nseg); + else if (r == PRO_SQUARE_IN_R) + return make_cube_corner_square_in(mem_arena, nseg); /* initial mesh has 3 sides, 2 segments */ vm0 = new_adj_vmesh(mem_arena, 3, 2, NULL); @@ -2687,6 +2698,7 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) } } } + return vm1; } @@ -2944,6 +2956,87 @@ static float snap_face_dist_squared(float *co, BMFace *f, BMEdge **r_snap_e, flo return beste_d2; } +static void build_center_ngon(BMesh *bm, BevVert *bv, int mat_nr) +{ + VMesh *vm = bv->vmesh; + BoundVert *v; + int i, ns2; + BMFace *frep; + BMEdge *frep_e1, *frep_e2, *frep_e; + BMVert **vv = NULL; + BMFace **vf = NULL; + BMEdge **ve = NULL; + BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE); + BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE); + BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE); + + ns2 = vm->seg / 2; + if (bv->any_seam) { + frep = boundvert_rep_face(vm->boundstart, NULL); + get_incident_edges(frep, bv->v, &frep_e1, &frep_e2); + } + else { + frep = NULL; + frep_e1 = frep_e2 = NULL; + } + v = vm->boundstart; + do { + i = v->index; + BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v); + if (frep) { + BLI_array_append(vf, frep); + frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2); + BLI_array_append(ve, v == vm->boundstart ? NULL : frep_e); + } + else { + BLI_array_append(vf, boundvert_rep_face(v, NULL)); + BLI_array_append(ve, NULL); + } + } while ((v = v->next) != vm->boundstart); + bev_create_ngon(bm, vv, BLI_array_count(vv), vf, frep, ve, mat_nr, true); + + BLI_array_free(vv); + BLI_array_free(vf); + BLI_array_free(ve); +} + +/* Special case of bevel_build_rings when tri-corner and profile is 0. + * There is no corner mesh except, if nseg odd, for a center poly. + * Boundary verts merge with previous ones according to pattern: + * (i, 0, k) merged with (i+1, 0, ns-k) for k <= ns/2 */ +static void build_square_in_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv, VMesh *vm1) +{ + int n, ns, ns2, odd, i, k; + VMesh *vm; + + vm = bv->vmesh; + n = vm->count; + ns = vm->seg; + ns2 = ns / 2; + odd = ns % 2; + + for (i = 0; i < n; i++) { + for (k = 1; k < ns; k++) { + copy_v3_v3(mesh_vert(vm, i, 0, k)->co, mesh_vert(vm1, i, 0, k)->co); + if (i > 0 && k <= ns2) { + mesh_vert(vm, i, 0, k)->v = mesh_vert(vm, i - 1, 0, ns - k)->v; + } + else if (i == n - 1 && k > ns2) { + mesh_vert(vm, i, 0, k)->v = mesh_vert(vm, 0, 0, ns - k)->v; + } + else { + create_mesh_bmvert(bm, vm, i, 0, k, bv->v); + } + } + } + if (odd) { + for (i = 0; i < n; i++) { + mesh_vert(vm, i, ns2, ns2)->v = mesh_vert(vm, i, 0, ns2)->v; + } + build_center_ngon(bm, bv, bp->mat_nr); + } +} + /* * Given that the boundary is built and the boundary BMVerts have been made, * calculate the positions of the interior mesh points for the M_ADJ pattern, @@ -2968,12 +3061,21 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv) vpipe = pipe_test(bv); - if (vpipe) + if (vpipe) { vm1 = pipe_adj_vmesh(bp, bv, vpipe); - else if (tri_corner_test(bp, bv)) + } + else if (tri_corner_test(bp, bv)) { vm1 = tri_corner_adj_vmesh(bp, bv); - else + /* the PRO_SQUARE_IN_R profile has boundary edges that merge + * and no internal ring polys except possibly center ngon */ + if (bp->pro_super_r == PRO_SQUARE_IN_R) { + build_square_in_vmesh(bp, bm, bv, vm1); + return; + } + } + else { vm1 = adj_vmesh(bp, bv); + } /* copy final vmesh into bv->vmesh, make BMVerts and BMFaces */ vm = bv->vmesh; @@ -3086,42 +3188,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv) /* center ngon */ if (odd) { - BMFace *frep; - BMEdge *frep_e1, *frep_e2, *frep_e; - BMVert **vv = NULL; - BMFace **vf = NULL; - BMEdge **ve = NULL; - BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE); - BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE); - BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE); - - if (bv->any_seam) { - frep = boundvert_rep_face(vm->boundstart, NULL); - get_incident_edges(frep, bv->v, &frep_e1, &frep_e2); - } - else { - frep = NULL; - frep_e1 = frep_e2 = NULL; - } - v = vm->boundstart; - do { - i = v->index; - BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v); - if (frep) { - BLI_array_append(vf, frep); - frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2); - BLI_array_append(ve, v == vm->boundstart ? NULL : frep_e); - } - else { - BLI_array_append(vf, boundvert_rep_face(v, NULL)); - BLI_array_append(ve, NULL); - } - } while ((v = v->next) != vm->boundstart); - bev_create_ngon(bm, vv, BLI_array_count(vv), vf, frep, ve, mat_nr, true); - - BLI_array_free(vv); - BLI_array_free(vf); - BLI_array_free(ve); + build_center_ngon(bm, bv, mat_nr); } } @@ -4389,143 +4456,296 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) } } -/* Returns the square of the length of the chord from parameter u0 to parameter u1 - * of superellipse_co. */ -static float superellipse_chord_length_squared(float u0, float u1, float r) -{ - float a[2], b[2]; - BLI_assert(u0 >= 0.0f && u1 >= u0 && u1 <= 2.0f); - superellipse_co(u0, r, a); - superellipse_co(u1, r, b); - return len_squared_v2v2(a, b); +/* Find xnew > x0 so that distance((x0,y0), (xnew, ynew)) = dtarget. + * False position Illinois method used because the function is somewhat linear + * -> linear interpolation converges fast. + * Assumes that the gradient is always between 1 and -1 for + * x in [x0, x0+dtarget] */ +static double find_superellipse_chord_endpoint(double x0, double dtarget, float r, bool rbig) +{ + double xmin, xmax, ymin, ymax, dmaxerr, dminerr, dnewerr, xnew, ynew; + double y0 = superellipse_co(x0, r, rbig); + const double tol = 1e-13; // accumulates for many segments so use low value + const int maxiter = 10; + bool lastupdated_upper; + + /* For gradient between -1 and 1, xnew can only be in + * [x0 + sqrt(2)/2*dtarget, x0 + dtarget]. */ + xmin = x0 + M_SQRT2 / 2.0 * dtarget; + if (xmin > 1.0) + xmin = 1.0; + xmax = x0 + dtarget; + if (xmax > 1.0) + xmax = 1.0; + ymin = superellipse_co(xmin, r, rbig); + ymax = superellipse_co(xmax, r, rbig); + + /* Note: using distance**2 (no sqrt needed) does not converge that well. */ + dmaxerr = sqrt(pow((xmax - x0), 2) + pow((ymax - y0), 2)) - dtarget; + dminerr = sqrt(pow((xmin - x0), 2) + pow((ymin - y0), 2)) - dtarget; + + xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr); + lastupdated_upper = true; + + for (int iter = 0; iter < maxiter; iter++) { + ynew = superellipse_co(xnew, r, rbig); + dnewerr = sqrt(pow((xnew - x0), 2) + pow((ynew - y0), 2)) - dtarget; + if (fabs(dnewerr) < tol) { + break; + } + if (dnewerr < 0) { + xmin = xnew; + ymin = ynew; + dminerr = dnewerr; + if (!lastupdated_upper) { + xnew = (dmaxerr / 2 * xmin - dminerr * xmax) / (dmaxerr / 2 - dminerr); + } + else { + xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr); + } + lastupdated_upper = false; + } + else { + xmax = xnew; + ymax = ynew; + dmaxerr = dnewerr; + if (lastupdated_upper) { + xnew = (dmaxerr * xmin - dminerr / 2 * xmax) / (dmaxerr - dminerr / 2); + } + else { + xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr); + } + lastupdated_upper = true; + } + } + return xnew; } -/* Find parameter u >= u0 to make chord of squared length d2goal, - * from u0 to u on superellipse with parameter r. - * If it cannot be found, return -1.0f. */ -static float find_superellipse_chord_u(float u0, float d2goal, float r) + /* This search procedure to find equidistant points (x,y) in the first + * superellipse quadrant works for every superellipse exponent but is more + * expensive than known solutions for special cases. + * Call the point on superellipse that intersects x=y line mx. + * For r>=1 use only the range x in [0,mx] and mirror the rest along x=y line, + * for r<1 use only x in [mx,1]. Points are initially spaced and iteratively + * repositioned to have the same distance. */ + +static void find_even_superellipse_chords_general(int seg, float r, double *xvals, double *yvals) { - float ulow, uhigh, u, d2, d2max; - const float dtol = 1e-4f; - const float utol = 1e-6f; - const float umax = 2.0f; - - if (d2goal == 0.0f) - return u0; - d2max = superellipse_chord_length_squared(u0, umax, r); - if (fabsf(d2goal - d2max) <= dtol) - return umax; - if (d2goal - d2max > dtol) - return -1.0f; - - /* binary search for good u value */ - ulow = u0; - uhigh = umax; - do { - u = 0.5f * (ulow + uhigh); - d2 = superellipse_chord_length_squared(u0, u, r); - if (fabsf(d2goal - d2) <= dtol) + const int smoothitermax = 10; + const double error_tol = 1e-7; + int i; + int imax = (seg + 1) / 2 - 1; /* ceiling division - 1 */ + + double d, dmin, dmax; + double davg; + double mx; + double sum; + double temp; + + bool precision_reached; + bool seg_odd = seg % 2; + bool rbig; + + if (r > 1.0f) { + rbig = true; + mx = pow(0.5, 1.0 / r); + } + else { + rbig = false; + mx = 1 - pow(0.5, 1.0 / r); + } + + /* Initial positions, linear spacing along x axis. */ + for (i = 0; i <= imax; i++) { + xvals[i] = i * mx / seg * 2; + yvals[i] = superellipse_co(xvals[i], r, rbig); + } + yvals[0] = 1; + + /* Smooth distance loop */ + for (int iter = 0; iter < smoothitermax; iter++) { + sum = 0.0; + dmin = 2.0; + dmax = 0.0; + /* Update distances between neighbor points. Store the highest and + * lowest to see if the maximum error to average distance (which isn't + * known yet) is below required precision. */ + for (i = 0; i < imax; i++) { + d = sqrt(pow((xvals[i + 1] - xvals[i]), 2) + pow((yvals[i + 1] - yvals[i]), 2)); + sum += d; + if (d > dmax) { + dmax = d; + } + if (d < dmin) { + dmin = d; + } + } + /* For last distance, weight with 1/2 if seg_odd. */ + if (seg_odd) { + sum += M_SQRT2 / 2 * (yvals[imax] - xvals[imax]); + davg = sum / (imax + 0.5); + } + else { + sum += sqrt(pow((xvals[imax] - mx), 2) + pow((yvals[imax] - mx), 2)); + davg = sum / (imax + 1.0); + } + /* Max error in tolerance? -> Quit. */ + if (dmax - davg > error_tol) { + precision_reached = false; + } + if (dmin - davg < error_tol) { + precision_reached = false; + } + if (precision_reached) { break; - if (d2 < d2goal) - ulow = u; - else - uhigh = u; - } while (fabsf(uhigh - ulow) > utol); - return u; + } + + + /* Update new coordinates. */ + for (i = 1; i <= imax; i++) { + xvals[i] = find_superellipse_chord_endpoint(xvals[i - 1], davg, r, rbig); + yvals[i] = superellipse_co(xvals[i], r, rbig); + } + } + + /* Fill remaining. */ + if (!seg_odd) { + xvals[imax + 1] = mx; + yvals[imax + 1] = mx; + } + for (i = imax + 1; i <= seg; i++) { + yvals[i] = xvals[seg - i]; + xvals[i] = yvals[seg - i]; + } + + if (!rbig) { + for (i = 0; i <= seg; i++) { + temp = xvals[i]; + xvals[i] = 1.0 - yvals[i]; + yvals[i] = 1.0 - temp; + } + } } -/* Find parameters u0, u1, ..., un that divide the quarter-arc superellipse - * with parameter r into n even chords. - * There is no closed form way of doing this except for a few special - * values of r, so this uses binary search to find a chord length that works. - * Return the u's in *r_params, which should point to an array of size n+1. */ -static void find_even_superellipse_params(int n, float r, float *r_params) + /* Find equidistant points (x0,y0), (x1,y1)... (xn,yn) on the superellipse + * function in the first quadrant. For special profiles (linear, arc, + * rectangle) the point can be calculated easily, for any other profile a more + * expensive search procedure must be used because there is no known closed + * form for equidistant parametrization + * xvals and yvals should be size n+1 */ + +static void find_even_superellipse_chords(int n, float r, double *xvals, double *yvals) { - float d2low, d2high, d2 = 0.0f, d2final, u; - int i, j, n2; - const int maxiters = 40; - const float d2tol = 1e-6f; - const float umax = 2.0f; - - if (r == PRO_CIRCLE_R || r == PRO_LINE_R || - ((n % 2 == 0) && (r == PRO_SQUARE_IN_R || r == PRO_SQUARE_R))) - { - /* even parameter spacing works for these cases */ - for (i = 0; i <= n; i++) - r_params[i] = i * 2.0f / (float) n; + int i, n2; + double temp; + bool seg_odd = n % 2; + + n2 = n / 2; + + /* Special cases. */ + if (r == PRO_LINE_R) { + /* Linear spacing */ + for (i = 0; i <= n; i++) { + xvals[i] = (double) i / n; + yvals[i] = 1.0 - (double) i / n; + } return; } - if (r == PRO_SQUARE_IN_R || r == PRO_SQUARE_R) { - /* n is odd, so get one corner-cut chord. - * Solve u == sqrt(2*(1-n2*u)^2) where n2 = floor(n/2) */ - n2 = n / 2; - u = (2.0f * n2 - (float)M_SQRT2) / (2.0f * n2 * n2 - 1.0f); - for (i = 0; i < n; i++) - r_params[i] = i * u; - r_params[n] = umax; - } - d2low = 2.0f / (n * n); /* (sqrt(2)/n)**2 */ - d2high = 2 * d2low; /* (2/n)**2 */ - for (i = 0; i < maxiters && fabsf(d2high - d2low) > d2tol; i++) { - d2 = 0.5f * (d2low + d2high); - - /* find where we are after n-1 chords of squared length d2 */ - u = 0.0f; - for (j = 0; j < n - 1; j++) { - u = find_superellipse_chord_u(u, d2, r); - if (u == -1.0f) - break; /* d2 is too big to go n-1 chords */ - } - if (u == -1.0f) { - d2high = d2; - continue; + if (r == PRO_CIRCLE_R) { + temp = (M_PI / 2) / n; + /* Angle spacing. */ + for (i = 0; i <= n; i++) { + xvals[i] = sin(i * temp); + yvals[i] = cos(i * temp); } - d2final = superellipse_chord_length_squared(u, umax, r); - if (fabsf(d2final - d2) <= d2tol) - break; - if (d2final < d2) - d2high = d2; - else - d2low = d2; + return; } - u = 0.0f; - for (i = 0; i < n; i++) { - r_params[i] = u; - u = find_superellipse_chord_u(u, d2, r); + if (r == PRO_SQUARE_IN_R) { + /* n is even, distribute first and second half linear. */ + if (!seg_odd) { + for (i = 0; i <= n2; i++) { + xvals[i] = 0.0; + yvals[i] = 1.0 - (double) i / n2; + xvals[n - i] = yvals[i]; + yvals[n - i] = xvals[i]; + } + } + /* n is odd, so get one corner-cut chord. */ + else { + temp = 1.0 / (n2 + M_SQRT2 / 2.0); + for (i = 0; i <= n2; i++) { + xvals[i] = 0.0; + yvals[i] = 1.0 - (double) i * temp; + xvals[n -i ] = yvals[i]; + yvals[n - i] = xvals[i]; + } + } + return; } - r_params[n] = umax; + if (r == PRO_SQUARE_R) { + /* n is even, distribute first and second half linear. */ + if (!seg_odd) { + for (i = 0; i <= n2; i++) { + xvals[i] = (double) i / n2; + yvals[i] = 1.0; + xvals[n - i] = yvals[i]; + yvals[n - i] = xvals[i]; + } + } + /* n is odd, so get one corner-cut chord. */ + else { + temp = 1.0 / (n2 + M_SQRT2 / 2); + for (i = 0; i <= n2; i++) { + xvals[i] = (double) i * temp; + yvals[i] = 1.0; + xvals[n - i] = yvals[i]; + yvals[n - i] = xvals[i]; + } + } + return; + } + /* For general case use the more expensive search algorithm. */ + find_even_superellipse_chords_general(n, r, xvals, yvals); } + /* The superellipse used for multisegment profiles does not * have a closed-form way to generate evenly spaced points * along an arc. We use an expensive search procedure to find * the parameter values that lead to bp->seg even chords. * We also want spacing for a number of segments that is - * a power of 2 >= bp->seg (but at least 4). */ + * a power of 2 >= bp->seg (but at least 4). + * Use doubles because otherwise we cannot come close to float + * precision for final results. */ static void set_profile_spacing(BevelParams *bp) { int seg, seg_2; seg = bp->seg; if (seg > 1) { - bp->pro_spacing.uvals = (float *)BLI_memarena_alloc(bp->mem_arena, (seg + 1) * sizeof(float)); - find_even_superellipse_params(seg, bp->pro_super_r, bp->pro_spacing.uvals); + bp->pro_spacing.xvals = (double *)BLI_memarena_alloc(bp->mem_arena, (seg + 1) * sizeof(double)); + bp->pro_spacing.yvals = (double *)BLI_memarena_alloc(bp->mem_arena, (seg + 1) * sizeof(double)); + find_even_superellipse_chords(seg, bp->pro_super_r, bp->pro_spacing.xvals, bp->pro_spacing.yvals); seg_2 = power_of_2_max_i(bp->seg); if (seg_2 == 2) seg_2 = 4; bp->pro_spacing.seg_2 = seg_2; if (seg_2 == seg) { - bp->pro_spacing.uvals_2 = bp->pro_spacing.uvals; + bp->pro_spacing.xvals_2 = bp->pro_spacing.xvals; + bp->pro_spacing.yvals_2 = bp->pro_spacing.yvals; } else { - bp->pro_spacing.uvals_2 = (float *)BLI_memarena_alloc(bp->mem_arena, (seg_2 + 1) * sizeof(float)); - find_even_superellipse_params(seg_2, bp->pro_super_r, bp->pro_spacing.uvals_2); + bp->pro_spacing.xvals_2 = (double *)BLI_memarena_alloc(bp->mem_arena, (seg_2 + 1) * sizeof(double)); + bp->pro_spacing.yvals_2 = (double *)BLI_memarena_alloc(bp->mem_arena, (seg_2 + 1) * sizeof(double)); + find_even_superellipse_chords(seg_2, bp->pro_super_r, bp->pro_spacing.xvals_2, bp->pro_spacing.yvals_2); } } else { - bp->pro_spacing.uvals = NULL; - bp->pro_spacing.uvals_2 = NULL; + bp->pro_spacing.xvals = NULL; + bp->pro_spacing.yvals = NULL; + bp->pro_spacing.xvals_2 = NULL; + bp->pro_spacing.yvals_2 = NULL; bp->pro_spacing.seg_2 = 0; } } @@ -4754,7 +4974,7 @@ void BM_mesh_bevel( bp.offset = offset; bp.offset_type = offset_type; bp.seg = segments; - bp.pro_super_r = 4.0f * profile; /* convert to superellipse exponent */ + bp.pro_super_r = -log(2.0) / log(sqrt(profile)); /* convert to superellipse exponent */ bp.vertex_only = vertex_only; bp.use_weights = use_weights; bp.loop_slide = loop_slide; @@ -4763,8 +4983,9 @@ void BM_mesh_bevel( bp.vertex_group = vertex_group; bp.mat_nr = mat; - if (bp.pro_super_r < 0.60f) - bp.pro_super_r = 0.60f; /* TODO: implement 0 case properly */ + if (profile >= 0.999f) { /* r ~ 692, so PRO_SQUARE_R is 1e4 */ + bp.pro_super_r = PRO_SQUARE_R; + } if (bp.offset > 0) { /* primary alloc */ diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 8908d0e603f..d3e23f740c8 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -267,7 +267,7 @@ void DocumentImporter::finish() std::vector<Object *>::iterator it; for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) { Object *ob = *it; - BKE_collections_object_remove(G.main, sce, ob, true); + BKE_collections_object_remove(G.main, &sce->id, ob, true); } libnode_ob.clear(); diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp index aa98f2ee96c..c375c09d869 100644 --- a/source/blender/collada/SceneExporter.cpp +++ b/source/blender/collada/SceneExporter.cpp @@ -26,6 +26,7 @@ extern "C" { #include "BLI_utildefines.h" + #include "BKE_group.h" #include "BKE_object.h" #include "BLI_listbase.h" } @@ -177,12 +178,13 @@ void SceneExporter::writeNodes(const EvaluationContext *eval_ctx, Object *ob, Sc // empty object else if (ob->type == OB_EMPTY) { // TODO: handle groups (OB_DUPLIGROUP if ((ob->transflag & OB_DUPLIGROUP) == OB_DUPLIGROUP && ob->dup_group) { - GroupObject *go = NULL; - Group *gr = ob->dup_group; - /* printf("group detected '%s'\n", gr->id.name + 2); */ - for (go = (GroupObject *)(gr->gobject.first); go; go = go->next) { - printf("\t%s\n", go->ob->id.name); + Group *group = ob->dup_group; + /* printf("group detected '%s'\n", group->id.name + 2); */ + FOREACH_GROUP_OBJECT(group, object) + { + printf("\t%s\n", object->id.name); } + FOREACH_GROUP_OBJECT_END } } diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index 1a6f2675cc7..6a52027fb47 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -147,7 +147,7 @@ Object *bc_add_object(Scene *scene, int type, const char *name) ViewLayer *view_layer = BKE_view_layer_context_active_PLACEHOLDER(scene); LayerCollection *layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer); - BKE_collection_object_add(scene, layer_collection->scene_collection, ob); + BKE_collection_object_add(&scene->id, layer_collection->scene_collection, ob); Base *base = BKE_view_layer_base_find(view_layer, ob); BKE_view_layer_base_select(view_layer, base); diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index 8b1ce5a9926..9495321a0ff 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -65,6 +65,8 @@ set(SRC intern/depsgraph_debug.cc intern/depsgraph_eval.cc intern/depsgraph_query.cc + intern/depsgraph_query_foreach.cc + intern/depsgraph_query_iter.cc intern/depsgraph_tag.cc intern/depsgraph_type_defines.cc @@ -78,6 +80,7 @@ set(SRC intern/builder/deg_builder_nodes.h intern/builder/deg_builder_pchanmap.h intern/builder/deg_builder_relations.h + intern/builder/deg_builder_relations_impl.h intern/builder/deg_builder_transitive.h intern/eval/deg_eval.h intern/eval/deg_eval_copy_on_write.h diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index 7b1f1fc8ca9..6bcbff4950b 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -86,7 +86,7 @@ typedef struct EvaluationContext { struct Depsgraph *depsgraph; struct ViewLayer *view_layer; - struct RenderEngineType *engine; + struct RenderEngineType *engine_type; } EvaluationContext; /* DagNode->eval_flags */ @@ -151,9 +151,9 @@ enum { DEG_TAG_TIME = (1 << 2), /* Particle system changed. */ - DEG_TAG_PSYSC_REDO = (1 << 3), - DEG_TAG_PSYS_RESET = (1 << 4), - DEG_TAG_PSYS_TYPE = (1 << 5), + DEG_TAG_PSYSC_REDO = (1 << 3), + DEG_TAG_PSYS_RESET = (1 << 4), + DEG_TAG_PSYS_TYPE = (1 << 5), DEG_TAG_PSYS_CHILD = (1 << 6), DEG_TAG_PSYS_PHYS = (1 << 7), DEG_TAG_PSYS = ((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)), @@ -167,6 +167,9 @@ enum { DEG_TAG_SHADING_UPDATE = (1 << 9), DEG_TAG_SELECT_UPDATE = (1 << 10), DEG_TAG_BASE_FLAGS_UPDATE = (1 << 11), + + /* Only inform editors about the change. Don't modify datablock itself. */ + DEG_TAG_EDITORS_UPDATE = (1 << 12), }; void DEG_id_tag_update(struct ID *id, int flag); void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag); @@ -176,10 +179,9 @@ void DEG_graph_id_tag_update(struct Main *bmain, struct ID *id, int flag); -/* Tag given ID type for update. - * - * Used by all sort of render engines to quickly check if - * IDs of a given type need to be checked for update. +/* Mark a particular datablock type as having changing. This does + * not cause any updates but is used by external render engines to detect if for + * example a datablock was removed. */ void DEG_id_type_tag(struct Main *bmain, short id_type); @@ -195,6 +197,7 @@ void DEG_graph_flush_update(struct Main *bmain, Depsgraph *depsgraph); */ void DEG_ids_check_recalc(struct Main *bmain, struct Scene *scene, + struct ViewLayer *view_layer, bool time); /* ************************************************ */ @@ -214,7 +217,7 @@ void DEG_evaluation_context_init(struct EvaluationContext *eval_ctx, void DEG_evaluation_context_init_from_scene(struct EvaluationContext *eval_ctx, struct Scene *scene, struct ViewLayer *view_layer, - struct RenderEngineType *engine, + struct RenderEngineType *engine_type, eEvaluationMode mode); /* Free evaluation context. */ @@ -245,20 +248,21 @@ bool DEG_needs_eval(Depsgraph *graph); * to do their own updates based on changes. */ -typedef void (*DEG_EditorUpdateIDCb)(struct Main *bmain, struct ID *id); -typedef void (*DEG_EditorUpdateSceneCb)(struct Main *bmain, - struct Scene *scene, - int updated); -typedef void (*DEG_EditorUpdateScenePreCb)(struct Main *bmain, - struct Scene *scene, - bool time); +typedef struct DEGEditorUpdateContext { + struct Main *bmain; + struct Scene *scene; + struct ViewLayer *view_layer; +} DEGEditorUpdateContext; + +typedef void (*DEG_EditorUpdateIDCb)( + const DEGEditorUpdateContext *update_ctx, + struct ID *id); +typedef void (*DEG_EditorUpdateSceneCb)( + const DEGEditorUpdateContext *update_ctx, int updated); /* Set callbacks which are being called when depsgraph changes. */ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, - DEG_EditorUpdateSceneCb scene_func, - DEG_EditorUpdateScenePreCb scene_pre_func); - -void DEG_editors_update_pre(struct Main *bmain, struct Scene *scene, bool time); + DEG_EditorUpdateSceneCb scene_func); #ifdef __cplusplus } /* extern "C" */ diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index 36d44a06eac..7771d35d581 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -67,16 +67,16 @@ struct Object *DEG_get_evaluated_object(struct Depsgraph *depsgraph, struct Obje /* Get evaluated version of given ID datablock. */ struct ID *DEG_get_evaluated_id(struct Depsgraph *depsgraph, struct ID *id); -/* ************************ DAG iterators ********************* */ +/* ************************ DEG iterators ********************* */ enum { - DEG_OBJECT_ITER_FLAG_SET = (1 << 0), - DEG_OBJECT_ITER_FLAG_DUPLI = (1 << 1), -}; + DEG_ITER_OBJECT_FLAG_SET = (1 << 0), + DEG_ITER_OBJECT_FLAG_DUPLI = (1 << 1), -#define DEG_OBJECT_ITER_FLAG_ALL (DEG_OBJECT_ITER_FLAG_SET | DEG_OBJECT_ITER_FLAG_DUPLI) + DEG_ITER_OBJECT_FLAG_ALL = (DEG_ITER_OBJECT_FLAG_SET | DEG_ITER_OBJECT_FLAG_DUPLI), +}; -typedef struct DEGObjectsIteratorData { +typedef struct DEGOIterObjectData { struct Depsgraph *graph; struct Scene *scene; struct EvaluationContext eval_ctx; @@ -103,28 +103,40 @@ typedef struct DEGObjectsIteratorData { /* **** Iteration ober ID nodes **** */ size_t id_node_index; size_t num_id_nodes; -} DEGObjectsIteratorData; +} DEGOIterObjectData; -void DEG_objects_iterator_begin(struct BLI_Iterator *iter, DEGObjectsIteratorData *data); -void DEG_objects_iterator_next(struct BLI_Iterator *iter); -void DEG_objects_iterator_end(struct BLI_Iterator *iter); +void DEG_iterator_objects_begin(struct BLI_Iterator *iter, DEGOIterObjectData *data); +void DEG_iterator_objects_next(struct BLI_Iterator *iter); +void DEG_iterator_objects_end(struct BLI_Iterator *iter); #define DEG_OBJECT_ITER(graph_, instance_, flag_) \ { \ - DEGObjectsIteratorData data_ = { \ + DEGOIterObjectData data_ = { \ .graph = (graph_), \ .flag = (flag_), \ }; \ \ - ITER_BEGIN(DEG_objects_iterator_begin, \ - DEG_objects_iterator_next, \ - DEG_objects_iterator_end, \ + ITER_BEGIN(DEG_iterator_objects_begin, \ + DEG_iterator_objects_next, \ + DEG_iterator_objects_end, \ &data_, Object *, instance_) #define DEG_OBJECT_ITER_END \ ITER_END \ } +/* ************************ DEG traversal ********************* */ + +typedef void (*DEGForeachIDCallback)(ID *id, void *user_data); + +/* NOTE: Modifies runtime flags in depsgraph nodes, so can not be used in + * parallel. Keep an eye on that! + */ +void DEG_foreach_dependent_ID(const Depsgraph *depsgraph, + const ID *id, + DEGForeachIDCallback callback, void *user_data); + + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index d6a054f2ee9..20a93673350 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -55,12 +55,6 @@ void deg_graph_build_finalize(Main *bmain, Depsgraph *graph) if ((id->tag & LIB_TAG_ID_RECALC_ALL)) { id_node->tag_update(graph); } - else if (GS(id->name) == ID_OB) { - Object *object = (Object *)id; - if (object->recalc & OB_RECALC_ALL) { - id_node->tag_update(graph); - } - } /* TODO(sergey): This is not ideal at all, since this forces * re-evaluaiton of the whole tree. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index a2a0f633fd9..8fbd1e7a46d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -180,7 +180,7 @@ DepsgraphNodeBuilder::~DepsgraphNodeBuilder() IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id, bool do_tag) { if (!DEG_depsgraph_use_copy_on_write()) { - return graph_->add_id_node(id); + return graph_->add_id_node(id, do_tag); } IDDepsNode *id_node = NULL; ID *id_cow = (ID *)BLI_ghash_lookup(cow_id_hash_, id); @@ -428,9 +428,11 @@ void DepsgraphNodeBuilder::build_group(Group *group) } group_id->tag |= LIB_TAG_DOIT; - LINKLIST_FOREACH (GroupObject *, go, &group->gobject) { - build_object(NULL, go->ob, DEG_ID_LINKED_INDIRECTLY); + LINKLIST_FOREACH(Base *, base, &group->view_layer->object_bases) { + build_object(NULL, base->object, DEG_ID_LINKED_INDIRECTLY); } + + build_view_layer_collections(&group->id, group->view_layer); } void DepsgraphNodeBuilder::build_object(Base *base, @@ -583,7 +585,6 @@ void DepsgraphNodeBuilder::build_object_transform(Object *object) op_node = add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM, function_bind(BKE_object_eval_local_transform, _1, - scene_cow, ob_cow), DEG_OPCODE_TRANSFORM_LOCAL); op_node->set_as_entry(); @@ -607,7 +608,6 @@ void DepsgraphNodeBuilder::build_object_transform(Object *object) add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM, function_bind(BKE_object_eval_uber_transform, _1, - scene_cow, ob_cow), DEG_OPCODE_TRANSFORM_OBJECT_UBEREVAL); @@ -804,8 +804,8 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene) /* objects - simulation participants */ if (rbw->group) { - LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) { - Object *object = go->ob; + LINKLIST_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) { + Object *object = base->object; if (!object || (object->type != OB_MESH)) continue; @@ -1241,6 +1241,9 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) * pipeline. No need to build dependencies for them here. */ } + else if (id_type == ID_TXT) { + /* Ignore script nodes. */ + } else if (bnode->type == NODE_GROUP) { bNodeTree *group_ntree = (bNodeTree *)id; if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 5c0a5054590..c9bdd194227 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -208,11 +208,13 @@ struct DepsgraphNodeBuilder { int index; LayerCollection *parent; }; - void build_layer_collection(LayerCollection *layer_collection, + void build_layer_collection(ID *owner_id, + LayerCollection *layer_collection, LayerCollectionState *state); - void build_layer_collections(ListBase *layer_collections, + void build_layer_collections(ID *owner_id, + ListBase *layer_collections, LayerCollectionState *state); - void build_view_layer_collections(Scene *scene, ViewLayer *view_layer); + void build_view_layer_collections(ID *owner_id, ViewLayer *view_layer); protected: struct SavedEntryTag { ID *id; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc index 4d4bf2e4ffe..79316e47022 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/builder/deg_builder_nodes_layer.cc +/** \file blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc * \ingroup depsgraph * * Methods for constructing depsgraph's nodes @@ -62,6 +62,7 @@ extern "C" { namespace DEG { void DepsgraphNodeBuilder::build_layer_collection( + ID *owner_id, LayerCollection *layer_collection, LayerCollectionState *state) { @@ -69,7 +70,7 @@ void DepsgraphNodeBuilder::build_layer_collection( * Harmless but could be optimized. */ ComponentDepsNode *comp = add_component_node( - &scene_->id, + owner_id, DEG_NODE_TYPE_LAYER_COLLECTIONS); add_operation_node(comp, @@ -85,31 +86,32 @@ void DepsgraphNodeBuilder::build_layer_collection( /* Recurs into nested layer collections. */ LayerCollection *parent = state->parent; state->parent = layer_collection; - build_layer_collections(&layer_collection->layer_collections, state); + build_layer_collections(owner_id, &layer_collection->layer_collections, state); state->parent = parent; } -void DepsgraphNodeBuilder::build_layer_collections(ListBase *layer_collections, +void DepsgraphNodeBuilder::build_layer_collections(ID *owner_id, + ListBase *layer_collections, LayerCollectionState *state) { LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) { - build_layer_collection(layer_collection, state); + build_layer_collection(owner_id, layer_collection, state); } } void DepsgraphNodeBuilder::build_view_layer_collections( - Scene *scene, + ID *owner_id, ViewLayer *view_layer) { LayerCollectionState state; state.index = 0; ComponentDepsNode *comp = add_component_node( - &scene_->id, + owner_id, DEG_NODE_TYPE_LAYER_COLLECTIONS); add_operation_node(comp, function_bind(BKE_layer_eval_layer_collection_pre, _1, - scene, + owner_id, view_layer), DEG_OPCODE_VIEW_LAYER_INIT); add_operation_node(comp, @@ -118,7 +120,7 @@ void DepsgraphNodeBuilder::build_view_layer_collections( view_layer), DEG_OPCODE_VIEW_LAYER_DONE); state.parent = NULL; - build_layer_collections(&view_layer->layer_collections, &state); + build_layer_collections(owner_id, &view_layer->layer_collections, &state); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index c4542660c8b..531ea55cf5c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -248,9 +248,9 @@ void DepsgraphNodeBuilder::build_rig(Object *object) /* bones */ LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) { - /* node for bone eval */ - op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, - pchan->name, NULL, DEG_OPCODE_BONE_LOCAL); + /* Node for bone evaluation. */ + op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, NULL, + DEG_OPCODE_BONE_LOCAL); op_node->set_as_entry(); add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, @@ -269,6 +269,14 @@ void DepsgraphNodeBuilder::build_rig(Object *object) function_bind(BKE_pose_bone_done, _1, pchan), DEG_OPCODE_BONE_DONE); op_node->set_as_exit(); + /* Custom properties. */ + if (pchan->prop != NULL) { + add_operation_node(&object->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_PARAMETERS_EVAL, + pchan->name); + } /* Build constraints. */ if (pchan->constraints.first != NULL) { build_pose_constraints(object, pchan); @@ -311,17 +319,26 @@ void DepsgraphNodeBuilder::build_rig(Object *object) void DepsgraphNodeBuilder::build_proxy_rig(Object *object) { - ID *obdata = (ID *)object->data; + bArmature *arm = (bArmature *)object->data; OperationDepsNode *op_node; - Object *object_cow = get_cow_datablock(object); + Object *object_cow; + if (DEG_depsgraph_use_copy_on_write()) { + /* NOTE: We need to expand both object and armature, so this way we can + * safely create object level pose. + */ + object_cow = expand_cow_datablock(object); + } + else { + object_cow = object; + } /* Sanity check. */ BLI_assert(object->pose != NULL); /* Animation. */ - build_animdata(obdata); + build_animdata(&arm->id); /* speed optimization for animation lookups */ BKE_pose_channels_hash_make(object->pose); - if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(object->pose); + if (object_cow->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(object_cow->pose); } op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, @@ -330,7 +347,7 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) object_cow), DEG_OPCODE_POSE_INIT); op_node->set_as_entry(); - LINKLIST_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) { /* Local bone transform. */ op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, @@ -351,6 +368,15 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) NULL, DEG_OPCODE_BONE_DONE); op_node->set_as_exit(); + + /* Custom properties. */ + if (pchan->prop != NULL) { + add_operation_node(&object->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_PARAMETERS_EVAL, + pchan->name); + } } op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index c7966af76c6..49772c4f852 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc +/** \file blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc * \ingroup depsgraph * * Methods for constructing depsgraph's nodes @@ -65,13 +65,35 @@ extern "C" { namespace DEG { -void DepsgraphNodeBuilder::build_view_layer(Scene *scene, - ViewLayer *view_layer, - eDepsNode_LinkedState_Type linked_state) +void DepsgraphNodeBuilder::build_view_layer( + Scene *scene, + ViewLayer *view_layer, + eDepsNode_LinkedState_Type linked_state) { + /* Scene ID block. */ + add_id_node(&scene->id); + /* Time source. */ + add_time_source(); + /* Setup currently building context. */ + scene_ = scene; + /* Expand Scene Cow datablock to get proper pointers to bases. */ Scene *scene_cow; ViewLayer *view_layer_cow; if (DEG_depsgraph_use_copy_on_write()) { + /* NOTE: We need to create ID nodes for all objects coming from bases, + * otherwise remapping will not replace objects with their CoW versions + * for CoW bases. + */ + LINKLIST_FOREACH(Base *, base, &view_layer->object_bases) { + Object *object = base->object; + add_id_node(&object->id, false); + } + /* Create ID node for nested ID of nodetree as well, otherwise remapping + * will not work correct either. + */ + if (scene->nodetree != NULL) { + add_id_node(&scene->nodetree->id, false); + } /* Make sure we've got ID node, so we can get pointer to CoW datablock. */ scene_cow = expand_cow_datablock(scene); @@ -84,80 +106,64 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene, scene_cow = scene; view_layer_cow = view_layer; } - - /* scene ID block */ - add_id_node(&scene->id); - - /* timesource */ - add_time_source(); - - /* Setup currently building context. */ - scene_ = scene; - - /* scene objects */ + /* Scene objects. */ int select_color = 1; - LINKLIST_FOREACH(Base *, base, &view_layer_cow->object_bases) { + /* NOTE: Base is used for function bindings as-is, so need to pass CoW base, + * but object is expected to be an original one. Hence we go into some + * tricks here iterating over the view layer. + */ + for (Base *base_orig = (Base *)view_layer->object_bases.first, + *base_cow = (Base *)view_layer_cow->object_bases.first; + base_orig != NULL; + base_orig = base_orig->next, base_cow = base_cow->next) + { /* object itself */ - build_object(base, base->object, linked_state); - base->object->select_color = select_color++; + build_object(base_cow, base_orig->object, linked_state); + base_orig->object->select_color = select_color++; } if (scene->camera != NULL) { - build_object(NULL, scene->camera, linked_state); + build_object(NULL, scene->camera, DEG_ID_LINKED_INDIRECTLY); } - - /* rigidbody */ - if (scene->rigidbody_world) { + /* Rigidbody. */ + if (scene->rigidbody_world != NULL) { build_rigidbody(scene); } - - /* scene's animation and drivers */ - if (scene->adt) { + /* Scene's animation and drivers. */ + if (scene->adt != NULL) { build_animdata(&scene->id); } - - /* world */ - if (scene->world) { + /* World. */ + if (scene->world != NULL) { build_world(scene->world); } - - /* compo nodes */ - if (scene->nodetree) { + /* Compositor nodes */ + if (scene->nodetree != NULL) { build_compositor(scene); } - - /* sequencer */ - // XXX... - - /* grease pencil */ - if (scene->gpd) { + /* Grease pencil. */ + if (scene->gpd != NULL) { build_gpencil(scene->gpd); } - /* Cache file. */ LINKLIST_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) { build_cachefile(cachefile); } - /* Masks. */ LINKLIST_FOREACH (Mask *, mask, &bmain_->mask) { build_mask(mask); } - /* Movie clips. */ LINKLIST_FOREACH (MovieClip *, clip, &bmain_->movieclip) { build_movieclip(clip); } - /* Collections. */ - build_view_layer_collections(scene_cow, view_layer_cow); - + build_view_layer_collections(&scene->id, view_layer_cow); /* Parameters evaluation for scene relations mainly. */ add_operation_node(&scene->id, DEG_NODE_TYPE_PARAMETERS, NULL, DEG_OPCODE_PLACEHOLDER, "Scene Eval"); - /* Build all set scenes. */ if (scene->set != NULL) { ViewLayer *set_view_layer = BKE_view_layer_from_scene_get(scene->set); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index f2805cc9a7c..14dedef2601 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -120,10 +120,10 @@ struct BuilderWalkUserData { DepsgraphRelationBuilder *builder; }; -static void modifier_walk(void *user_data, - struct Object * /*object*/, - struct Object **obpoin, - int /*cb_flag*/) +void modifier_walk(void *user_data, + struct Object * /*object*/, + struct Object **obpoin, + int /*cb_flag*/) { BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; if (*obpoin) { @@ -203,20 +203,6 @@ static bool object_particles_depends_on_time(Object *object) /* **** General purpose functions **** */ -RNAPathKey::RNAPathKey(ID *id, const char *path) : - id(id) -{ - /* create ID pointer for root of path lookup */ - PointerRNA id_ptr; - RNA_id_pointer_create(id, &id_ptr); - /* try to resolve path... */ - int index; - if (!RNA_path_resolve_full(&id_ptr, path, &this->ptr, &this->prop, &index)) { - this->ptr = PointerRNA_NULL; - this->prop = NULL; - } -} - DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph) : bmain_(bmain), @@ -289,10 +275,11 @@ bool DepsgraphRelationBuilder::has_node(const OperationKey &key) const void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc, DepsNode *node_to, - const char *description) + const char *description, + bool check_unique) { if (timesrc && node_to) { - graph_->add_new_relation(timesrc, node_to, description); + graph_->add_new_relation(timesrc, node_to, description, check_unique); } else { DEG_DEBUG_PRINTF("add_time_relation(%p = %s, %p = %s, %s) Failed\n", @@ -305,10 +292,11 @@ void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc, void DepsgraphRelationBuilder::add_operation_relation( OperationDepsNode *node_from, OperationDepsNode *node_to, - const char *description) + const char *description, + bool check_unique) { if (node_from && node_to) { - graph_->add_new_relation(node_from, node_to, description); + graph_->add_new_relation(node_from, node_to, description, check_unique); } else { DEG_DEBUG_PRINTF("add_operation_relation(%p = %s, %p = %s, %s) Failed\n", @@ -318,13 +306,22 @@ void DepsgraphRelationBuilder::add_operation_relation( } } -void DepsgraphRelationBuilder::add_collision_relations(const OperationKey &key, Scene *scene, Object *object, Group *group, bool dupli, const char *name) +void DepsgraphRelationBuilder::add_collision_relations( + const OperationKey &key, + Scene *scene, + Object *object, + Group *group, + bool dupli, + const char *name) { unsigned int numcollobj; - Object **collobjs = get_collisionobjects_ext(scene, object, group, &numcollobj, eModifierType_Collision, dupli); - - for (unsigned int i = 0; i < numcollobj; i++) - { + Object **collobjs = get_collisionobjects_ext(scene, + object, + group, + &numcollobj, + eModifierType_Collision, + dupli); + for (unsigned int i = 0; i < numcollobj; i++) { Object *ob1 = collobjs[i]; ComponentKey trf_key(&ob1->id, DEG_NODE_TYPE_TRANSFORM); @@ -333,47 +330,62 @@ void DepsgraphRelationBuilder::add_collision_relations(const OperationKey &key, ComponentKey coll_key(&ob1->id, DEG_NODE_TYPE_GEOMETRY); add_relation(coll_key, key, name); } - - if (collobjs) + if (collobjs != NULL) { MEM_freeN(collobjs); + } } -void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key, Scene *scene, Object *object, ParticleSystem *psys, EffectorWeights *eff, bool add_absorption, const char *name) +void DepsgraphRelationBuilder::add_forcefield_relations( + const OperationKey &key, + Scene *scene, + Object *object, + ParticleSystem *psys, + EffectorWeights *eff, + bool add_absorption, + const char *name) { ListBase *effectors = pdInitEffectors(NULL, scene, object, psys, eff, false); - - if (effectors) { - for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) { + if (effectors != NULL) { + LINKLIST_FOREACH(EffectorCache *, eff, effectors) { if (eff->ob != object) { ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_TRANSFORM); add_relation(eff_key, key, name); } - - if (eff->psys) { + if (eff->psys != NULL) { if (eff->ob != object) { ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES); add_relation(eff_key, key, name); - /* TODO: remove this when/if EVAL_PARTICLES is sufficient for up to date particles */ + /* TODO: remove this when/if EVAL_PARTICLES is sufficient + * for up to date particles. + */ ComponentKey mod_key(&eff->ob->id, DEG_NODE_TYPE_GEOMETRY); add_relation(mod_key, key, name); } else if (eff->psys != psys) { - OperationKey eff_key(&eff->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PARTICLE_SYSTEM_EVAL, eff->psys->name); + OperationKey eff_key(&eff->ob->id, + DEG_NODE_TYPE_EVAL_PARTICLES, + DEG_OPCODE_PARTICLE_SYSTEM_EVAL, + eff->psys->name); add_relation(eff_key, key, name); } } - if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) { - ComponentKey trf_key(&eff->pd->f_source->id, DEG_NODE_TYPE_TRANSFORM); + ComponentKey trf_key(&eff->pd->f_source->id, + DEG_NODE_TYPE_TRANSFORM); add_relation(trf_key, key, "Smoke Force Domain"); - ComponentKey eff_key(&eff->pd->f_source->id, DEG_NODE_TYPE_GEOMETRY); + ComponentKey eff_key(&eff->pd->f_source->id, + DEG_NODE_TYPE_GEOMETRY); add_relation(eff_key, key, "Smoke Force Domain"); } - if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) { - add_collision_relations(key, scene, object, NULL, true, "Force Absorption"); + add_collision_relations(key, + scene, + object, + NULL, + true, + "Force Absorption"); } } } @@ -413,14 +425,20 @@ void DepsgraphRelationBuilder::build_group(Object *object, Group *group) OperationKey object_local_transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL); - LINKLIST_FOREACH (GroupObject *, go, &group->gobject) { - if (!group_done) { - build_object(NULL, go->ob); + + if (!group_done) { + LINKLIST_FOREACH(Base *, base, &group->view_layer->object_bases) { + build_object(NULL, base->object); } - ComponentKey dupli_transform_key(&go->ob->id, DEG_NODE_TYPE_TRANSFORM); + + build_view_layer_collections(&group->id, group->view_layer); + group_id->tag |= LIB_TAG_DOIT; + } + + LINKLIST_FOREACH (Base *, base, &group->view_layer->object_bases) { + ComponentKey dupli_transform_key(&base->object->id, DEG_NODE_TYPE_TRANSFORM); add_relation(dupli_transform_key, object_local_transform_key, "Dupligroup"); } - group_id->tag |= LIB_TAG_DOIT; } void DepsgraphRelationBuilder::build_object(Base *base, Object *object) @@ -457,7 +475,7 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) /* Local -> parent. */ add_relation(local_transform_key, parent_transform_key, - "[ObLocal -> ObParent]"); + "ObLocal -> ObParent"); } /* Modifiers. */ if (object->modifiers.first != NULL) { @@ -483,8 +501,8 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) &object->constraints, NULL); /* operation order */ - add_relation(base_op_key, constraint_key, "[ObBase-> Constraint Stack]"); - add_relation(constraint_key, final_transform_key, "[ObConstraints -> Done]"); + add_relation(base_op_key, constraint_key, "ObBase-> Constraint Stack"); + add_relation(constraint_key, final_transform_key, "ObConstraints -> Done"); // XXX add_relation(constraint_key, ob_ubereval_key, "Temp Ubereval"); add_relation(ob_ubereval_key, final_transform_key, "Temp Ubereval"); @@ -504,11 +522,6 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) } /* Animation data */ build_animdata(&object->id); - // XXX: This should be hooked up by the build_animdata code - if (needs_animdata_node(&object->id)) { - ComponentKey adt_key(&object->id, DEG_NODE_TYPE_ANIMATION); - add_relation(adt_key, local_transform_key, "Object Animation"); - } /* Object data. */ build_object_data(object); /* Particle systems. */ @@ -747,14 +760,14 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, * Constraint dependency chain. */ TimeSourceKey time_src_key; - add_relation(time_src_key, constraint_op_key, "[TimeSrc -> Animation]"); + add_relation(time_src_key, constraint_op_key, "TimeSrc -> Animation"); } else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) { /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint * dependency chain. */ TimeSourceKey time_src_key; - add_relation(time_src_key, constraint_op_key, "[TimeSrc -> Animation]"); + add_relation(time_src_key, constraint_op_key, "TimeSrc -> Animation"); bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data; if (data->cache_file) { ComponentKey cache_key(&data->cache_file->id, DEG_NODE_TYPE_CACHE); @@ -908,25 +921,85 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, void DepsgraphRelationBuilder::build_animdata(ID *id) { - AnimData *adt = BKE_animdata_from_id(id); + /* Animation curves and NLA. */ + build_animdata_curves(id); + /* Drivers. */ + build_animdata_drievrs(id); +} - if (adt == NULL) +void DepsgraphRelationBuilder::build_animdata_curves(ID *id) +{ + AnimData *adt = BKE_animdata_from_id(id); + if (adt == NULL) { return; - + } + if (adt->action == NULL && adt->nla_tracks.first == NULL) { + return; + } + /* Wire up dependency to time source. */ ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION); + TimeSourceKey time_src_key; + add_relation(time_src_key, adt_key, "TimeSrc -> Animation"); + /* Build relations from animation operation to properties it changes. */ + build_animdata_curves_targets(id); +} - /* animation */ - if (adt->action || adt->nla_tracks.first) { - /* wire up dependency to time source */ - TimeSourceKey time_src_key; - add_relation(time_src_key, adt_key, "[TimeSrc -> Animation]"); - - // XXX: Hook up specific update callbacks for special properties which may need it... - - // XXX: animdata "hierarchy" - top-level overrides need to go after lower-down +void DepsgraphRelationBuilder::build_animdata_curves_targets(ID *id) +{ + AnimData *adt = BKE_animdata_from_id(id); + if (adt == NULL || adt->action == NULL) { + return; + } + /* Get source operation. */ + ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION); + DepsNode *node_from = get_node(adt_key); + BLI_assert(node_from != NULL); + if (node_from == NULL) { + return; } + OperationDepsNode *operation_from = node_from->get_exit_operation(); + BLI_assert(operation_from != NULL); + /* Iterate over all curves and build relations. */ + PointerRNA id_ptr; + RNA_id_pointer_create(id, &id_ptr); + LINKLIST_FOREACH(FCurve *, fcu, &adt->action->curves) { + PointerRNA ptr; + PropertyRNA *prop; + int index; + if (!RNA_path_resolve_full(&id_ptr, fcu->rna_path, + &ptr, &prop, &index)) + { + continue; + } + DepsNode *node_to = graph_->find_node_from_pointer(&ptr, prop); + if (node_to == NULL) { + continue; + } + OperationDepsNode *operation_to = node_to->get_entry_operation(); + /* NOTE: Special case for bones, avoid relation from animation to + * each of the bones. Bone evaluation could only start from pose + * init anyway. + */ + if (operation_to->opcode == DEG_OPCODE_BONE_LOCAL) { + OperationKey pose_init_key(id, + DEG_NODE_TYPE_EVAL_POSE, + DEG_OPCODE_POSE_INIT); + add_relation(adt_key, pose_init_key, "Animation -> Prop", true); + continue; + } + graph_->add_new_relation(operation_from, operation_to, + "Animation -> Prop", + true); + } +} - /* drivers */ +void DepsgraphRelationBuilder::build_animdata_drievrs(ID *id) +{ + AnimData *adt = BKE_animdata_from_id(id); + if (adt == NULL) { + return; + } + ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION); LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) { OperationKey driver_key(id, DEG_NODE_TYPE_PARAMETERS, @@ -979,13 +1052,13 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) DEG_OPCODE_DRIVER, fcu->rna_path ? fcu->rna_path : "", fcu->array_index); - add_relation(prev_driver_key, driver_key, "[Driver Order]"); + add_relation(prev_driver_key, driver_key, "Driver Order"); } } /* prevent driver from occurring before own animation... */ if (adt->action || adt->nla_tracks.first) { - add_relation(adt_key, driver_key, "[AnimData Before Drivers]"); + add_relation(adt_key, driver_key, "AnimData Before Drivers"); } } } @@ -998,45 +1071,34 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) DEG_OPCODE_DRIVER, fcu->rna_path ? fcu->rna_path : "", fcu->array_index); - bPoseChannel *pchan = NULL; - const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; - const ID_Type id_type = GS(id->name); - - /* Create dependency between driver and data affected by it. */ - /* - direct property relationship... */ - //RNAPathKey affected_key(id, fcu->rna_path); - //add_relation(driver_key, affected_key, "[Driver -> Data] DepsRel"); - /* Driver -> data components (for interleaved evaluation * bones/constraints/modifiers). */ - // XXX: this probably should probably be moved out into a separate function. - if (strstr(rna_path, "pose.bones[") != NULL) { - /* interleaved drivers during bone eval */ - /* TODO: ideally, if this is for a constraint, it goes to said - * constraint. - */ - Object *object = (Object *)id; - char *bone_name = BLI_str_quoted_substrN(rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(object->pose, bone_name); - if (bone_name != NULL) { - MEM_freeN(bone_name); - bone_name = NULL; - } - if (pchan != NULL) { - OperationKey bone_key(id, - DEG_NODE_TYPE_BONE, - pchan->name, - DEG_OPCODE_BONE_LOCAL); - add_relation(driver_key, bone_key, "[Driver -> Bone]"); - } - else { - fprintf(stderr, - "Couldn't find bone name for driver path - '%s'\n", - rna_path); - } + build_driver_data(id, fcu); + /* Loop over variables to get the target relationships. */ + build_driver_variables(id, fcu); + /* It's quite tricky to detect if the driver actually depends on time or + * not, so for now we'll be quite conservative here about optimization and + * consider all python drivers to be depending on time. + */ + if ((driver->type == DRIVER_TYPE_PYTHON) && + python_driver_depends_on_time(driver)) + { + TimeSourceKey time_src_key; + add_relation(time_src_key, driver_key, "TimeSrc -> Driver"); } - else if (id_type == ID_AR && strstr(rna_path, "bones[")) { +} + +void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) +{ + OperationKey driver_key(id, + DEG_NODE_TYPE_PARAMETERS, + DEG_OPCODE_DRIVER, + fcu->rna_path ? fcu->rna_path : "", + fcu->array_index); + const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; + const RNAPathKey self_key(id, rna_path); + if (GS(id->name) == ID_AR && strstr(rna_path, "bones[")) { /* Drivers on armature-level bone settings (i.e. bbone stuff), * which will affect the evaluation of corresponding pose bones. */ @@ -1061,7 +1123,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) DEG_OPCODE_BONE_LOCAL); add_relation(driver_key, bone_key, - "[Arm Bone -> Driver -> Bone]"); + "Arm Bone -> Driver -> Bone"); } } } @@ -1075,71 +1137,23 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) rna_path); } } - else if (id_type == ID_OB && strstr(rna_path, "modifiers[")) { - OperationKey modifier_key(id, - DEG_NODE_TYPE_GEOMETRY, - DEG_OPCODE_GEOMETRY_UBEREVAL); - if (has_node(modifier_key)) { - add_relation(driver_key, modifier_key, "[Driver -> Modifier]"); - } - else { - printf("Unexisting driver RNA path: %s\n", rna_path); - } - } - else if (id_type == ID_KE && strstr(rna_path, "key_blocks[")) { - /* Shape key driver - hook into the base geometry operation. */ - // XXX: double check where this points - Key *shape_key = (Key *)id; - ComponentKey geometry_key(shape_key->from, DEG_NODE_TYPE_GEOMETRY); - add_relation(driver_key, geometry_key, "[Driver -> ShapeKey Geom]"); - } - else if (strstr(rna_path, "key_blocks[")) { - ComponentKey geometry_key(id, DEG_NODE_TYPE_GEOMETRY); - add_relation(driver_key, geometry_key, "[Driver -> ShapeKey Geom]"); - } else { - switch (id_type) { - case ID_OB: - { - /* Assume that driver affects a transform. */ - OperationKey local_transform_key(id, - DEG_NODE_TYPE_TRANSFORM, - DEG_OPCODE_TRANSFORM_LOCAL); - add_relation(driver_key, - local_transform_key, - "[Driver -> Transform]"); - break; - } - case ID_KE: - { - ComponentKey geometry_key(id, DEG_NODE_TYPE_GEOMETRY); - add_relation(driver_key, - geometry_key, - "[Driver -> Shapekey Geometry]"); - break; - } - case ID_NT: - { - ComponentKey ntree_key(id, DEG_NODE_TYPE_SHADING); - add_relation(driver_key, - ntree_key, - "[Driver -> NTree Shading Update]"); - break; - } - default: - break; - } + RNAPathKey target_key(id, rna_path); + add_relation(driver_key, target_key, "Driver -> Target"); } - /* Ensure that affected prop's update callbacks will be triggered once - * done. - */ - /* TODO: Implement this once the functionality to add these links exists - * RNA. - */ - /* XXX: the data itself could also set this, if it were to be truly - * initialised later? - */ - /* Loop over variables to get the target relationships. */ +} + +void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) +{ + ChannelDriver *driver = fcu->driver; + OperationKey driver_key(id, + DEG_NODE_TYPE_PARAMETERS, + DEG_OPCODE_DRIVER, + fcu->rna_path ? fcu->rna_path : "", + fcu->array_index); + const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; + const RNAPathKey self_key(id, rna_path); + LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) { /* Only used targets. */ DRIVER_TARGETS_USED_LOOPER(dvar) @@ -1148,31 +1162,25 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) continue; } /* Special handling for directly-named bones. */ - if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) { + if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && + (((Object *)dtar->id)->type == OB_ARMATURE) && + (dtar->pchan_name[0])) + { Object *object = (Object *)dtar->id; bPoseChannel *target_pchan = - BKE_pose_channel_find_name(object->pose, dtar->pchan_name); - if (target_pchan != NULL) { - /* Get node associated with bone. */ - // XXX: watch the space! - /* Some cases can't use final bone transform, for example: - * - Driving the bone with itself (addressed here) - * - Relations inside an IK chain (TODO?) - */ - if (dtar->id == id && - pchan != NULL && - STREQ(pchan->name, target_pchan->name)) - { - continue; - } - OperationKey target_key(dtar->id, - DEG_NODE_TYPE_BONE, - target_pchan->name, - DEG_OPCODE_BONE_DONE); - add_relation(target_key, - driver_key, - "[Bone Target -> Driver]"); + BKE_pose_channel_find_name(object->pose, + dtar->pchan_name); + if (target_pchan == NULL) { + continue; + } + OperationKey variable_key(dtar->id, + DEG_NODE_TYPE_BONE, + target_pchan->name, + DEG_OPCODE_BONE_DONE); + if (is_same_bone_dependency(variable_key, self_key)) { + continue; } + add_relation(variable_key, driver_key, "Bone Target -> Driver"); } else if (dtar->flag & DTAR_FLAG_STRUCT_REF) { /* Get node associated with the object's transforms. */ @@ -1186,34 +1194,17 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) OperationKey target_key(dtar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL); - add_relation(target_key, driver_key, "[Target -> Driver]"); + add_relation(target_key, driver_key, "Target -> Driver"); } - else if (dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) { - /* Workaround for ensuring that local bone transforms don't end - * up having to wait for pose eval to finish (to prevent cycles). - */ - Object *object = (Object *)dtar->id; - char *bone_name = BLI_str_quoted_substrN(dtar->rna_path, - "pose.bones["); - bPoseChannel *target_pchan = - BKE_pose_channel_find_name(object->pose, bone_name); - if (bone_name != NULL) { - MEM_freeN(bone_name); - bone_name = NULL; + else if (dtar->rna_path) { + RNAPathKey variable_key(dtar->id, dtar->rna_path); + if (RNA_pointer_is_null(&variable_key.ptr)) { + continue; } - if (target_pchan != NULL) { - if (dtar->id == id && - pchan != NULL && - STREQ(pchan->name, target_pchan->name)) - { - continue; - } - OperationKey bone_key(dtar->id, - DEG_NODE_TYPE_BONE, - target_pchan->name, - DEG_OPCODE_BONE_LOCAL); - add_relation(bone_key, driver_key, "[RNA Bone -> Driver]"); + if (is_same_bone_dependency(variable_key, self_key)) { + continue; } + add_relation(variable_key, driver_key, "RNA Bone -> Driver"); } else { if (dtar->id == id) { @@ -1226,21 +1217,11 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) /* Resolve path to get node. */ RNAPathKey target_key(dtar->id, dtar->rna_path ? dtar->rna_path : ""); - add_relation(target_key, driver_key, "[RNA Target -> Driver]"); + add_relation(target_key, driver_key, "RNA Target -> Driver"); } } DRIVER_TARGETS_LOOPER_END } - /* It's quite tricky to detect if the driver actually depends on time or - * not, so for now we'll be quite conservative here about optimization and - * consider all python drivers to be depending on time. - */ - if ((driver->type == DRIVER_TYPE_PYTHON) && - python_driver_depends_on_time(driver)) - { - TimeSourceKey time_src_key; - add_relation(time_src_key, driver_key, "[TimeSrc -> Driver]"); - } } void DepsgraphRelationBuilder::build_world(World *world) @@ -1285,8 +1266,8 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) /* objects - simulation participants */ if (rbw->group) { - LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) { - Object *object = go->ob; + LINKLIST_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) { + Object *object = base->object; if (object == NULL || object->type != OB_MESH) { continue; } @@ -1339,8 +1320,8 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) /* constraints */ if (rbw->constraints) { - LINKLIST_FOREACH (GroupObject *, go, &rbw->constraints->gobject) { - Object *object = go->ob; + LINKLIST_FOREACH (Base *, base, &rbw->constraints->view_layer->object_bases) { + Object *object = base->object; if (object == NULL || !object->rigidbody_constraint) { continue; } @@ -1598,7 +1579,6 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object) if (object->modifiers.first != NULL) { LINKLIST_FOREACH (ModifierData *, md, &object->modifiers) { const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type); - if (mti->updateDepsgraph) { DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); mti->updateDepsgraph( @@ -1608,23 +1588,10 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object) object, reinterpret_cast< ::DepsNodeHandle* >(&handle)); } - if (BKE_object_modifier_use_time(object, md)) { TimeSourceKey time_src_key; add_relation(time_src_key, obdata_ubereval_key, "Time Source"); - - /* Hacky fix for T45633 (Animated modifiers aren't updated) - * - * This check works because BKE_object_modifier_use_time() tests - * for either the modifier needing time, or that it is animated. - */ - /* XXX: Remove this hack when these links are added as part of build_animdata() instead */ - if (modifier_dependsOnTime(md) == false && needs_animdata_node(&object->id)) { - ComponentKey animation_key(&object->id, DEG_NODE_TYPE_ANIMATION); - add_relation(animation_key, obdata_ubereval_key, "Modifier Animation"); - } } - if (md->type == eModifierType_Cloth) { build_cloth(object, md); } @@ -1757,16 +1724,6 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object) if (key) { build_shapekeys(obdata, key); } - - if (needs_animdata_node(obdata)) { - ComponentKey animation_key(obdata, DEG_NODE_TYPE_ANIMATION); - ComponentKey parameters_key(obdata, DEG_NODE_TYPE_PARAMETERS); - add_relation(animation_key, parameters_key, "Geom Parameters"); - /* Evaluation usually depends on animation. - * TODO(sergey): Need to re-hook it after granular update is implemented.. - */ - add_relation(animation_key, obdata_geom_eval_key, "Animation"); - } } /* Cameras */ @@ -1786,11 +1743,6 @@ void DepsgraphRelationBuilder::build_camera(Object *object) add_relation(camera_parameters_key, object_parameters_key, "Camera -> Object"); - if (needs_animdata_node(camera_id)) { - ComponentKey animation_key(camera_id, DEG_NODE_TYPE_ANIMATION); - add_relation(animation_key, camera_parameters_key, "Camera Parameters"); - } - /* DOF */ if (cam->dof_ob != NULL) { ComponentKey dof_ob_key(&cam->dof_ob->id, DEG_NODE_TYPE_TRANSFORM); @@ -1814,18 +1766,12 @@ void DepsgraphRelationBuilder::build_lamp(Object *object) add_relation(lamp_parameters_key, object_parameters_key, "Lamp -> Object"); - if (needs_animdata_node(lamp_id)) { - ComponentKey animation_key(lamp_id, DEG_NODE_TYPE_ANIMATION); - add_relation(animation_key, lamp_parameters_key, "Lamp Parameters"); - } - /* lamp's nodetree */ - if (la->nodetree) { + if (la->nodetree != NULL) { build_nodetree(la->nodetree); ComponentKey nodetree_key(&la->nodetree->id, DEG_NODE_TYPE_SHADING); add_relation(nodetree_key, lamp_parameters_key, "NTree->Lamp Parameters"); } - /* textures */ build_texture_stack(la->mtex); @@ -1875,6 +1821,9 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) * pipeline. No need to build dependencies for them here. */ } + else if (id_type == ID_TXT) { + /* Ignore script nodes. */ + } else if (bnode->type == NODE_GROUP) { bNodeTree *group_ntree = (bNodeTree *)id; if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) { @@ -1890,11 +1839,6 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) } } - if (needs_animdata_node(ntree_id)) { - ComponentKey animation_key(ntree_id, DEG_NODE_TYPE_ANIMATION); - add_relation(animation_key, shading_key, "NTree Parameters"); - } - OperationKey shading_update_key(ntree_id, DEG_NODE_TYPE_SHADING, DEG_OPCODE_MATERIAL_UPDATE); @@ -1975,15 +1919,6 @@ void DepsgraphRelationBuilder::build_gpencil(bGPdata *gpd) // TODO: parent object (when that feature is implemented) } -bool DepsgraphRelationBuilder::needs_animdata_node(ID *id) -{ - AnimData *adt = BKE_animdata_from_id(id); - if (adt != NULL) { - return (adt->action != NULL) || (adt->nla_tracks.first != NULL); - } - return false; -} - void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) { /* Animation. */ build_animdata(&cache_file->id); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 8fe98ae9901..9f661b8e825 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -31,6 +31,7 @@ #pragma once #include <cstdio> +#include <cstring> #include "intern/depsgraph_types.h" @@ -43,6 +44,7 @@ #include "BLI_string.h" #include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" #include "intern/nodes/deg_node_operation.h" struct Base; @@ -175,17 +177,20 @@ struct DepsgraphRelationBuilder template <typename KeyFrom, typename KeyTo> void add_relation(const KeyFrom& key_from, const KeyTo& key_to, - const char *description); + const char *description, + bool check_unique = false); template <typename KeyTo> void add_relation(const TimeSourceKey& key_from, const KeyTo& key_to, - const char *description); + const char *description, + bool check_unique = false); template <typename KeyType> void add_node_handle_relation(const KeyType& key_from, const DepsNodeHandle *handle, - const char *description); + const char *description, + bool check_unique = false); void build_view_layer(Scene *scene, ViewLayer *view_layer); void build_group(Object *object, Group *group); @@ -199,7 +204,12 @@ struct DepsgraphRelationBuilder ListBase *constraints, RootPChanMap *root_map); void build_animdata(ID *id); + void build_animdata_curves(ID *id); + void build_animdata_curves_targets(ID *id); + void build_animdata_drievrs(ID *id); void build_driver(ID *id, FCurve *fcurve); + void build_driver_data(ID *id, FCurve *fcurve); + void build_driver_variables(ID *id, FCurve *fcurve); void build_world(World *world); void build_rigidbody(Scene *scene); void build_particles(Object *object); @@ -249,11 +259,13 @@ struct DepsgraphRelationBuilder OperationKey done_key; OperationKey prev_key; }; - void build_layer_collection(LayerCollection *layer_collection, + void build_layer_collection(ID *owner_id, + LayerCollection *layer_collection, LayerCollectionState *state); - void build_layer_collections(ListBase *layer_collections, + void build_layer_collections(ID *owner_id, + ListBase *layer_collections, LayerCollectionState *state); - void build_view_layer_collections(ViewLayer *view_layer); + void build_view_layer_collections(struct ID *owner_id, ViewLayer *view_layer); void build_copy_on_write_relations(); void build_copy_on_write_relations(IDDepsNode *id_node); @@ -274,16 +286,19 @@ protected: void add_time_relation(TimeSourceDepsNode *timesrc, DepsNode *node_to, - const char *description); + const char *description, + bool check_unique = false); void add_operation_relation(OperationDepsNode *node_from, OperationDepsNode *node_to, - const char *description); + const char *description, + bool check_unique = false); template <typename KeyType> DepsNodeHandle create_node_handle(const KeyType& key, const char *default_name = ""); - bool needs_animdata_node(ID *id); + template <typename KeyFrom, typename KeyTo> + bool is_same_bone_dependency(const KeyFrom& key_from, const KeyTo& key_to); private: /* State which never changes, same for the whole builder time. */ @@ -296,10 +311,12 @@ private: struct DepsNodeHandle { - DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const char *default_name = "") : - builder(builder), - node(node), - default_name(default_name) + DepsNodeHandle(DepsgraphRelationBuilder *builder, + OperationDepsNode *node, + const char *default_name = "") + : builder(builder), + node(node), + default_name(default_name) { BLI_assert(node != NULL); } @@ -309,92 +326,7 @@ struct DepsNodeHandle const char *default_name; }; -/* Utilities for Builders ----------------------------------------------------- */ - -template <typename KeyType> -OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key) -{ - DepsNode *node = get_node(key); - return node != NULL ? node->get_exit_operation() : NULL; -} - -template <typename KeyFrom, typename KeyTo> -void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from, - const KeyTo &key_to, - const char *description) -{ - DepsNode *node_from = get_node(key_from); - DepsNode *node_to = get_node(key_to); - OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL; - OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL; - if (op_from && op_to) { - add_operation_relation(op_from, op_to, description); - } - else { - if (!op_from) { - /* XXX TODO handle as error or report if needed */ - fprintf(stderr, "add_relation(%s) - Could not find op_from (%s)\n", - description, key_from.identifier().c_str()); - } - else { - fprintf(stderr, "add_relation(%s) - Failed, but op_from (%s) was ok\n", - description, key_from.identifier().c_str()); - } - if (!op_to) { - /* XXX TODO handle as error or report if needed */ - fprintf(stderr, "add_relation(%s) - Could not find op_to (%s)\n", - description, key_to.identifier().c_str()); - } - else { - fprintf(stderr, "add_relation(%s) - Failed, but op_to (%s) was ok\n", - description, key_to.identifier().c_str()); - } - } -} - -template <typename KeyTo> -void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from, - const KeyTo &key_to, - const char *description) -{ - TimeSourceDepsNode *time_from = get_node(key_from); - DepsNode *node_to = get_node(key_to); - OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL; - if (time_from != NULL && op_to != NULL) { - add_time_relation(time_from, op_to, description); - } -} - -template <typename KeyType> -void DepsgraphRelationBuilder::add_node_handle_relation( - const KeyType &key_from, - const DepsNodeHandle *handle, - const char *description) -{ - DepsNode *node_from = get_node(key_from); - OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL; - OperationDepsNode *op_to = handle->node->get_entry_operation(); - if (op_from != NULL && op_to != NULL) { - add_operation_relation(op_from, op_to, description); - } - else { - if (!op_from) { - fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_from (%s)\n", - description, key_from.identifier().c_str()); - } - if (!op_to) { - fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_to (%s)\n", - description, key_from.identifier().c_str()); - } - } -} +} // namespace DEG -template <typename KeyType> -DepsNodeHandle DepsgraphRelationBuilder::create_node_handle( - const KeyType &key, - const char *default_name) -{ - return DepsNodeHandle(this, get_node(key), default_name); -} -} // namespace DEG +#include "intern/builder/deg_builder_relations_impl.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h new file mode 100644 index 00000000000..ba55a83b767 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h @@ -0,0 +1,155 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Lukas Toenne + * Contributor(s): Sergey SHarybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_relations_impl.h + * \ingroup depsgraph + */ + +#pragma once + +namespace DEG { + +template <typename KeyType> +OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key) +{ + DepsNode *node = get_node(key); + return node != NULL ? node->get_exit_operation() : NULL; +} + +template <typename KeyFrom, typename KeyTo> +void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from, + const KeyTo &key_to, + const char *description, + bool check_unique) +{ + DepsNode *node_from = get_node(key_from); + DepsNode *node_to = get_node(key_to); + OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL; + OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL; + if (op_from && op_to) { + add_operation_relation(op_from, op_to, description, check_unique); + } + else { + if (!op_from) { + /* XXX TODO handle as error or report if needed */ + fprintf(stderr, "add_relation(%s) - Could not find op_from (%s)\n", + description, key_from.identifier().c_str()); + } + else { + fprintf(stderr, "add_relation(%s) - Failed, but op_from (%s) was ok\n", + description, key_from.identifier().c_str()); + } + if (!op_to) { + /* XXX TODO handle as error or report if needed */ + fprintf(stderr, "add_relation(%s) - Could not find op_to (%s)\n", + description, key_to.identifier().c_str()); + } + else { + fprintf(stderr, "add_relation(%s) - Failed, but op_to (%s) was ok\n", + description, key_to.identifier().c_str()); + } + } +} + +template <typename KeyTo> +void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from, + const KeyTo &key_to, + const char *description, + bool check_unique) +{ + TimeSourceDepsNode *time_from = get_node(key_from); + DepsNode *node_to = get_node(key_to); + OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL; + if (time_from != NULL && op_to != NULL) { + add_time_relation(time_from, op_to, description, check_unique); + } +} + +template <typename KeyType> +void DepsgraphRelationBuilder::add_node_handle_relation( + const KeyType &key_from, + const DepsNodeHandle *handle, + const char *description, + bool check_unique) +{ + DepsNode *node_from = get_node(key_from); + OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL; + OperationDepsNode *op_to = handle->node->get_entry_operation(); + if (op_from != NULL && op_to != NULL) { + add_operation_relation(op_from, op_to, description, check_unique); + } + else { + if (!op_from) { + fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_from (%s)\n", + description, key_from.identifier().c_str()); + } + if (!op_to) { + fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_to (%s)\n", + description, key_from.identifier().c_str()); + } + } +} + +template <typename KeyType> +DepsNodeHandle DepsgraphRelationBuilder::create_node_handle( + const KeyType &key, + const char *default_name) +{ + return DepsNodeHandle(this, get_node(key), default_name); +} + +/* Rig compatibility: we check if bone is using local transform as a variable + * for driver on itself and ignore those relations to avoid "false-positive" + * dependency cycles. + */ +template <typename KeyFrom, typename KeyTo> +bool DepsgraphRelationBuilder::is_same_bone_dependency(const KeyFrom& key_from, + const KeyTo& key_to) +{ + /* Get operations for requested keys. */ + DepsNode *node_from = get_node(key_from); + DepsNode *node_to = get_node(key_to); + if (node_from == NULL || node_to == NULL) { + return false; + } + OperationDepsNode *op_from = node_from->get_exit_operation(); + OperationDepsNode *op_to = node_to->get_entry_operation(); + if (op_from == NULL || op_to == NULL) { + return false; + } + /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */ + if (!(op_from->opcode == DEG_OPCODE_BONE_DONE && + op_to->opcode == DEG_OPCODE_BONE_LOCAL)) { + return false; + } + /* ... BUT, we also need to check if it's same bone. */ + if (!STREQ(op_from->owner->name, op_to->owner->name)) { + return false; + } + return true; +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc index 9d6ab3358a7..4b8e4faae3f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc @@ -193,6 +193,20 @@ RNAPathKey::RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop) { } +RNAPathKey::RNAPathKey(ID *id, const char *path) + : id(id) +{ + /* create ID pointer for root of path lookup */ + PointerRNA id_ptr; + RNA_id_pointer_create(id, &id_ptr); + /* try to resolve path... */ + int index; + if (!RNA_path_resolve_full(&id_ptr, path, &this->ptr, &this->prop, &index)) { + this->ptr = PointerRNA_NULL; + this->prop = NULL; + } +} + string RNAPathKey::identifier() const { const char *id_name = (id) ? id->name : "<No ID>"; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc index a7c70bfc098..452bd7b19e7 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/builder/deg_builder_relations_layer.cc +/** \file blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc * \ingroup depsgraph * * Methods for constructing depsgraph @@ -69,10 +69,11 @@ extern "C" { namespace DEG { void DepsgraphRelationBuilder::build_layer_collection( + ID *owner_id, LayerCollection *layer_collection, LayerCollectionState *state) { - OperationKey layer_key(&scene_->id, + OperationKey layer_key(owner_id, DEG_NODE_TYPE_LAYER_COLLECTIONS, DEG_OPCODE_VIEW_LAYER_EVAL, layer_collection->scene_collection->name, @@ -83,29 +84,31 @@ void DepsgraphRelationBuilder::build_layer_collection( state->prev_key = layer_key; /* Recurs into nested layer collections. */ - build_layer_collections(&layer_collection->layer_collections, state); + build_layer_collections(owner_id, &layer_collection->layer_collections, state); } void DepsgraphRelationBuilder::build_layer_collections( + ID *owner_id, ListBase *layer_collections, LayerCollectionState *state) { LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) { /* Recurs into the layer. */ - build_layer_collection(layer_collection, state); + build_layer_collection(owner_id, layer_collection, state); } } void DepsgraphRelationBuilder::build_view_layer_collections( + ID *owner_id, ViewLayer *view_layer) { LayerCollectionState state; state.index = 0; - OperationKey init_key(&scene_->id, + OperationKey init_key(owner_id, DEG_NODE_TYPE_LAYER_COLLECTIONS, DEG_OPCODE_VIEW_LAYER_INIT); - OperationKey done_key(&scene_->id, + OperationKey done_key(owner_id, DEG_NODE_TYPE_LAYER_COLLECTIONS, DEG_OPCODE_VIEW_LAYER_DONE); @@ -113,7 +116,7 @@ void DepsgraphRelationBuilder::build_view_layer_collections( state.done_key = done_key; state.prev_key = init_key; - build_layer_collections(&view_layer->layer_collections, &state); + build_layer_collections(owner_id, &view_layer->layer_collections, &state); add_relation(state.prev_key, done_key, "Layer collection order"); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index ce63d6455cc..2aff1ca33c7 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -258,7 +258,7 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object, // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry... ComponentKey target_key(&data->tar->id, DEG_NODE_TYPE_GEOMETRY); ComponentKey pose_key(&object->id, DEG_NODE_TYPE_EVAL_POSE); - add_relation(target_key, pose_key, "[Curve.Path -> Spline IK] DepsRel"); + add_relation(target_key, pose_key, "Curve.Path -> Spline IK"); } pchan->flag |= POSE_DONE; @@ -324,11 +324,6 @@ void DepsgraphRelationBuilder::build_rig(Object *object) "Armature Eval"); add_relation(armature_key, init_key, "Data dependency"); - if (needs_animdata_node(&object->id)) { - ComponentKey animation_key(&object->id, DEG_NODE_TYPE_ANIMATION); - add_relation(animation_key, init_key, "Rig Animation"); - } - /* IK Solvers... * - These require separate processing steps are pose-level * to be executed between chains of bones (i.e. once the @@ -410,7 +405,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object) } OperationKey parent_key(&object->id, DEG_NODE_TYPE_BONE, pchan->parent->name, parent_key_opcode); - add_relation(parent_key, bone_pose_key, "[Parent Bone -> Child Bone]"); + add_relation(parent_key, bone_pose_key, "Parent Bone -> Child Bone"); } /* Buil constraints. */ if (pchan->constraints.first != NULL) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index d23fdaacf08..29cff0cb28d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/builder/deg_builder_relations_scene.cc +/** \file blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc * \ingroup depsgraph * * Methods for constructing depsgraph @@ -72,53 +72,47 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la { /* Setup currently building context. */ scene_ = scene; - - /* scene objects */ + /* Scene objects. */ + /* NOTE: Nodes builder requires us to pass CoW base because it's being + * passed to the evaluation functions. During relations builder we only + * do NULL-pointer check of the base, so it's fine to pass original one. + */ LINKLIST_FOREACH(Base *, base, &view_layer->object_bases) { build_object(base, base->object); } if (scene->camera != NULL) { build_object(NULL, scene->camera); } - - /* rigidbody */ - if (scene->rigidbody_world) { + /* Rigidbody. */ + if (scene->rigidbody_world != NULL) { build_rigidbody(scene); } - - /* scene's animation and drivers */ - if (scene->adt) { + /* Scene's animation and drivers. */ + if (scene->adt != NULL) { build_animdata(&scene->id); } - - /* world */ - if (scene->world) { + /* World. */ + if (scene->world != NULL) { build_world(scene->world); } - - /* compo nodes */ - if (scene->nodetree) { + /* Compositor nodes. */ + if (scene->nodetree != NULL) { build_compositor(scene); } - - /* grease pencil */ - if (scene->gpd) { + /* Grease pencil. */ + if (scene->gpd != NULL) { build_gpencil(scene->gpd); } - /* Masks. */ LINKLIST_FOREACH (Mask *, mask, &bmain_->mask) { build_mask(mask); } - /* Movie clips. */ LINKLIST_FOREACH (MovieClip *, clip, &bmain_->movieclip) { build_movieclip(clip); } - /* Collections. */ - build_view_layer_collections(view_layer); - + build_view_layer_collections(&scene_->id, view_layer); /* TODO(sergey): Do this flush on CoW object? */ foreach (OperationDepsNode *node, graph_->operations) { IDDepsNode *id_node = node->owner->owner; @@ -128,7 +122,6 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la object->customdata_mask |= node->customdata_mask; } } - /* Build all set scenes. */ if (scene->set != NULL) { ViewLayer *set_view_layer = BKE_view_layer_from_scene_get(scene->set); diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index d4907eeff46..4fea8b49706 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -78,7 +78,6 @@ namespace DEG { static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL; static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL; -static DEG_EditorUpdateScenePreCb deg_editor_update_scene_pre_cb = NULL; Depsgraph::Depsgraph() : time_source(NULL), @@ -104,72 +103,60 @@ Depsgraph::~Depsgraph() /* Query Conditions from RNA ----------------------- */ -static bool pointer_to_id_node_criteria(const PointerRNA *ptr, - const PropertyRNA *prop, - ID **id) +static bool pointer_to_component_node_criteria( + const PointerRNA *ptr, + const PropertyRNA *prop, + ID **id, + eDepsNode_Type *type, + const char **subdata, + eDepsOperation_Code *operation_code, + const char **operation_name, + int *operation_name_tag) { - if (!ptr->type) + if (ptr->type == NULL) { return false; - - if (!prop) { - if (RNA_struct_is_ID(ptr->type)) { - *id = (ID *)ptr->data; - return true; - } } - - return false; -} - -static bool pointer_to_component_node_criteria(const PointerRNA *ptr, - const PropertyRNA *prop, - ID **id, - eDepsNode_Type *type, - const char **subdata) -{ - if (!ptr->type) - return false; - /* Set default values for returns. */ - *id = (ID *)ptr->id.data; /* For obvious reasons... */ - *subdata = ""; /* Default to no subdata (e.g. bone) name - * lookup in most cases. */ - - /* Handling of commonly known scenarios... */ + *id = (ID *)ptr->id.data; + *subdata = ""; + *operation_code = DEG_OPCODE_OPERATION; + *operation_name = ""; + *operation_name_tag = -1; + /* Handling of commonly known scenarios. */ if (ptr->type == &RNA_PoseBone) { bPoseChannel *pchan = (bPoseChannel *)ptr->data; - - /* Bone - generally, we just want the bone component... */ - *type = DEG_NODE_TYPE_BONE; - *subdata = pchan->name; - + if (prop != NULL && RNA_property_is_idprop(prop)) { + *type = DEG_NODE_TYPE_PARAMETERS; + *subdata = ""; + *operation_code = DEG_OPCODE_PARAMETERS_EVAL; + *operation_name = pchan->name;; + } + else { + /* Bone - generally, we just want the bone component. */ + *type = DEG_NODE_TYPE_BONE; + *subdata = pchan->name; + } return true; } else if (ptr->type == &RNA_Bone) { Bone *bone = (Bone *)ptr->data; - /* armature-level bone, but it ends up going to bone component anyway */ - // TODO: the ID in thise case will end up being bArmature, not Object as needed! + // NOTE: the ID in thise case will end up being bArmature. *type = DEG_NODE_TYPE_BONE; *subdata = bone->name; - //*id = ... - return true; } else if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) { Object *object = (Object *)ptr->id.data; bConstraint *con = (bConstraint *)ptr->data; - - /* object or bone? */ + /* Check whether is object or bone constraint. */ if (BLI_findindex(&object->constraints, con) != -1) { - /* object transform */ - // XXX: for now, we can't address the specific constraint or the constraint stack... + /* Constraint is defining object transform. */ *type = DEG_NODE_TYPE_TRANSFORM; return true; } - else if (object->pose) { - bPoseChannel *pchan; - for (pchan = (bPoseChannel *)object->pose->chanbase.first; pchan; pchan = pchan->next) { + else if (object->pose != NULL) { + LINKLIST_FOREACH(bPoseChannel *, pchan, &object->pose->chanbase) { if (BLI_findindex(&pchan->constraints, con) != -1) { /* bone transforms */ *type = DEG_NODE_TYPE_BONE; @@ -180,23 +167,12 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr, } } else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) { - //ModifierData *md = (ModifierData *)ptr->data; - - /* Modifier */ - /* NOTE: subdata is not the same as "operation name", - * so although we have unique ops for modifiers, - * we can't lump them together - */ - *type = DEG_NODE_TYPE_BONE; - //*subdata = md->name; - + *type = DEG_NODE_TYPE_GEOMETRY; return true; } else if (ptr->type == &RNA_Object) { - //Object *object = (Object *)ptr->data; - /* Transforms props? */ - if (prop) { + if (prop != NULL) { const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); /* TODO(sergey): How to optimize this? */ if (strstr(prop_identifier, "location") || @@ -218,11 +194,16 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr, } else if (ptr->type == &RNA_ShapeKey) { Key *key = (Key *)ptr->id.data; - - /* ShapeKeys are currently handled as geometry on the geometry that owns it */ - *id = key->from; // XXX - *type = DEG_NODE_TYPE_PARAMETERS; - + /* ShapeKeys are currently handled as geometry on the geometry that + * owns it. + */ + *id = key->from; + *type = DEG_NODE_TYPE_GEOMETRY; + return true; + } + else if (ptr->type == &RNA_Key) { + *id = (ID *)ptr->id.data; + *type = DEG_NODE_TYPE_GEOMETRY; return true; } else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { @@ -232,13 +213,14 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr, *subdata = seq->name; // xxx? return true; } - - if (prop) { - /* All unknown data effectively falls under "parameter evaluation" */ + if (prop != NULL) { + /* All unknown data effectively falls under "parameter evaluation". */ *type = DEG_NODE_TYPE_PARAMETERS; + *operation_code = DEG_OPCODE_PARAMETERS_EVAL; + *operation_name = ""; + *operation_name_tag = -1; return true; } - return false; } @@ -247,20 +229,32 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr, const PropertyRNA *prop) const { ID *id; - eDepsNode_Type type; - const char *name; - - /* Get querying conditions. */ - if (pointer_to_id_node_criteria(ptr, prop, &id)) { - return find_id_node(id); - } - else if (pointer_to_component_node_criteria(ptr, prop, &id, &type, &name)) { + eDepsNode_Type node_type; + const char *component_name, *operation_name; + eDepsOperation_Code operation_code; + int operation_name_tag; + + if (pointer_to_component_node_criteria( + ptr, prop, + &id, &node_type, &component_name, + &operation_code, &operation_name, &operation_name_tag)) + { IDDepsNode *id_node = find_id_node(id); - if (id_node != NULL) { - return id_node->find_component(type, name); + if (id_node == NULL) { + return NULL; + } + ComponentDepsNode *comp_node = + id_node->find_component(node_type, component_name); + if (comp_node == NULL) { + return NULL; } + if (operation_code == DEG_OPCODE_OPERATION) { + return comp_node; + } + return comp_node->find_operation(operation_code, + operation_name, + operation_name_tag); } - return NULL; } @@ -342,10 +336,18 @@ void Depsgraph::clear_id_nodes() /* Add new relationship between two nodes. */ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from, OperationDepsNode *to, - const char *description) + const char *description, + bool check_unique) { + DepsRelation *rel = NULL; + if (check_unique) { + rel = check_nodes_connected(from, to, description); + } + if (rel != NULL) { + return rel; + } /* Create new relation, and add it to the graph. */ - DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description); + rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description); /* TODO(sergey): Find a better place for this. */ #ifdef WITH_OPENSUBDIV ComponentDepsNode *comp_node = from->owner; @@ -365,13 +367,38 @@ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from, /* Add new relation between two nodes */ DepsRelation *Depsgraph::add_new_relation(DepsNode *from, DepsNode *to, - const char *description) + const char *description, + bool check_unique) { + DepsRelation *rel = NULL; + if (check_unique) { + rel = check_nodes_connected(from, to, description); + } + if (rel != NULL) { + return rel; + } /* Create new relation, and add it to the graph. */ - DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description); + rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description); return rel; } +DepsRelation *Depsgraph::check_nodes_connected(const DepsNode *from, + const DepsNode *to, + const char *description) +{ + foreach (DepsRelation *rel, from->outlinks) { + BLI_assert(rel->from == from); + if (rel->to != to) { + continue; + } + if (description != NULL && !STREQ(rel->name, description)) { + continue; + } + return rel; + } + return NULL; +} + /* ************************ */ /* Relationships Management */ @@ -383,24 +410,6 @@ DepsRelation::DepsRelation(DepsNode *from, name(description), flag(0) { -#ifndef NDEBUG -/* - for (OperationDepsNode::Relations::const_iterator it = from->outlinks.begin(); - it != from->outlinks.end(); - ++it) - { - DepsRelation *rel = *it; - if (rel->from == from && - rel->to == to && - rel->type == type && - rel->name == description) - { - BLI_assert(!"Duplicated relation, should not happen!"); - } - } -*/ -#endif - /* Hook it up to the nodes which use it. * * NOTE: We register relation in the nodes which this link connects to here @@ -477,17 +486,18 @@ ID *Depsgraph::get_cow_id(const ID *id_orig) const return id_node->id_cow; } -void deg_editors_id_update(Main *bmain, ID *id) +void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, ID *id) { if (deg_editor_update_id_cb != NULL) { - deg_editor_update_id_cb(bmain, id); + deg_editor_update_id_cb(update_ctx, id); } } -void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated) +void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, + bool updated) { if (deg_editor_update_scene_cb != NULL) { - deg_editor_update_scene_cb(bmain, scene, updated); + deg_editor_update_scene_cb(update_ctx, updated); } } @@ -513,17 +523,8 @@ void DEG_graph_free(Depsgraph *graph) /* Set callbacks which are being called when depsgraph changes. */ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, - DEG_EditorUpdateSceneCb scene_func, - DEG_EditorUpdateScenePreCb scene_pre_func) + DEG_EditorUpdateSceneCb scene_func) { DEG::deg_editor_update_id_cb = id_func; DEG::deg_editor_update_scene_cb = scene_func; - DEG::deg_editor_update_scene_pre_cb = scene_pre_func; -} - -void DEG_editors_update_pre(Main *bmain, Scene *scene, bool time) -{ - if (DEG::deg_editor_update_scene_pre_cb != NULL) { - DEG::deg_editor_update_scene_pre_cb(bmain, scene, time); - } } diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index d841ae045f2..8a34be0c7a2 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -123,11 +123,21 @@ struct Depsgraph { /* Add new relationship between two nodes. */ DepsRelation *add_new_relation(OperationDepsNode *from, OperationDepsNode *to, - const char *description); + const char *description, + bool check_unique = false); DepsRelation *add_new_relation(DepsNode *from, DepsNode *to, - const char *description); + const char *description, + bool check_unique = false); + + /* Check whether two nodes are connected by relation with given + * description. Description might be NULL to check ANY relation between + * given nodes. + */ + DepsRelation *check_nodes_connected(const DepsNode *from, + const DepsNode *to, + const char *description); /* Tag a specific node as needing updates. */ void add_entry_tag(OperationDepsNode *node); diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index 68cf4d77360..57153279acb 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -206,6 +206,7 @@ void DEG_graph_build_from_view_layer(Depsgraph *graph, #endif DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1); /* TODO(sergey): This is a bit tricky, but ensures that all the data * is evaluated properly when depsgraph is becoming "visible". diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index 31332b416d5..1d389b902b8 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -81,13 +81,13 @@ void DEG_evaluation_context_init(EvaluationContext *eval_ctx, void DEG_evaluation_context_init_from_scene(EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, - RenderEngineType *engine, + RenderEngineType *engine_type, eEvaluationMode mode) { DEG_evaluation_context_init(eval_ctx, mode); eval_ctx->depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false); eval_ctx->view_layer = view_layer; - eval_ctx->engine = engine; + eval_ctx->engine_type = engine_type; eval_ctx->ctime = BKE_scene_frame_get(scene); BLI_assert(eval_ctx->depsgraph != NULL); } diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h index 5ab090f3b3d..e7e472ea5d6 100644 --- a/source/blender/depsgraph/intern/depsgraph_intern.h +++ b/source/blender/depsgraph/intern/depsgraph_intern.h @@ -46,8 +46,9 @@ extern "C" { #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph.h" -struct Main; +struct DEGEditorUpdateContext; struct Group; +struct Main; struct Scene; namespace DEG { @@ -109,9 +110,11 @@ DepsNodeFactory *deg_node_get_factory(const DepsNode *node); /* Editors Integration -------------------------------------------------- */ -void deg_editors_id_update(struct Main *bmain, struct ID *id); +void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, + struct ID *id); -void deg_editors_scene_update(struct Main *bmain, struct Scene *scene, bool updated); +void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, + bool updated); /* Tagging helpers ------------------------------------------------------ */ diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index f2288e93beb..6892bdaa178 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -34,11 +34,7 @@ extern "C" { #include "BLI_utildefines.h" -#include "BLI_ghash.h" -#include "BLI_math.h" -#include "BKE_anim.h" #include "BKE_idcode.h" -#include "BKE_layer.h" #include "BKE_main.h" #include "BLI_listbase.h" } /* extern "C" */ @@ -50,11 +46,6 @@ extern "C" { #include "DEG_depsgraph_query.h" #include "intern/depsgraph_intern.h" -#include "util/deg_util_foreach.h" - -#ifndef NDEBUG -# include "intern/eval/deg_eval_copy_on_write.h" -#endif bool DEG_id_type_tagged(Main *bmain, short id_type) { @@ -122,159 +113,3 @@ ID *DEG_get_evaluated_id(struct Depsgraph *depsgraph, ID *id) return id_node->id_cow; } -/* ************************ DEG ITERATORS ********************* */ - -static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) -{ - DEGObjectsIteratorData *data = (DEGObjectsIteratorData *)iter->data; - while (data->dupli_object_next != NULL) { - DupliObject *dob = data->dupli_object_next; - Object *obd = dob->ob; - - data->dupli_object_next = data->dupli_object_next->next; - - /* Group duplis need to set ob matrices correct, for deform. so no_draw - * is part handled. - */ - if ((obd->transflag & OB_RENDER_DUPLI) == 0 && dob->no_draw) { - continue; - } - - if (obd->type == OB_MBALL) { - continue; - } - - data->dupli_object_current = dob; - - /* Temporary object to evaluate. */ - Object *dupli_parent = data->dupli_parent; - Object *temp_dupli_object = &data->temp_dupli_object; - *temp_dupli_object = *dob->ob; - temp_dupli_object->select_color = dupli_parent->select_color; - temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROMDUPLI; - temp_dupli_object->base_collection_properties = - dupli_parent->base_collection_properties; - copy_m4_m4(data->temp_dupli_object.obmat, dob->mat); - - iter->current = &data->temp_dupli_object; - BLI_assert( - DEG::deg_validate_copy_on_write_datablock( - &data->temp_dupli_object.id)); - return true; - } - - return false; -} - -static void deg_objects_iterator_step(BLI_Iterator *iter, DEG::IDDepsNode *id_node) -{ - /* Reset the skip in case we are running from within a loop. */ - iter->skip = false; - - DEGObjectsIteratorData *data = (DEGObjectsIteratorData *)iter->data; - const ID_Type id_type = GS(id_node->id_orig->name); - - if (id_type != ID_OB) { - iter->skip = true; - return; - } - - switch (id_node->linked_state) { - case DEG::DEG_ID_LINKED_DIRECTLY: - break; - case DEG::DEG_ID_LINKED_VIA_SET: - if (data->flag & DEG_OBJECT_ITER_FLAG_SET) { - break; - } - else { - ATTR_FALLTHROUGH; - } - case DEG::DEG_ID_LINKED_INDIRECTLY: - iter->skip = true; - return; - } - - Object *object = (Object *)id_node->id_cow; - BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id)); - - if ((data->flag & DEG_OBJECT_ITER_FLAG_DUPLI) && (object->transflag & OB_DUPLI)) { - data->dupli_parent = object; - data->dupli_list = object_duplilist(&data->eval_ctx, data->scene, object); - data->dupli_object_next = (DupliObject *)data->dupli_list->first; - } - - iter->current = object; -} - -void DEG_objects_iterator_begin(BLI_Iterator *iter, DEGObjectsIteratorData *data) -{ - Depsgraph *depsgraph = data->graph; - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); - const size_t num_id_nodes = deg_graph->id_nodes.size(); - - if (num_id_nodes == 0) { - iter->valid = false; - return; - } - - /* TODO(sergey): What evaluation type we want here? */ - DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_RENDER); - data->eval_ctx.view_layer = DEG_get_evaluated_view_layer(depsgraph); - - iter->data = data; - data->dupli_parent = NULL; - data->dupli_list = NULL; - data->dupli_object_next = NULL; - data->dupli_object_current = NULL; - data->scene = DEG_get_evaluated_scene(depsgraph); - data->id_node_index = 0; - data->num_id_nodes = num_id_nodes; - - DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index]; - deg_objects_iterator_step(iter, id_node); - - if (iter->skip) { - DEG_objects_iterator_next(iter); - } -} - -void DEG_objects_iterator_next(BLI_Iterator *iter) -{ - DEGObjectsIteratorData *data = (DEGObjectsIteratorData *)iter->data; - Depsgraph *depsgraph = data->graph; - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); - do { - if (data->dupli_list) { - if (deg_objects_dupli_iterator_next(iter)) { - return; - } - else { - free_object_duplilist(data->dupli_list); - data->dupli_parent = NULL; - data->dupli_list = NULL; - data->dupli_object_next = NULL; - data->dupli_object_current = NULL; - } - } - - ++data->id_node_index; - if (data->id_node_index == data->num_id_nodes) { - iter->valid = false; - return; - } - - DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index]; - deg_objects_iterator_step(iter, id_node); - } while (iter->skip); -} - -void DEG_objects_iterator_end(BLI_Iterator *iter) -{ -#ifndef NDEBUG - DEGObjectsIteratorData *data = (DEGObjectsIteratorData *)iter->data; - /* Force crash in case the iterator data is referenced and accessed down the line. (T51718) */ - memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object)); -#else - (void) iter; -#endif -} diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc new file mode 100644 index 00000000000..b1353f528bc --- /dev/null +++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc @@ -0,0 +1,147 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 Blender Foundation. + * All rights reserved. + * + * Original Author: Sergey Sharybin + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/depsgraph_query_foreach.cc + * \ingroup depsgraph + * + * Implementation of Querying and Filtering API's + */ + +// TODO(sergey): Use some sort of wrapper. +#include <deque> + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +} /* extern "C" */ + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "intern/depsgraph_intern.h" + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" + +#include "util/deg_util_foreach.h" + +/* ************************ DEG TRAVERSAL ********************* */ + +namespace DEG { + +typedef std::deque<OperationDepsNode *> TraversalQueue; + +static void deg_foreach_clear_flags(const Depsgraph *graph) +{ + foreach (OperationDepsNode *op_node, graph->operations) { + op_node->scheduled = false; + } + foreach (IDDepsNode *id_node, graph->id_nodes) { + id_node->done = false; + } +} + +static void deg_foreach_dependent_ID(const Depsgraph *graph, + const ID *id, + DEGForeachIDCallback callback, + void *user_data) +{ + /* Start with getting ID node from the graph. */ + IDDepsNode *id_node = graph->find_id_node(id); + if (id_node == NULL) { + /* TODO(sergey): Shall we inform or assert here about attempt to start + * iterating over non-existing ID? + */ + return; + } + /* Make sure all runtime flags are ready and clear. */ + deg_foreach_clear_flags(graph); + /* Start with scheduling all operations from ID node. */ + TraversalQueue queue; + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components) + { + foreach (OperationDepsNode *op_node, comp_node->operations) { + queue.push_back(op_node); + op_node->scheduled = true; + } + } + GHASH_FOREACH_END(); + id_node->done = true; + /* Process the queue. */ + while (!queue.empty()) { + /* get next operation node to process. */ + OperationDepsNode *op_node = queue.front(); + queue.pop_front(); + for (;;) { + /* Check whether we need to inform callee about corresponding ID node. */ + ComponentDepsNode *comp_node = op_node->owner; + IDDepsNode *id_node = comp_node->owner; + if (!id_node->done) { + /* TODO(sergey): Is it orig or CoW? */ + callback(id_node->id_orig, user_data); + id_node->done = true; + } + /* Schedule outgoing operation nodes. */ + if (op_node->outlinks.size() == 1) { + OperationDepsNode *to_node = (OperationDepsNode *)op_node->outlinks[0]->to; + if (to_node->scheduled == false) { + to_node->scheduled = true; + op_node = to_node; + } + else { + break; + } + } + else { + foreach (DepsRelation *rel, op_node->outlinks) { + OperationDepsNode *to_node = (OperationDepsNode *)rel->to; + if (to_node->scheduled == false) { + queue.push_front(to_node); + to_node->scheduled = true; + } + } + break; + } + } + } +} + +} // namespace DEG + +void DEG_foreach_dependent_ID(const Depsgraph *depsgraph, + const ID *id, + DEGForeachIDCallback callback, void *user_data) +{ + DEG::deg_foreach_dependent_ID((const DEG::Depsgraph *)depsgraph, + id, + callback, user_data); +} diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc new file mode 100644 index 00000000000..d8a54642a85 --- /dev/null +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -0,0 +1,211 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 Blender Foundation. + * All rights reserved. + * + * Original Author: Dalai Felinto + * Contributor(s): Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/depsgraph_query_iter.cc + * \ingroup depsgraph + * + * Implementation of Querying and Filtering API's + */ + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BKE_anim.h" +#include "BKE_idprop.h" +#include "BKE_layer.h" +} /* extern "C" */ + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" + +#ifndef NDEBUG +# include "intern/eval/deg_eval_copy_on_write.h" +#endif + +/* ************************ DEG ITERATORS ********************* */ + +static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) +{ + DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data; + while (data->dupli_object_next != NULL) { + DupliObject *dob = data->dupli_object_next; + Object *obd = dob->ob; + + data->dupli_object_next = data->dupli_object_next->next; + + /* Group duplis need to set ob matrices correct, for deform. so no_draw + * is part handled. + */ + if ((obd->transflag & OB_RENDER_DUPLI) == 0 && dob->no_draw) { + continue; + } + + if (obd->type == OB_MBALL) { + continue; + } + + data->dupli_object_current = dob; + + /* Temporary object to evaluate. */ + Object *dupli_parent = data->dupli_parent; + Object *temp_dupli_object = &data->temp_dupli_object; + *temp_dupli_object = *dob->ob; + temp_dupli_object->select_color = dupli_parent->select_color; + temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROMDUPLI; + BLI_assert(dob->collection_properties != NULL); + temp_dupli_object->base_collection_properties = dob->collection_properties; + IDP_MergeGroup(temp_dupli_object->base_collection_properties, dupli_parent->base_collection_properties, false); + copy_m4_m4(data->temp_dupli_object.obmat, dob->mat); + iter->current = &data->temp_dupli_object; + BLI_assert( + DEG::deg_validate_copy_on_write_datablock( + &data->temp_dupli_object.id)); + return true; + } + + return false; +} + +static void DEG_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_node) +{ + /* Reset the skip in case we are running from within a loop. */ + iter->skip = false; + + DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data; + const ID_Type id_type = GS(id_node->id_orig->name); + + if (id_type != ID_OB) { + iter->skip = true; + return; + } + + switch (id_node->linked_state) { + case DEG::DEG_ID_LINKED_DIRECTLY: + break; + case DEG::DEG_ID_LINKED_VIA_SET: + if (data->flag & DEG_ITER_OBJECT_FLAG_SET) { + break; + } + else { + ATTR_FALLTHROUGH; + } + case DEG::DEG_ID_LINKED_INDIRECTLY: + iter->skip = true; + return; + } + + Object *object = (Object *)id_node->id_cow; + BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id)); + + if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && (object->transflag & OB_DUPLI)) { + data->dupli_parent = object; + data->dupli_list = object_duplilist(&data->eval_ctx, data->scene, object); + data->dupli_object_next = (DupliObject *)data->dupli_list->first; + } + + iter->current = object; +} + +void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGOIterObjectData *data) +{ + Depsgraph *depsgraph = data->graph; + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + const size_t num_id_nodes = deg_graph->id_nodes.size(); + + if (num_id_nodes == 0) { + iter->valid = false; + return; + } + + /* TODO(sergey): What evaluation type we want here? */ + DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_RENDER); + data->eval_ctx.view_layer = DEG_get_evaluated_view_layer(depsgraph); + + iter->data = data; + data->dupli_parent = NULL; + data->dupli_list = NULL; + data->dupli_object_next = NULL; + data->dupli_object_current = NULL; + data->scene = DEG_get_evaluated_scene(depsgraph); + data->id_node_index = 0; + data->num_id_nodes = num_id_nodes; + + DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index]; + DEG_iterator_objects_step(iter, id_node); + + if (iter->skip) { + DEG_iterator_objects_next(iter); + } +} + +void DEG_iterator_objects_next(BLI_Iterator *iter) +{ + DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data; + Depsgraph *depsgraph = data->graph; + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + do { + if (data->dupli_list) { + if (deg_objects_dupli_iterator_next(iter)) { + return; + } + else { + free_object_duplilist(data->dupli_list); + data->dupli_parent = NULL; + data->dupli_list = NULL; + data->dupli_object_next = NULL; + data->dupli_object_current = NULL; + } + } + + ++data->id_node_index; + if (data->id_node_index == data->num_id_nodes) { + iter->valid = false; + return; + } + + DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index]; + DEG_iterator_objects_step(iter, id_node); + } while (iter->skip); +} + +void DEG_iterator_objects_end(BLI_Iterator *iter) +{ +#ifndef NDEBUG + DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data; + /* Force crash in case the iterator data is referenced and accessed down the line. (T51718) */ + memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object)); +#else + (void) iter; +#endif +} diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index faaf3a828b2..e928da58e87 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -111,11 +111,6 @@ void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag) * after relations update and after layer visibility changes. */ if (flag) { - ID_Type id_type = GS(id->name); - if (id_type == ID_OB) { - Object *object = (Object *)id; - object->recalc |= (flag & OB_RECALC_ALL); - } if (flag & OB_RECALC_OB) { lib_id_recalc_tag(bmain, id); } @@ -352,6 +347,19 @@ void id_tag_update_base_flags(Depsgraph *graph, IDDepsNode *id_node) } } +void id_tag_update_editors_update(Main *bmain, Depsgraph *graph, ID *id) +{ + /* NOTE: We handle this immediately, without delaying anything, to be + * sure we don't cause threading issues with OpenGL. + */ + /* TODO(sergey): Make sure this works for CoW-ed datablocks as well. */ + DEGEditorUpdateContext update_ctx = {NULL}; + update_ctx.bmain = bmain; + update_ctx.scene = graph->scene; + update_ctx.view_layer = graph->view_layer; + deg_editors_id_update(&update_ctx, id); +} + void id_tag_update_ntree_special(Main *bmain, Depsgraph *graph, ID *id, int flag) { bNodeTree *ntree = NULL; @@ -421,6 +429,9 @@ void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag) if (flag & DEG_TAG_BASE_FLAGS_UPDATE) { id_tag_update_base_flags(graph, id_node); } + if (flag & DEG_TAG_EDITORS_UPDATE) { + id_tag_update_editors_update(bmain, graph, id); + } id_tag_update_ntree_special(bmain, graph, id, flag); } @@ -445,14 +456,6 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph) /* Make sure objects are up to date. */ foreach (DEG::IDDepsNode *id_node, graph->id_nodes) { const ID_Type id_type = GS(id_node->id_orig->name); - /* TODO(sergey): Special exception for now. */ - if (id_type == ID_MSK) { - deg_graph_id_tag_update(bmain, graph, id_node->id_orig, 0); - } - if (id_type != ID_OB) { - /* Ignore non-object nodes on visibility changes. */ - continue; - } int flag = 0; /* We only tag components which needs an update. Tagging everything is * not a good idea because that might reset particles cache (or any @@ -502,7 +505,7 @@ void DEG_graph_id_tag_update(struct Main *bmain, DEG::deg_graph_id_tag_update(bmain, graph, id, flag); } -/* Tag given ID type for update. */ +/* Mark a particular datablock type as having changing. */ void DEG_id_type_tag(Main *bmain, short id_type) { if (id_type == ID_NT) { @@ -552,7 +555,10 @@ void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time)) /* Check if something was changed in the database and inform * editors about this. */ -void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time) +void DEG_ids_check_recalc(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + bool time) { ListBase *lbarray[MAX_LIBARRAY]; int a; @@ -570,7 +576,11 @@ void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time) } } - DEG::deg_editors_scene_update(bmain, scene, (updated || time)); + DEGEditorUpdateContext update_ctx = {NULL}; + update_ctx.bmain = bmain; + update_ctx.scene = scene; + update_ctx.view_layer = view_layer; + DEG::deg_editors_scene_update(&update_ctx, (updated || time)); } void DEG_ids_clear_recalc(Main *bmain) diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 99efd633524..97e38af4367 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -653,7 +653,7 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, switch (id_type) { case ID_SCE: { - done = scene_copy_inplace_no_main((Scene *)id_orig, (Scene*)id_cow); + done = scene_copy_inplace_no_main((Scene *)id_orig, (Scene *)id_cow); break; } case ID_ME: @@ -746,9 +746,15 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, * Note that we never free GPU materials from here since that's not * safe for threading and GPU materials are likely to be re-used. */ + /* TODO(sergey): Either move this to an utility function or redesign + * Copy-on-Write components in a way that only needed parts are being + * copied over. + */ ListBase gpumaterial_backup; ListBase *gpumaterial_ptr = NULL; Mesh *mesh_evaluated = NULL; + IDProperty *base_collection_properties = NULL; + short base_flag = 0; if (check_datablock_expanded(id_cow)) { switch (id_type) { case ID_MA: @@ -778,6 +784,9 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, object->data = mesh_evaluated->id.newid; } } + /* Make a backup of base flags. */ + base_collection_properties = object->base_collection_properties; + base_flag = object->base_flag; break; } default: @@ -795,8 +804,8 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, *gpumaterial_ptr = gpumaterial_backup; } if (id_type == ID_OB) { + Object *object = (Object *)id_cow; if (mesh_evaluated != NULL) { - Object *object = (Object *)id_cow; object->mesh_evaluated = mesh_evaluated; /* Do same thing as object update: override actual object data * pointer with evaluated datablock. @@ -811,6 +820,10 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, ((Mesh *)mesh_evaluated->id.newid)->edit_btmesh; } } + if (base_collection_properties != NULL) { + object->base_collection_properties = base_collection_properties; + object->base_flag = base_flag; + } } return id_cow; } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 715a95432c0..a30812c692f 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -56,6 +56,11 @@ extern "C" { namespace DEG { enum { + ID_STATE_NONE = 0, + ID_STATE_MODIFIED = 1, +}; + +enum { COMPONENT_STATE_NONE = 0, COMPONENT_STATE_SCHEDULED = 1, COMPONENT_STATE_DONE = 2, @@ -63,208 +68,201 @@ enum { typedef std::deque<OperationDepsNode *> FlushQueue; -static void flush_init_func(void *data_v, int i) +namespace { + +void flush_init_operation_node_func(void *data_v, int i) { - /* ID node's done flag is used to avoid multiple editors update - * for the same ID. - */ Depsgraph *graph = (Depsgraph *)data_v; OperationDepsNode *node = graph->operations[i]; - ComponentDepsNode *comp_node = node->owner; - IDDepsNode *id_node = comp_node->owner; - id_node->done = 0; - comp_node->done = COMPONENT_STATE_NONE; node->scheduled = false; } -/* Flush updates from tagged nodes outwards until all affected nodes - * are tagged. - */ -void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) +void flush_init_id_node_func(void *data_v, int i) { - const bool use_copy_on_write = DEG_depsgraph_use_copy_on_write(); - /* Sanity check. */ - if (graph == NULL) { - return; - } - - /* Nothing to update, early out. */ - if (BLI_gset_size(graph->entry_tags) == 0) { - return; - } + Depsgraph *graph = (Depsgraph *)data_v; + IDDepsNode *id_node = graph->id_nodes[i]; + id_node->done = ID_STATE_NONE; + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components) + comp_node->done = COMPONENT_STATE_NONE; + GHASH_FOREACH_END(); +} - /* TODO(sergey): With a bit of flag magic we can get rid of this - * extra loop. - */ +BLI_INLINE void flush_prepare(Depsgraph *graph) +{ const int num_operations = graph->operations.size(); - const bool do_threads = num_operations > 256; - BLI_task_parallel_range(0, - num_operations, + BLI_task_parallel_range(0, num_operations, + graph, + flush_init_operation_node_func, + (num_operations > 256)); + const int num_id_nodes = graph->id_nodes.size(); + BLI_task_parallel_range(0, num_id_nodes, graph, - flush_init_func, - do_threads); + flush_init_id_node_func, + (num_id_nodes > 256)); +} - FlushQueue queue; - /* Starting from the tagged "entry" nodes, flush outwards... */ - /* NOTE: Also need to ensure that for each of these, there is a path back to - * root, or else they won't be done. - * NOTE: Count how many nodes we need to handle - entry nodes may be - * component nodes which don't count for this purpose! - */ +BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue) +{ GSET_FOREACH_BEGIN(OperationDepsNode *, op_node, graph->entry_tags) { - queue.push_back(op_node); + queue->push_back(op_node); op_node->scheduled = true; } GSET_FOREACH_END(); +} - int num_flushed_objects = 0; - while (!queue.empty()) { - OperationDepsNode *node = queue.front(); - queue.pop_front(); - - for (;;) { - node->flag |= DEPSOP_FLAG_NEEDS_UPDATE; +BLI_INLINE void flush_handle_id_node(IDDepsNode *id_node) +{ + id_node->done = ID_STATE_MODIFIED; +} - ComponentDepsNode *comp_node = node->owner; - IDDepsNode *id_node = comp_node->owner; +/* TODO(sergey): We can reduce number of arguments here. */ +BLI_INLINE void flush_handle_component_node(Depsgraph *graph, + IDDepsNode *id_node, + ComponentDepsNode *comp_node, + bool use_copy_on_write, + FlushQueue *queue) +{ + /* We only handle component once. */ + if (comp_node->done == COMPONENT_STATE_DONE) { + return; + } + comp_node->done = COMPONENT_STATE_DONE; + /* Currently this is needed to get object->mesh to be replaced with + * original mesh (rather than being evaluated_mesh). + * + * TODO(sergey): This is something we need to avoid. + */ + if (use_copy_on_write && comp_node->depends_on_cow()) { + ComponentDepsNode *cow_comp = + id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE); + cow_comp->tag_update(graph); + } + /* Tag all required operations in component for update. */ + foreach (OperationDepsNode *op, comp_node->operations) { + /* We don't want to flush tags in "upstream" direction for + * certain types of operations. + * + * TODO(sergey): Need a more generic solution for this. + */ + if (op->opcode == DEG_OPCODE_PARTICLE_SETTINGS_EVAL) { + continue; + } + op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; + } + /* When some target changes bone, we might need to re-run the + * whole IK solver, otherwise result might be unpredictable. + */ + if (comp_node->type == DEG_NODE_TYPE_BONE) { + ComponentDepsNode *pose_comp = + id_node->find_component(DEG_NODE_TYPE_EVAL_POSE); + BLI_assert(pose_comp != NULL); + if (pose_comp->done == COMPONENT_STATE_NONE) { + queue->push_front(pose_comp->get_entry_operation()); + pose_comp->done = COMPONENT_STATE_SCHEDULED; + } + } +} - /* TODO(sergey): Do we need to pass original or evaluated ID here? */ - ID *id_orig = id_node->id_orig; - ID *id_cow = id_node->id_cow; - if (id_node->done == 0) { - /* Copy tag from original data to CoW storage. - * This is because DEG_id_tag_update() sets tags on original - * data. - */ - id_cow->tag |= (id_orig->tag & LIB_TAG_ID_RECALC_ALL); - if (deg_copy_on_write_is_expanded(id_cow)) { - deg_editors_id_update(bmain, id_cow); - } - lib_id_recalc_tag(bmain, id_orig); - /* TODO(sergey): For until we've got proper data nodes in the graph. */ - lib_id_recalc_data_tag(bmain, id_orig); +/* Schedule children of the given operation node for traversal. + * + * One of the children will by-pass the queue and will be returned as a function + * return value, so it can start being handled right away, without building too + * much of a queue. + */ +BLI_INLINE OperationDepsNode *flush_schedule_children( + OperationDepsNode *op_node, + FlushQueue *queue) +{ + OperationDepsNode *result = NULL; + foreach (DepsRelation *rel, op_node->outlinks) { + OperationDepsNode *to_node = (OperationDepsNode *)rel->to; + if (to_node->scheduled == false) { + if (result != NULL) { + queue->push_front(to_node); } - - if (comp_node->done != COMPONENT_STATE_DONE) { - /* Currently this is needed to get object->mesh to be replaced with - * original mesh (rather than being evaluated_mesh). - * - * TODO(sergey): This is something we need to avoid. - */ - if (use_copy_on_write && comp_node->depends_on_cow()) { - ComponentDepsNode *cow_comp = - id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE); - cow_comp->tag_update(graph); - } - - Object *object = NULL; - if (GS(id_orig->name) == ID_OB) { - object = (Object *)id_orig; - if (id_node->done == 0) { - ++num_flushed_objects; - } - } - foreach (OperationDepsNode *op, comp_node->operations) { - /* We don't want to flush tags in "upstream" direction for - * certain types of operations. - * - * TODO(sergey): Need a more generic solution for this. - */ - if (op->opcode == DEG_OPCODE_PARTICLE_SETTINGS_EVAL) { - continue; - } - op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; - } - if (object != NULL) { - /* This code is used to preserve those areas which does - * direct object update, - * - * Plus it ensures visibility changes and relations and - * layers visibility update has proper flags to work with. - */ - switch (comp_node->type) { - case DEG_NODE_TYPE_UNDEFINED: - case DEG_NODE_TYPE_OPERATION: - case DEG_NODE_TYPE_TIMESOURCE: - case DEG_NODE_TYPE_ID_REF: - case DEG_NODE_TYPE_PARAMETERS: - case DEG_NODE_TYPE_SEQUENCER: - /* Ignore, does not translate to object component. */ - BLI_assert(!"This should never happen!"); - break; - case DEG_NODE_TYPE_ANIMATION: - object->recalc |= OB_RECALC_TIME; - break; - case DEG_NODE_TYPE_TRANSFORM: - object->recalc |= OB_RECALC_OB; - break; - case DEG_NODE_TYPE_GEOMETRY: - case DEG_NODE_TYPE_EVAL_POSE: - case DEG_NODE_TYPE_BONE: - case DEG_NODE_TYPE_EVAL_PARTICLES: - case DEG_NODE_TYPE_SHADING: - case DEG_NODE_TYPE_CACHE: - case DEG_NODE_TYPE_PROXY: - object->recalc |= OB_RECALC_DATA; - break; - case DEG_NODE_TYPE_BATCH_CACHE: - case DEG_NODE_TYPE_SHADING_PARAMETERS: - case DEG_NODE_TYPE_LAYER_COLLECTIONS: - case DEG_NODE_TYPE_COPY_ON_WRITE: - /* Ignore, does not translate to recalc flags. */ - break; - } - - /* TODO : replace with more granular flags */ - object->deg_update_flag |= DEG_RUNTIME_DATA_UPDATE; - } - /* When some target changes bone, we might need to re-run the - * whole IK solver, otherwise result might be unpredictable. - */ - if (comp_node->type == DEG_NODE_TYPE_BONE) { - ComponentDepsNode *pose_comp = - id_node->find_component(DEG_NODE_TYPE_EVAL_POSE); - BLI_assert(pose_comp != NULL); - if (pose_comp->done == COMPONENT_STATE_NONE) { - queue.push_front(pose_comp->get_entry_operation()); - pose_comp->done = COMPONENT_STATE_SCHEDULED; - } - } + else { + result = to_node; } + to_node->scheduled = true; + } + } + return result; +} - id_node->done = 1; - comp_node->done = COMPONENT_STATE_DONE; +BLI_INLINE void flush_editors_id_update(Main *bmain, + Depsgraph *graph, + const DEGEditorUpdateContext *update_ctx) +{ + foreach (IDDepsNode *id_node, graph->id_nodes) { + if (id_node->done != ID_STATE_MODIFIED) { + continue; + } + /* TODO(sergey): Do we need to pass original or evaluated ID here? */ + ID *id_orig = id_node->id_orig; + ID *id_cow = id_node->id_cow; + /* Copy tag from original data to CoW storage. + * This is because DEG_id_tag_update() sets tags on original + * data. + */ + id_cow->tag |= (id_orig->tag & LIB_TAG_ID_RECALC_ALL); + if (deg_copy_on_write_is_expanded(id_cow)) { + deg_editors_id_update(update_ctx, id_cow); + } + lib_id_recalc_tag(bmain, id_orig); + /* TODO(sergey): For until we've got proper data nodes in the graph. */ + lib_id_recalc_data_tag(bmain, id_orig); + } +} - /* Flush to nodes along links... */ - /* TODO(sergey): This is mainly giving speedup due ot less queue pushes, which - * reduces number of memory allocations. - * - * We should try solve the allocation issue instead of doing crazy things here. - */ - if (node->outlinks.size() == 1) { - OperationDepsNode *to_node = (OperationDepsNode *)node->outlinks[0]->to; - if (to_node->scheduled == false) { - to_node->scheduled = true; - node = to_node; - } - else { - break; - } - } - else { - foreach (DepsRelation *rel, node->outlinks) { - OperationDepsNode *to_node = (OperationDepsNode *)rel->to; - if (to_node->scheduled == false) { - queue.push_front(to_node); - to_node->scheduled = true; - } - } - break; - } +} // namespace + +/* Flush updates from tagged nodes outwards until all affected nodes + * are tagged. + */ +void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) +{ + const bool use_copy_on_write = DEG_depsgraph_use_copy_on_write(); + /* Sanity checks. */ + BLI_assert(bmain != NULL); + BLI_assert(graph != NULL); + /* Nothing to update, early out. */ + if (BLI_gset_size(graph->entry_tags) == 0) { + return; + } + /* Reset all flags, get ready for the flush. */ + flush_prepare(graph); + /* Starting from the tagged "entry" nodes, flush outwards. */ + FlushQueue queue; + flush_schedule_entrypoints(graph, &queue); + /* Prepare update context for editors. */ + DEGEditorUpdateContext update_ctx = { + bmain, + graph->scene, + graph->view_layer, + }; + /* Do actual flush. */ + while (!queue.empty()) { + OperationDepsNode *op_node = queue.front(); + queue.pop_front(); + while (op_node != NULL) { + /* Tag operation as required for update. */ + op_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE; + /* Inform corresponding ID and component nodes about the change. */ + ComponentDepsNode *comp_node = op_node->owner; + IDDepsNode *id_node = comp_node->owner; + flush_handle_id_node(id_node); + flush_handle_component_node(graph, + id_node, + comp_node, + use_copy_on_write, + &queue); + /* Flush to nodes along links. */ + op_node = flush_schedule_children(op_node, &queue); } } - DEG_DEBUG_PRINTF("Update flushed to %d objects\n", num_flushed_objects); + /* Inform editors about all changes. */ + flush_editors_id_update(bmain, graph, &update_ctx); } static void graph_clear_func(void *data_v, int i) diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 9c806f26fda..8339b6b8720 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -137,6 +137,7 @@ data_to_c_simple(engines/eevee/shaders/lamps_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_geom.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_cube_display_frag.glsl SRC) diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index da7524754de..ba0f8681f10 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -30,9 +30,11 @@ struct ARegion; struct CollectionEngineSettings; struct Depsgraph; struct DRWPass; +struct Main; struct Material; struct Scene; struct DrawEngineType; +struct ID; struct IDProperty; struct bContext; struct Object; @@ -68,13 +70,22 @@ void DRW_engine_viewport_data_size_get( const void *engine_type, int *r_fbl_len, int *r_txl_len, int *r_psl_len, int *r_stl_len); -void DRW_notify_view_update(const struct bContext *C); +typedef struct DRWUpdateContext { + struct Main *bmain; + struct Scene *scene; + struct ViewLayer *view_layer; + struct ARegion *ar; + struct View3D *v3d; + struct RenderEngineType *engine_type; +} DRWUpdateContext; +void DRW_notify_view_update(const DRWUpdateContext *update_ctx); +void DRW_notify_id_update(const DRWUpdateContext *update_ctx, struct ID *id); void DRW_draw_view(const struct bContext *C); void DRW_draw_render_loop_ex( struct Depsgraph *graph, - struct RenderEngineType *engine, + struct RenderEngineType *engine_type, struct ARegion *ar, struct View3D *v3d, const struct bContext *evil_C); void DRW_draw_render_loop( @@ -82,7 +93,7 @@ void DRW_draw_render_loop( struct ARegion *ar, struct View3D *v3d); void DRW_draw_render_loop_offscreen( struct Depsgraph *graph, - struct RenderEngineType *engine, + struct RenderEngineType *engine_type, struct ARegion *ar, struct View3D *v3d, struct GPUOffScreen *ofs); void DRW_draw_select_loop( diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index 92ffa8a1794..10dfe7b5996 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -111,7 +111,7 @@ typedef struct BASIC_PrivateData { /* Functions */ -static void BASIC_engine_init(void *vedata) +static void basic_engine_init(void *vedata) { BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl; BASIC_TextureList *txl = ((BASIC_Data *)vedata)->txl; @@ -144,7 +144,7 @@ static void BASIC_engine_init(void *vedata) #endif } -static void BASIC_cache_init(void *vedata) +static void basic_cache_init(void *vedata) { BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl; BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl; @@ -174,7 +174,7 @@ static void BASIC_cache_init(void *vedata) } } -static void BASIC_cache_populate(void *vedata, Object *ob) +static void basic_cache_populate(void *vedata, Object *ob) { BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl; @@ -193,14 +193,14 @@ static void BASIC_cache_populate(void *vedata, Object *ob) } } -static void BASIC_cache_finish(void *vedata) +static void basic_cache_finish(void *vedata) { BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl; UNUSED_VARS(stl); } -static void BASIC_draw_scene(void *vedata) +static void basic_draw_scene(void *vedata) { BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl; @@ -244,24 +244,25 @@ static void BASIC_draw_scene(void *vedata) } } -static void BASIC_engine_free(void) +static void basic_engine_free(void) { /* all shaders are builtin */ } -static const DrawEngineDataSize BASIC_data_size = DRW_VIEWPORT_DATA_SIZE(BASIC_Data); +static const DrawEngineDataSize basic_data_size = DRW_VIEWPORT_DATA_SIZE(BASIC_Data); DrawEngineType draw_engine_basic_type = { NULL, NULL, N_("Basic"), - &BASIC_data_size, - &BASIC_engine_init, - &BASIC_engine_free, - &BASIC_cache_init, - &BASIC_cache_populate, - &BASIC_cache_finish, + &basic_data_size, + &basic_engine_init, + &basic_engine_free, + &basic_cache_init, + &basic_cache_populate, + &basic_cache_finish, + NULL, + &basic_draw_scene, NULL, - &BASIC_draw_scene, NULL, }; diff --git a/source/blender/draw/engines/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c index fe81e1e484c..01f89ae6b1c 100644 --- a/source/blender/draw/engines/clay/clay_engine.c +++ b/source/blender/draw/engines/clay/clay_engine.c @@ -197,7 +197,7 @@ static void clay_view_layer_data_free(void *storage) static CLAY_ViewLayerData *CLAY_view_layer_data_get(void) { - CLAY_ViewLayerData **sldata = (CLAY_ViewLayerData **)DRW_view_layer_engine_data_get(&draw_engine_clay_type, &clay_view_layer_data_free); + CLAY_ViewLayerData **sldata = (CLAY_ViewLayerData **)DRW_view_layer_engine_data_ensure(&draw_engine_clay_type, &clay_view_layer_data_free); if (*sldata == NULL) { *sldata = MEM_callocN(sizeof(**sldata), "CLAY_ViewLayerData"); @@ -322,7 +322,7 @@ static struct GPUTexture *create_jitter_texture(int num_samples) return DRW_texture_create_2D(64, 64, DRW_TEX_RGB_16, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]); } -static void CLAY_engine_init(void *vedata) +static void clay_engine_init(void *vedata) { CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl; @@ -702,7 +702,7 @@ static DRWShadingGroup *CLAY_object_shgrp_default_mode_get( return CLAY_object_shgrp_get(vedata, ob, stl, psl, use_flat); } -static void CLAY_cache_init(void *vedata) +static void clay_cache_init(void *vedata) { CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; @@ -746,7 +746,7 @@ static void CLAY_cache_init(void *vedata) } } -static void CLAY_cache_populate(void *vedata, Object *ob) +static void clay_cache_populate(void *vedata, Object *ob) { CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; @@ -826,7 +826,7 @@ static void CLAY_cache_populate(void *vedata, Object *ob) } } -static void CLAY_cache_finish(void *vedata) +static void clay_cache_finish(void *vedata) { CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; @@ -834,7 +834,7 @@ static void CLAY_cache_finish(void *vedata) DRW_uniformbuffer_update(stl->hair_mat_ubo, &stl->storage->hair_mat_storage); } -static void CLAY_draw_scene(void *vedata) +static void clay_draw_scene(void *vedata) { CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; @@ -866,7 +866,7 @@ static void CLAY_draw_scene(void *vedata) DRW_draw_pass(psl->hair_pass); } -static void CLAY_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props) +static void clay_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props) { BLI_assert(props && props->type == IDP_GROUP && @@ -885,7 +885,7 @@ static void CLAY_layer_collection_settings_create(RenderEngine *UNUSED(engine), BKE_collection_engine_property_add_float(props, "hair_brightness_randomness", 0.0f); } -static void CLAY_view_layer_settings_create(RenderEngine *UNUSED(engine), IDProperty *props) +static void clay_view_layer_settings_create(RenderEngine *UNUSED(engine), IDProperty *props) { BLI_assert(props && props->type == IDP_GROUP && @@ -894,7 +894,7 @@ static void CLAY_view_layer_settings_create(RenderEngine *UNUSED(engine), IDProp BKE_collection_engine_property_add_int(props, "ssao_samples", 16); } -static void CLAY_engine_free(void) +static void clay_engine_free(void) { DRW_SHADER_FREE_SAFE(e_data.clay_sh); DRW_SHADER_FREE_SAFE(e_data.clay_flat_sh); @@ -902,19 +902,20 @@ static void CLAY_engine_free(void) DRW_TEXTURE_FREE_SAFE(e_data.matcap_array); } -static const DrawEngineDataSize CLAY_data_size = DRW_VIEWPORT_DATA_SIZE(CLAY_Data); +static const DrawEngineDataSize clay_data_size = DRW_VIEWPORT_DATA_SIZE(CLAY_Data); DrawEngineType draw_engine_clay_type = { NULL, NULL, N_("Clay"), - &CLAY_data_size, - &CLAY_engine_init, - &CLAY_engine_free, - &CLAY_cache_init, - &CLAY_cache_populate, - &CLAY_cache_finish, + &clay_data_size, + &clay_engine_init, + &clay_engine_free, + &clay_cache_init, + &clay_cache_populate, + &clay_cache_finish, + NULL, + &clay_draw_scene, NULL, - &CLAY_draw_scene, NULL, }; @@ -922,8 +923,8 @@ RenderEngineType DRW_engine_viewport_clay_type = { NULL, NULL, CLAY_ENGINE, N_("Clay"), RE_INTERNAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &CLAY_layer_collection_settings_create, - &CLAY_view_layer_settings_create, + &clay_layer_collection_settings_create, + &clay_view_layer_settings_create, &draw_engine_clay_type, {NULL, NULL, NULL} }; @@ -931,4 +932,4 @@ RenderEngineType DRW_engine_viewport_clay_type = { #undef CLAY_ENGINE -#endif +#endif /* WITH_CLAY_ENGINE */ diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index 6b95844591d..d5582a498a4 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -55,6 +55,7 @@ static void eevee_view_layer_data_free(void *storage) DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb); DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb); DRW_TEXTURE_FREE_SAFE(sldata->probe_rt); + DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt); DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool); DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt); @@ -80,7 +81,13 @@ static void eevee_lightprobe_data_free(void *storage) EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void) { - EEVEE_ViewLayerData **sldata = (EEVEE_ViewLayerData **)DRW_view_layer_engine_data_get( + return (EEVEE_ViewLayerData *)DRW_view_layer_engine_data_get( + &draw_engine_eevee_type); +} + +EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void) +{ + EEVEE_ViewLayerData **sldata = (EEVEE_ViewLayerData **)DRW_view_layer_engine_data_ensure( &draw_engine_eevee_type, &eevee_view_layer_data_free); if (*sldata == NULL) { @@ -92,7 +99,13 @@ EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void) EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob) { - EEVEE_ObjectEngineData **oedata = (EEVEE_ObjectEngineData **)DRW_object_engine_data_get( + return (EEVEE_ObjectEngineData *)DRW_object_engine_data_get( + ob, &draw_engine_eevee_type); +} + +EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob) +{ + EEVEE_ObjectEngineData **oedata = (EEVEE_ObjectEngineData **)DRW_object_engine_data_ensure( ob, &draw_engine_eevee_type, NULL); if (*oedata == NULL) { @@ -104,11 +117,18 @@ EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob) EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob) { - EEVEE_LightProbeEngineData **pedata = (EEVEE_LightProbeEngineData **)DRW_object_engine_data_get( + return (EEVEE_LightProbeEngineData *)DRW_object_engine_data_get( + ob, &draw_engine_eevee_type); +} + +EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob) +{ + EEVEE_LightProbeEngineData **pedata = (EEVEE_LightProbeEngineData **)DRW_object_engine_data_ensure( ob, &draw_engine_eevee_type, &eevee_lightprobe_data_free); if (*pedata == NULL) { *pedata = MEM_callocN(sizeof(**pedata), "EEVEE_LightProbeEngineData"); + (*pedata)->need_full_update = true; (*pedata)->need_update = true; } @@ -117,7 +137,13 @@ EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob) EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob) { - EEVEE_LampEngineData **ledata = (EEVEE_LampEngineData **)DRW_object_engine_data_get( + return (EEVEE_LampEngineData *)DRW_object_engine_data_get( + ob, &draw_engine_eevee_type); +} + +EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob) +{ + EEVEE_LampEngineData **ledata = (EEVEE_LampEngineData **)DRW_object_engine_data_ensure( ob, &draw_engine_eevee_type, &eevee_lamp_data_free); if (*ledata == NULL) { diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index f059fbe2268..a20b1afe3d4 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -44,13 +44,13 @@ extern GlobalsUboStorage ts; /* *********** FUNCTIONS *********** */ -static void EEVEE_engine_init(void *ved) +static void eevee_engine_init(void *ved) { EEVEE_Data *vedata = (EEVEE_Data *)ved; EEVEE_TextureList *txl = vedata->txl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; - EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_get(); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); if (!stl->g_data) { /* Alloc transient pointers */ @@ -82,10 +82,10 @@ static void EEVEE_engine_init(void *ved) } } -static void EEVEE_cache_init(void *vedata) +static void eevee_cache_init(void *vedata) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; - EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_get(); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); EEVEE_bloom_cache_init(sldata, vedata); EEVEE_depth_of_field_cache_init(sldata, vedata); @@ -101,9 +101,9 @@ static void EEVEE_cache_init(void *vedata) EEVEE_volumes_cache_init(sldata, vedata); } -static void EEVEE_cache_populate(void *vedata, Object *ob) +static void eevee_cache_populate(void *vedata, Object *ob) { - EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_get(); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); const DRWContextState *draw_ctx = DRW_context_state_get(); const bool is_active = (ob == draw_ctx->obact); @@ -128,8 +128,6 @@ static void EEVEE_cache_populate(void *vedata, Object *ob) } else { BLI_addtail(&sldata->shadow_casters, BLI_genericNodeN(ob)); - EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(ob); - oedata->need_update = ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0); } } } @@ -151,21 +149,21 @@ static void EEVEE_cache_populate(void *vedata, Object *ob) } } -static void EEVEE_cache_finish(void *vedata) +static void eevee_cache_finish(void *vedata) { - EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_get(); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); EEVEE_materials_cache_finish(vedata); EEVEE_lights_cache_finish(sldata); EEVEE_lightprobes_cache_finish(sldata, vedata); } -static void EEVEE_draw_scene(void *vedata) +static void eevee_draw_scene(void *vedata) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl; - EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_get(); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); /* Default framebuffer and texture */ DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); @@ -279,7 +277,7 @@ static void EEVEE_draw_scene(void *vedata) stl->g_data->view_updated = false; } -static void EEVEE_view_update(void *vedata) +static void eevee_view_update(void *vedata) { EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; if (stl->g_data) { @@ -287,7 +285,27 @@ static void EEVEE_view_update(void *vedata) } } -static void EEVEE_engine_free(void) +static void eevee_id_update(void *UNUSED(vedata), ID *id) +{ + const ID_Type id_type = GS(id->name); + if (id_type == ID_OB) { + Object *object = (Object *)id; + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object); + if (ped != NULL) { + ped->need_full_update = true; + } + EEVEE_LampEngineData *led = EEVEE_lamp_data_get(object); + if (led != NULL) { + led->need_update = true; + } + EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object); + if (oedata != NULL) { + oedata->need_update = true; + } + } +} + +static void eevee_engine_free(void) { EEVEE_bloom_free(); EEVEE_depth_of_field_free(); @@ -303,7 +321,7 @@ static void EEVEE_engine_free(void) EEVEE_volumes_free(); } -static void EEVEE_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props) +static void eevee_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props) { BLI_assert(props && props->type == IDP_GROUP && @@ -312,7 +330,7 @@ static void EEVEE_layer_collection_settings_create(RenderEngine *UNUSED(engine), UNUSED_VARS_NDEBUG(props); } -static void EEVEE_view_layer_settings_create(RenderEngine *UNUSED(engine), IDProperty *props) +static void eevee_view_layer_settings_create(RenderEngine *UNUSED(engine), IDProperty *props) { BLI_assert(props && props->type == IDP_GROUP && @@ -320,6 +338,7 @@ static void EEVEE_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro BKE_collection_engine_property_add_int(props, "gi_diffuse_bounces", 3); BKE_collection_engine_property_add_int(props, "gi_cubemap_resolution", 512); + BKE_collection_engine_property_add_int(props, "gi_visibility_resolution", 32); BKE_collection_engine_property_add_int(props, "taa_samples", 8); @@ -381,27 +400,29 @@ static void EEVEE_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro BKE_collection_engine_property_add_bool(props, "shadow_high_bitdepth", false); } -static const DrawEngineDataSize EEVEE_data_size = DRW_VIEWPORT_DATA_SIZE(EEVEE_Data); +static const DrawEngineDataSize eevee_data_size = DRW_VIEWPORT_DATA_SIZE(EEVEE_Data); DrawEngineType draw_engine_eevee_type = { NULL, NULL, N_("Eevee"), - &EEVEE_data_size, - &EEVEE_engine_init, - &EEVEE_engine_free, - &EEVEE_cache_init, - &EEVEE_cache_populate, - &EEVEE_cache_finish, - &EEVEE_draw_scene, + &eevee_data_size, + &eevee_engine_init, + &eevee_engine_free, + &eevee_cache_init, + &eevee_cache_populate, + &eevee_cache_finish, + &eevee_draw_scene, NULL, //&EEVEE_draw_scene - &EEVEE_view_update, + &eevee_view_update, + &eevee_id_update, }; RenderEngineType DRW_engine_viewport_eevee_type = { NULL, NULL, EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_SHADING_NODES, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &EEVEE_layer_collection_settings_create, &EEVEE_view_layer_settings_create, + &eevee_layer_collection_settings_create, + &eevee_view_layer_settings_create, &draw_engine_eevee_type, {NULL, NULL, NULL} }; diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index a58e6e20c58..d7ccc1a5336 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -46,12 +46,30 @@ #include "ED_screen.h" -#define IRRADIANCE_POOL_SIZE 1024 +/* Rounded to nearest PowerOfTwo */ +#if defined(IRRADIANCE_SH_L2) +#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */ +#define IRRADIANCE_SAMPLE_SIZE_Y 4 /* 3 in reality */ +#elif defined(IRRADIANCE_CUBEMAP) +#define IRRADIANCE_SAMPLE_SIZE_X 8 +#define IRRADIANCE_SAMPLE_SIZE_Y 8 +#elif defined(IRRADIANCE_HL2) +#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */ +#define IRRADIANCE_SAMPLE_SIZE_Y 2 +#endif + +#define IRRADIANCE_MAX_POOL_LAYER 256 /* OpenGL 3.3 core requirement, can be extended but it's already very big */ +#define IRRADIANCE_MAX_POOL_SIZE 1024 +#define MAX_IRRADIANCE_SAMPLES \ + (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_X) * \ + (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_Y) +#define HAMMERSLEY_SIZE 1024 static struct { struct GPUShader *probe_default_sh; struct GPUShader *probe_filter_glossy_sh; struct GPUShader *probe_filter_diffuse_sh; + struct GPUShader *probe_filter_visibility_sh; struct GPUShader *probe_grid_fill_sh; struct GPUShader *probe_grid_display_sh; struct GPUShader *probe_planar_display_sh; @@ -62,7 +80,6 @@ static struct { struct GPUTexture *planar_pool_placeholder; struct GPUTexture *depth_placeholder; struct GPUTexture *depth_array_placeholder; - struct GPUTexture *cube_face_depth; struct GPUTexture *cube_face_minmaxz; int update_world; @@ -73,6 +90,7 @@ extern char datatoc_background_vert_glsl[]; extern char datatoc_default_world_frag_glsl[]; extern char datatoc_lightprobe_filter_glossy_frag_glsl[]; extern char datatoc_lightprobe_filter_diffuse_frag_glsl[]; +extern char datatoc_lightprobe_filter_visibility_frag_glsl[]; extern char datatoc_lightprobe_geom_glsl[]; extern char datatoc_lightprobe_vert_glsl[]; extern char datatoc_lightprobe_planar_display_frag_glsl[]; @@ -95,6 +113,21 @@ extern GlobalsUboStorage ts; /* *********** FUNCTIONS *********** */ +static void irradiance_pool_size_get(int visibility_size, int total_samples, int r_size[3]) +{ + /* Compute how many irradiance samples we can store per visibility sample. */ + int irr_per_vis = (visibility_size / IRRADIANCE_SAMPLE_SIZE_X) * + (visibility_size / IRRADIANCE_SAMPLE_SIZE_Y); + + /* The irradiance itself take one layer, hence the +1 */ + int layer_ct = MIN2(irr_per_vis + 1, IRRADIANCE_MAX_POOL_LAYER); + + int texel_ct = (int)ceilf((float)total_samples / (float)(layer_ct - 1)); + r_size[0] = visibility_size * max_ii(1, min_ii(texel_ct, (IRRADIANCE_MAX_POOL_SIZE / visibility_size))); + r_size[1] = visibility_size * max_ii(1, (texel_ct / (IRRADIANCE_MAX_POOL_SIZE / visibility_size))); + r_size[2] = layer_ct; +} + static struct GPUTexture *create_hammersley_sample_texture(int samples) { struct GPUTexture *tex; @@ -157,110 +190,110 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref) } } -void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata)) +static void lightprobe_shaders_init(void) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - ViewLayer *view_layer = draw_ctx->view_layer; - IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); - - /* Shaders */ - if (!e_data.probe_filter_glossy_sh) { - char *shader_str = NULL; - - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_glossy_frag_glsl); - shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - e_data.probe_filter_glossy_sh = DRW_shader_create( - datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str, - "#define HAMMERSLEY_SIZE 1024\n" - "#define NOISE_SIZE 64\n"); - - e_data.probe_default_sh = DRW_shader_create( - datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, NULL); - - MEM_freeN(shader_str); - - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_diffuse_frag_glsl); - shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen( - shader_str, + const char *filter_defines = "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n" #if defined(IRRADIANCE_SH_L2) - "#define IRRADIANCE_SH_L2\n" + "#define IRRADIANCE_SH_L2\n" #elif defined(IRRADIANCE_CUBEMAP) - "#define IRRADIANCE_CUBEMAP\n" + "#define IRRADIANCE_CUBEMAP\n" #elif defined(IRRADIANCE_HL2) - "#define IRRADIANCE_HL2\n" + "#define IRRADIANCE_HL2\n" #endif - "#define HAMMERSLEY_SIZE 1024\n" - "#define NOISE_SIZE 64\n"); - - MEM_freeN(shader_str); - - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_grid_display_frag_glsl); - shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - e_data.probe_grid_display_sh = DRW_shader_create( - datatoc_lightprobe_grid_display_vert_glsl, NULL, shader_str, -#if defined(IRRADIANCE_SH_L2) - "#define IRRADIANCE_SH_L2\n" -#elif defined(IRRADIANCE_CUBEMAP) - "#define IRRADIANCE_CUBEMAP\n" -#elif defined(IRRADIANCE_HL2) - "#define IRRADIANCE_HL2\n" -#endif - ); + "#define NOISE_SIZE 64\n"; - MEM_freeN(shader_str); + char *shader_str = NULL; - e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen(datatoc_lightprobe_grid_fill_frag_glsl, -#if defined(IRRADIANCE_SH_L2) - "#define IRRADIANCE_SH_L2\n" -#elif defined(IRRADIANCE_CUBEMAP) - "#define IRRADIANCE_CUBEMAP\n" -#elif defined(IRRADIANCE_HL2) - "#define IRRADIANCE_HL2\n" -#endif - ); + DynStr *ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_glossy_frag_glsl); + shader_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + e_data.probe_filter_glossy_sh = DRW_shader_create( + datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str, filter_defines); + + e_data.probe_default_sh = DRW_shader_create( + datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, NULL); + + MEM_freeN(shader_str); + + ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_diffuse_frag_glsl); + shader_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen(shader_str, filter_defines); + + MEM_freeN(shader_str); + + ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_visibility_frag_glsl); + shader_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen(shader_str, filter_defines); - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_cube_display_frag_glsl); - shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); + MEM_freeN(shader_str); - e_data.probe_cube_display_sh = DRW_shader_create( - datatoc_lightprobe_cube_display_vert_glsl, NULL, shader_str, NULL); + ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lightprobe_grid_display_frag_glsl); + shader_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); - MEM_freeN(shader_str); + e_data.probe_grid_display_sh = DRW_shader_create( + datatoc_lightprobe_grid_display_vert_glsl, NULL, shader_str, filter_defines); - e_data.probe_planar_display_sh = DRW_shader_create( - datatoc_lightprobe_planar_display_vert_glsl, NULL, - datatoc_lightprobe_planar_display_frag_glsl, NULL); + MEM_freeN(shader_str); - e_data.probe_planar_downsample_sh = DRW_shader_create( - datatoc_lightprobe_planar_downsample_vert_glsl, - datatoc_lightprobe_planar_downsample_geom_glsl, - datatoc_lightprobe_planar_downsample_frag_glsl, - NULL); + e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen( + datatoc_lightprobe_grid_fill_frag_glsl, filter_defines); - e_data.hammersley = create_hammersley_sample_texture(1024); + ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lightprobe_cube_display_frag_glsl); + shader_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + e_data.probe_cube_display_sh = DRW_shader_create( + datatoc_lightprobe_cube_display_vert_glsl, NULL, shader_str, NULL); + + MEM_freeN(shader_str); + + e_data.probe_planar_display_sh = DRW_shader_create( + datatoc_lightprobe_planar_display_vert_glsl, NULL, + datatoc_lightprobe_planar_display_frag_glsl, NULL); + + e_data.probe_planar_downsample_sh = DRW_shader_create( + datatoc_lightprobe_planar_downsample_vert_glsl, + datatoc_lightprobe_planar_downsample_geom_glsl, + datatoc_lightprobe_planar_downsample_frag_glsl, + NULL); + + e_data.hammersley = create_hammersley_sample_texture(HAMMERSLEY_SIZE); +} + +void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata)) +{ + bool update_all = false; + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + + /* Shaders */ + if (!e_data.probe_filter_glossy_sh) { + lightprobe_shaders_init(); } if (!sldata->probes) { @@ -275,21 +308,15 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda } int prop_bounce_num = BKE_collection_engine_property_value_get_int(props, "gi_diffuse_bounces"); - /* Update all probes if number of bounces mismatch. */ if (sldata->probes->num_bounce != prop_bounce_num) { - e_data.update_world |= PROBE_UPDATE_ALL; - sldata->probes->updated_bounce = 0; - sldata->probes->grid_initialized = false; + sldata->probes->num_bounce = prop_bounce_num; + update_all = true; } - sldata->probes->num_bounce = prop_bounce_num; int prop_cubemap_res = BKE_collection_engine_property_value_get_int(props, "gi_cubemap_resolution"); if (sldata->probes->cubemap_res != prop_cubemap_res) { sldata->probes->cubemap_res = prop_cubemap_res; - - e_data.update_world |= PROBE_UPDATE_ALL; - sldata->probes->updated_bounce = 0; - sldata->probes->grid_initialized = false; + update_all = true; sldata->probes->target_size = prop_cubemap_res >> 1; @@ -297,25 +324,27 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); } - /* Setup Render Target Cubemap */ - - /* We do this detach / attach dance to not generate an invalid framebuffer (mixed cubemap / 2D map) */ - if (sldata->probe_rt) { - /* XXX Silly,TODO Cleanup this mess */ - DRW_framebuffer_texture_detach(sldata->probe_rt); + int visibility_res = BKE_collection_engine_property_value_get_int(props, "gi_visibility_resolution"); + if (sldata->probes->irradiance_vis_size != visibility_res) { + sldata->probes->irradiance_vis_size = visibility_res; + update_all = true; } - DRWFboTexture tex_probe = {&e_data.cube_face_depth, DRW_TEX_DEPTH_24, DRW_TEX_TEMP}; - DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, sldata->probes->target_size, sldata->probes->target_size, &tex_probe, 1); + if (update_all) { + e_data.update_world |= PROBE_UPDATE_ALL; + sldata->probes->updated_bounce = 0; + sldata->probes->grid_initialized = false; + } + /* Setup Render Target Cubemap */ if (!sldata->probe_rt) { + sldata->probe_depth_rt = DRW_texture_create_cube(sldata->probes->target_size, DRW_TEX_DEPTH_24, 0, NULL); sldata->probe_rt = DRW_texture_create_cube(sldata->probes->target_size, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); } - if (sldata->probe_rt) { - /* XXX Silly,TODO Cleanup this mess */ - DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0); - } + DRWFboTexture tex_probe[2] = {{&sldata->probe_depth_rt, DRW_TEX_DEPTH_24, 0}, + {&sldata->probe_rt, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}}; + DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, sldata->probes->target_size, sldata->probes->target_size, tex_probe, 2); /* Minmaxz Pyramid */ // DRWFboTexture tex_minmaxz = {&e_data.cube_face_minmaxz, DRW_TEX_RG_32, DRW_TEX_MIPMAP | DRW_TEX_TEMP}; @@ -344,6 +373,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat pinfo->num_cube = 1; /* at least one for the world */ pinfo->num_grid = 1; pinfo->num_planar = 0; + pinfo->total_irradiance_samples = 1; memset(pinfo->probes_cube_ref, 0, sizeof(pinfo->probes_cube_ref)); memset(pinfo->probes_grid_ref, 0, sizeof(pinfo->probes_grid_ref)); memset(pinfo->probes_planar_ref, 0, sizeof(pinfo->probes_planar_ref)); @@ -435,10 +465,29 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat } { + psl->probe_visibility_compute = DRW_pass_create("LightProbe Visibility Compute", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_visibility_sh, psl->probe_visibility_compute); + DRW_shgroup_uniform_int(grp, "outputSize", &sldata->probes->shres, 1); + DRW_shgroup_uniform_float(grp, "visibilityRange", &sldata->probes->visibility_range, 1); + DRW_shgroup_uniform_float(grp, "visibilityBlur", &sldata->probes->visibility_blur, 1); + DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1); + DRW_shgroup_uniform_float(grp, "storedTexelSize", &sldata->probes->texel_size, 1); + DRW_shgroup_uniform_float(grp, "nearClip", &sldata->probes->near_clip, 1); + DRW_shgroup_uniform_float(grp, "farClip", &sldata->probes->far_clip, 1); + DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); + DRW_shgroup_uniform_texture(grp, "probeDepth", sldata->probe_depth_rt); + + struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); + DRW_shgroup_call_add(grp, geom, NULL); + } + + { psl->probe_grid_fill = DRW_pass_create("LightProbe Grid Floodfill", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_grid_fill_sh, psl->probe_grid_fill); - DRW_shgroup_uniform_buffer(grp, "gridTexture", &sldata->irradiance_pool); + DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool); struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); DRW_shgroup_call_add(grp, geom, NULL); @@ -486,11 +535,20 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) return; } - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob); + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); ped->num_cell = probe->grid_resolution_x * probe->grid_resolution_y * probe->grid_resolution_z; - if ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0) { + if ((probe->type == LIGHTPROBE_TYPE_GRID) && + ((pinfo->total_irradiance_samples + ped->num_cell) >= MAX_IRRADIANCE_SAMPLES)) + { + printf("Too much grid samples !!!\n"); + return; + } + + if (ped->need_full_update) { + ped->need_full_update = false; + ped->need_update = true; ped->probe_id = 0; @@ -520,6 +578,7 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) else { /* GRID */ pinfo->probes_grid_ref[pinfo->num_grid] = ob; pinfo->num_grid++; + pinfo->total_irradiance_samples += ped->num_cell; } } @@ -549,7 +608,7 @@ static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata, EEVEE_ for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) { LightProbe *probe = (LightProbe *)ob->data; EEVEE_PlanarReflection *eplanar = &pinfo->planar_data[i]; - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob); + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); /* Computing mtx : matrix that mirror position around object's XY plane. */ normalize_m4_m4(normat, ob->obmat); /* object > world */ @@ -644,7 +703,7 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) { LightProbe *probe = (LightProbe *)ob->data; EEVEE_LightProbe *eprobe = &pinfo->probe_data[i]; - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob); + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); /* Update transforms */ copy_v3_v3(eprobe->position, ob->obmat[3]); @@ -690,7 +749,14 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) { LightProbe *probe = (LightProbe *)ob->data; EEVEE_LightGrid *egrid = &pinfo->grid_data[i]; - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob); + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); + + /* If one grid has move we need to recompute all the lighting. */ + if (!pinfo->grid_initialized) { + ped->updated_cells = 0; + ped->updated_lvl = 0; + ped->need_update = true; + } /* Add one for level 0 */ ped->max_lvl = 1.0f + floorf(log2f((float)MAX3(probe->grid_resolution_x, @@ -742,6 +808,13 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis copy_v3_v3_int(egrid->resolution, &probe->grid_resolution_x); + /* Visibility bias */ + egrid->visibility_bias = 0.05f * probe->vis_bias; + egrid->visibility_bleed = probe->vis_bleedbias; + egrid->visibility_range = max_ff(max_ff(len_v3(egrid->increment_x), + len_v3(egrid->increment_y)), + len_v3(egrid->increment_z)) + 1.0f; + /* Debug Display */ if (BKE_object_is_visible(ob) && DRW_state_draw_support() && @@ -780,6 +853,18 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved pinfo->cache_num_planar = pinfo->num_planar; } + int irr_size[3]; + irradiance_pool_size_get(pinfo->irradiance_vis_size, pinfo->total_irradiance_samples, irr_size); + + if ((irr_size[0] != pinfo->cache_irradiance_size[0]) || + (irr_size[1] != pinfo->cache_irradiance_size[1]) || + (irr_size[2] != pinfo->cache_irradiance_size[2])) + { + DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool); + DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt); + copy_v3_v3_int(pinfo->cache_irradiance_size, irr_size); + } + /* XXX this should be run each frame as it ensure planar_depth is set */ planar_pool_ensure_alloc(vedata, pinfo->num_planar); @@ -800,7 +885,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved pinfo->cache_num_cube = pinfo->num_cube; for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) { - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob); + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); ped->need_update = true; ped->ready_to_shade = false; ped->probe_id = 0; @@ -816,16 +901,17 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved /* we need a signed format for Spherical Harmonics */ int irradiance_format = DRW_TEX_RGBA_16; #else - int irradiance_format = DRW_TEX_RGB_11_11_10; + int irradiance_format = DRW_TEX_RGBA_8; #endif - /* TODO Allocate bigger storage if needed. */ if (!sldata->irradiance_pool || !sldata->irradiance_rt) { if (!sldata->irradiance_pool) { - sldata->irradiance_pool = DRW_texture_create_2D(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, irradiance_format, DRW_TEX_FILTER, NULL); + sldata->irradiance_pool = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2], + irradiance_format, DRW_TEX_FILTER, NULL); } if (!sldata->irradiance_rt) { - sldata->irradiance_rt = DRW_texture_create_2D(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, irradiance_format, DRW_TEX_FILTER, NULL); + sldata->irradiance_rt = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2], + irradiance_format, DRW_TEX_FILTER, NULL); } pinfo->num_render_grid = 0; pinfo->updated_bounce = 0; @@ -833,7 +919,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved e_data.update_world |= PROBE_UPDATE_GRID; for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_PROBE); i++) { - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob); + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); ped->need_update = true; ped->updated_cells = 0; } @@ -944,10 +1030,15 @@ static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, } /* Diffuse filter probe_rt to irradiance_pool at index probe_idx */ -static void diffuse_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int offset) +static void diffuse_filter_probe( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int offset, + float clipsta, float clipend, float vis_range, float vis_blur) { EEVEE_LightProbesInfo *pinfo = sldata->probes; + int pool_size[3]; + irradiance_pool_size_get(pinfo->irradiance_vis_size, pinfo->total_irradiance_samples, pool_size); + /* find cell position on the virtual 3D texture */ /* NOTE : Keep in sync with load_irradiance_cell() */ #if defined(IRRADIANCE_SH_L2) @@ -960,7 +1051,7 @@ static void diffuse_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata pinfo->samples_ct = 1024.0f; #endif - int cell_per_row = IRRADIANCE_POOL_SIZE / size[0]; + int cell_per_row = pool_size[0] / size[0]; int x = size[0] * (offset % cell_per_row); int y = size[1] * (offset / cell_per_row); @@ -980,11 +1071,36 @@ static void diffuse_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata EEVEE_downsample_cube_buffer(vedata, sldata->probe_filter_fb, sldata->probe_rt, (int)(pinfo->lod_rt_max)); DRW_framebuffer_texture_detach(sldata->probe_pool); - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); + DRW_framebuffer_texture_layer_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0, 0); DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, size[0], size[1]); DRW_draw_pass(psl->probe_diffuse_compute); + /* World irradiance have no visibility */ + if (offset > 0) { + /* Compute visibility */ + pinfo->samples_ct = 512.0f; /* TODO refine */ + pinfo->invsamples_ct = 1.0f / pinfo->samples_ct; + pinfo->shres = pinfo->irradiance_vis_size; + pinfo->visibility_range = vis_range; + pinfo->visibility_blur = vis_blur; + pinfo->near_clip = -clipsta; + pinfo->far_clip = -clipend; + pinfo->texel_size = 1.0f / (float)pinfo->irradiance_vis_size; + + int cell_per_col = pool_size[1] / pinfo->irradiance_vis_size; + cell_per_row = pool_size[0] / pinfo->irradiance_vis_size; + x = pinfo->irradiance_vis_size * (offset % cell_per_row); + y = pinfo->irradiance_vis_size * ((offset / cell_per_row) % cell_per_col); + int layer = 1 + ((offset / cell_per_row) / cell_per_col); + + DRW_framebuffer_texture_detach(sldata->irradiance_rt); + DRW_framebuffer_texture_layer_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, layer, 0); + + DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, pinfo->irradiance_vis_size, sldata->probes->irradiance_vis_size); + DRW_draw_pass(psl->probe_visibility_compute); + } + /* reattach to have a valid framebuffer. */ DRW_framebuffer_texture_detach(sldata->irradiance_rt); DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); @@ -1035,8 +1151,8 @@ static void render_scene_to_probe( /* Detach to rebind the right cubeface. */ DRW_framebuffer_bind(sldata->probe_fb); - DRW_framebuffer_texture_attach(sldata->probe_fb, e_data.cube_face_depth, 0, 0); DRW_framebuffer_texture_detach(sldata->probe_rt); + DRW_framebuffer_texture_detach(sldata->probe_depth_rt); for (int i = 0; i < 6; ++i) { float viewmat[4][4], persmat[4][4]; float viewinv[4][4], persinv[4][4]; @@ -1059,6 +1175,7 @@ static void render_scene_to_probe( EEVEE_draw_shadows(sldata, psl); DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_rt, 0, i, 0); + DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, i, 0); DRW_framebuffer_viewport_size(sldata->probe_fb, 0, 0, pinfo->target_size, pinfo->target_size); DRW_framebuffer_clear(false, true, false, NULL, 1.0); @@ -1069,7 +1186,7 @@ static void render_scene_to_probe( DRW_draw_pass(psl->probe_background); - // EEVEE_create_minmax_buffer(vedata, e_data.cube_face_depth); + // EEVEE_create_minmax_buffer(vedata, sldata->probe_depth_rt); /* Rebind Planar FB */ DRW_framebuffer_bind(sldata->probe_fb); @@ -1080,9 +1197,10 @@ static void render_scene_to_probe( DRW_draw_pass(psl->sss_pass); /* Only output standard pass */ DRW_framebuffer_texture_detach(sldata->probe_rt); + DRW_framebuffer_texture_detach(sldata->probe_depth_rt); } DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0); - DRW_framebuffer_texture_detach(e_data.cube_face_depth); + DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, 0); DRW_viewport_matrix_override_unset(DRW_MAT_PERS); DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV); @@ -1203,6 +1321,7 @@ static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *p /* Detach to rebind the right cubeface. */ DRW_framebuffer_bind(sldata->probe_fb); DRW_framebuffer_texture_detach(sldata->probe_rt); + DRW_framebuffer_texture_detach(sldata->probe_depth_rt); for (int i = 0; i < 6; ++i) { float viewmat[4][4], persmat[4][4]; float viewinv[4][4], persinv[4][4]; @@ -1228,6 +1347,7 @@ static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *p DRW_framebuffer_texture_detach(sldata->probe_rt); } DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0); + DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, 0); DRW_viewport_matrix_override_unset(DRW_MAT_PERS); DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV); @@ -1258,262 +1378,275 @@ static void lightprobe_cell_world_location_get(EEVEE_LightGrid *egrid, float loc add_v3_v3(r_pos, tmp); } -void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { - EEVEE_TextureList *txl = vedata->txl; EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; - Object *ob; - const DRWContextState *draw_ctx = DRW_context_state_get(); - RegionView3D *rv3d = draw_ctx->rv3d; - - /* Render world in priority */ - if (e_data.update_world) { - render_world_to_probe(sldata, psl); - - if (e_data.update_world & PROBE_UPDATE_CUBE) { - glossy_filter_probe(sldata, vedata, psl, 0); - } - - if (e_data.update_world & PROBE_UPDATE_GRID) { - diffuse_filter_probe(sldata, vedata, psl, 0); - - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); - - DRW_framebuffer_texture_detach(sldata->probe_pool); + render_world_to_probe(sldata, psl); + if (e_data.update_world & PROBE_UPDATE_CUBE) { + glossy_filter_probe(sldata, vedata, psl, 0); + } + if (e_data.update_world & PROBE_UPDATE_GRID) { + diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0); + SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); + DRW_framebuffer_texture_detach(sldata->probe_pool); + DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); + DRW_draw_pass(psl->probe_grid_fill); + DRW_framebuffer_texture_detach(sldata->irradiance_rt); + DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); + } + e_data.update_world = 0; + if (!e_data.world_ready_to_shade) { + e_data.world_ready_to_shade = true; + pinfo->num_render_cube = 1; + pinfo->num_render_grid = 1; + } + DRW_viewport_request_redraw(); +} - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); - DRW_draw_pass(psl->probe_grid_fill); - DRW_framebuffer_texture_detach(sldata->irradiance_rt); +static void lightprobes_refresh_initialize_grid(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_LightProbesInfo *pinfo = sldata->probes; + EEVEE_PassList *psl = vedata->psl; + if (pinfo->grid_initialized) { + /* Grid is already initialized, nothing to do. */ + return; + } + DRW_framebuffer_texture_detach(sldata->probe_pool); + /* Flood fill with world irradiance. */ + DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); + DRW_framebuffer_bind(sldata->probe_filter_fb); + DRW_draw_pass(psl->probe_grid_fill); + DRW_framebuffer_texture_detach(sldata->irradiance_rt); - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); - } + SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); + DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); + DRW_draw_pass(psl->probe_grid_fill); - e_data.update_world = 0; + DRW_framebuffer_texture_detach(sldata->irradiance_rt); + SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); + /* Reattach to have a valid framebuffer. */ + DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); + pinfo->grid_initialized = true; +} - if (!e_data.world_ready_to_shade) { - e_data.world_ready_to_shade = true; - pinfo->num_render_cube = 1; - pinfo->num_render_grid = 1; +static void lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_TextureList *txl = vedata->txl; + Object *ob; + EEVEE_LightProbesInfo *pinfo = sldata->probes; + for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) { + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); + if (!ped->need_update) { + continue; } - - DRW_viewport_request_redraw(); + /* Temporary Remove all planar reflections (avoid lag effect). */ + int tmp_num_planar = pinfo->num_planar; + pinfo->num_planar = 0; + render_scene_to_planar(sldata, vedata, i, ped->viewmat, ped->persmat, ped->planer_eq_offset); + /* Restore */ + pinfo->num_planar = tmp_num_planar; + ped->need_update = false; + ped->probe_id = i; } - else if (true) { /* TODO if at least one probe needs refresh */ + /* If there is at least one planar probe */ + if (pinfo->num_planar > 0 && (vedata->stl->effects->enabled_effects & EFFECT_SSR) != 0) { + const int max_lod = 9; + DRW_stats_group_start("Planar Probe Downsample"); + DRW_framebuffer_recursive_downsample(vedata->fbl->downsample_fb, txl->planar_pool, max_lod, &downsample_planar, vedata); + /* For shading, save max level of the planar map */ + pinfo->lod_planar_max = (float)(max_lod); + DRW_stats_group_end(); + } +} - if (draw_ctx->evil_C != NULL) { - /* Only compute probes if not navigating or in playback */ - struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); - if (((rv3d->rflag & RV3D_NAVIGATING) != 0) || ED_screen_animation_no_scrub(wm) != NULL) { - goto update_planar; - } +static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_LightProbesInfo *pinfo = sldata->probes; + Object *ob; + for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) { + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); + if (!ped->need_update) { + continue; } - - if (!pinfo->grid_initialized) { - DRW_framebuffer_texture_detach(sldata->probe_pool); - - /* Flood fill with world irradiance. */ - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); - DRW_draw_pass(psl->probe_grid_fill); - DRW_framebuffer_texture_detach(sldata->irradiance_rt); - - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); - - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); - DRW_draw_pass(psl->probe_grid_fill); - DRW_framebuffer_texture_detach(sldata->irradiance_rt); - - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); - - /* reattach to have a valid framebuffer. */ - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); - - pinfo->grid_initialized = true; + LightProbe *prb = (LightProbe *)ob->data; + render_scene_to_probe(sldata, vedata, ob->obmat[3], prb->clipsta, prb->clipend); + glossy_filter_probe(sldata, vedata, psl, i); + ped->need_update = false; + ped->probe_id = i; + if (!ped->ready_to_shade) { + pinfo->num_render_cube++; + ped->ready_to_shade = true; } - - /* Reflection probes depend on diffuse lighting thus on irradiance grid, - * so update them first. */ - while (pinfo->updated_bounce < pinfo->num_bounce) { - pinfo->num_render_grid = pinfo->num_grid; - - for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) { - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob); - - if (ped->need_update) { - EEVEE_LightGrid *egrid = &pinfo->grid_data[i]; - LightProbe *prb = (LightProbe *)ob->data; - - /* Find the next cell corresponding to the current level. */ - bool valid_cell = false; - int cell_id = ped->updated_cells; - float pos[3], grid_loc[3]; - - /* Other levels */ - int current_stride = 1 << max_ii(0, ped->max_lvl - ped->updated_lvl); - int prev_stride = current_stride << 1; - - while (!valid_cell) { - cell_id = ped->updated_cells; - lightprobe_cell_grid_location_get(egrid, cell_id, grid_loc); - - if (ped->updated_lvl == 0 && cell_id == 0) { - valid_cell = true; - ped->updated_cells = ped->num_cell; - continue; - } - else if (((((int)grid_loc[0] % current_stride) == 0) && - (((int)grid_loc[1] % current_stride) == 0) && - (((int)grid_loc[2] % current_stride) == 0)) && - !((((int)grid_loc[0] % prev_stride) == 0) && - (((int)grid_loc[1] % prev_stride) == 0) && - (((int)grid_loc[2] % prev_stride) == 0))) - { - valid_cell = true; - } - - ped->updated_cells++; - - if (ped->updated_cells > ped->num_cell) { - goto skip_rendering; - } - } - - lightprobe_cell_world_location_get(egrid, grid_loc, pos); - - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); - - /* Temporary Remove all probes. */ - int tmp_num_render_grid = pinfo->num_render_grid; - int tmp_num_render_cube = pinfo->num_render_cube; - int tmp_num_planar = pinfo->num_planar; - pinfo->num_render_cube = 0; - pinfo->num_planar = 0; - - /* Use light from previous bounce when capturing radiance. */ - if (pinfo->updated_bounce == 0) { - pinfo->num_render_grid = 0; - } - - render_scene_to_probe(sldata, vedata, pos, prb->clipsta, prb->clipend); - diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id); - - /* To see what is going on. */ - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); - - /* Restore */ - pinfo->num_render_grid = tmp_num_render_grid; - pinfo->num_render_cube = tmp_num_render_cube; - pinfo->num_planar = tmp_num_planar; - -skip_rendering: - - if (ped->updated_cells >= ped->num_cell) { - ped->updated_lvl++; - ped->updated_cells = 0; - - if (ped->updated_lvl > ped->max_lvl) { - ped->need_update = false; - } - - egrid->level_bias = (float)(1 << max_ii(0, ped->max_lvl - ped->updated_lvl + 1)); - DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); - } #if 0 - printf("Updated Grid %d : cell %d / %d, bounce %d / %d\n", - i, ped->updated_cells, ped->num_cell, pinfo->updated_bounce + 1, pinfo->num_bounce); + printf("Update Cubemap %d\n", i); #endif - /* Only do one probe per frame */ - DRW_viewport_request_redraw(); - /* Do not let this frame accumulate. */ - stl->effects->taa_current_sample = 1; + DRW_viewport_request_redraw(); + /* Do not let this frame accumulate. */ + stl->effects->taa_current_sample = 1; - goto update_planar; - } - } + /* Only do one probe per frame */ + lightprobes_refresh_planar(sldata, vedata); + return; + } +} - pinfo->updated_bounce++; - pinfo->num_render_grid = pinfo->num_grid; +static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_LightProbesInfo *pinfo = sldata->probes; + Object *ob; + const DRWContextState *draw_ctx = DRW_context_state_get(); + RegionView3D *rv3d = draw_ctx->rv3d; - if (pinfo->updated_bounce < pinfo->num_bounce) { - /* Retag all grids to update for next bounce */ - for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) { - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob); - ped->need_update = true; - ped->updated_cells = 0; - ped->updated_lvl = 0; + if (draw_ctx->evil_C != NULL) { + /* Only compute probes if not navigating or in playback */ + struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); + if (((rv3d->rflag & RV3D_NAVIGATING) != 0) || ED_screen_animation_no_scrub(wm) != NULL) { + lightprobes_refresh_planar(sldata, vedata); + return; + } + } + /* Make sure grid is initialized. */ + lightprobes_refresh_initialize_grid(sldata, vedata); + /* Reflection probes depend on diffuse lighting thus on irradiance grid, + * so update them first. */ + while (pinfo->updated_bounce < pinfo->num_bounce) { + pinfo->num_render_grid = pinfo->num_grid; + /* TODO(sergey): This logic can be split into smaller functions. */ + for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) { + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); + if (!ped->need_update) { + continue; + } + EEVEE_LightGrid *egrid = &pinfo->grid_data[i]; + LightProbe *prb = (LightProbe *)ob->data; + /* Find the next cell corresponding to the current level. */ + bool valid_cell = false; + int cell_id = ped->updated_cells; + float pos[3], grid_loc[3]; + /* Other levels */ + int current_stride = 1 << max_ii(0, ped->max_lvl - ped->updated_lvl); + int prev_stride = current_stride << 1; + bool do_rendering = true; + while (!valid_cell) { + cell_id = ped->updated_cells; + lightprobe_cell_grid_location_get(egrid, cell_id, grid_loc); + if (ped->updated_lvl == 0 && cell_id == 0) { + valid_cell = true; + ped->updated_cells = ped->num_cell; + continue; + } + else if (((((int)grid_loc[0] % current_stride) == 0) && + (((int)grid_loc[1] % current_stride) == 0) && + (((int)grid_loc[2] % current_stride) == 0)) && + !((((int)grid_loc[0] % prev_stride) == 0) && + (((int)grid_loc[1] % prev_stride) == 0) && + (((int)grid_loc[2] % prev_stride) == 0))) + { + valid_cell = true; + } + ped->updated_cells++; + if (ped->updated_cells > ped->num_cell) { + do_rendering = false; + break; } - - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); - - /* Reset the next buffer so we can see the progress. */ - DRW_framebuffer_texture_detach(sldata->probe_pool); - - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); - DRW_draw_pass(psl->probe_grid_fill); - DRW_framebuffer_texture_detach(sldata->irradiance_rt); - - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); } - } - - for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) { - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob); - - if (ped->need_update) { - LightProbe *prb = (LightProbe *)ob->data; - - render_scene_to_probe(sldata, vedata, ob->obmat[3], prb->clipsta, prb->clipend); - glossy_filter_probe(sldata, vedata, psl, i); - - ped->need_update = false; - ped->probe_id = i; - - if (!ped->ready_to_shade) { - pinfo->num_render_cube++; - ped->ready_to_shade = true; + if (do_rendering) { + lightprobe_cell_world_location_get(egrid, grid_loc, pos); + SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); + /* Temporary Remove all probes. */ + int tmp_num_render_grid = pinfo->num_render_grid; + int tmp_num_render_cube = pinfo->num_render_cube; + int tmp_num_planar = pinfo->num_planar; + float tmp_level_bias = egrid->level_bias; + pinfo->num_render_cube = 0; + pinfo->num_planar = 0; + /* Use light from previous bounce when capturing radiance. */ + if (pinfo->updated_bounce == 0) { + /* But not on first bounce. */ + pinfo->num_render_grid = 0; + } + else { + /* Remove bias */ + egrid->level_bias = (float)(1 << 0); + DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); + } + render_scene_to_probe(sldata, vedata, pos, prb->clipsta, prb->clipend); + diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id, + prb->clipsta, prb->clipend, egrid->visibility_range, prb->vis_blur); + /* To see what is going on. */ + SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); + /* Restore */ + pinfo->num_render_cube = tmp_num_render_cube; + pinfo->num_planar = tmp_num_planar; + if (pinfo->updated_bounce == 0) { + pinfo->num_render_grid = tmp_num_render_grid; + } + else { + egrid->level_bias = tmp_level_bias; + DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); } #if 0 - printf("Update Cubemap %d\n", i); + printf("Updated Grid %d : cell %d / %d, bounce %d / %d\n", + i, cell_id + 1, ped->num_cell, pinfo->updated_bounce + 1, pinfo->num_bounce); #endif - DRW_viewport_request_redraw(); - /* Do not let this frame accumulate. */ - stl->effects->taa_current_sample = 1; - - /* Only do one probe per frame */ - goto update_planar; } + if (ped->updated_cells >= ped->num_cell) { + ped->updated_lvl++; + ped->updated_cells = 0; + if (ped->updated_lvl > ped->max_lvl) { + ped->need_update = false; + } + egrid->level_bias = (float)(1 << max_ii(0, ped->max_lvl - ped->updated_lvl + 1)); + DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); + } + /* Only do one probe per frame */ + DRW_viewport_request_redraw(); + /* Do not let this frame accumulate. */ + stl->effects->taa_current_sample = 1; + lightprobes_refresh_planar(sldata, vedata); + return; } - } - -update_planar: - - for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) { - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob); - - if (ped->need_update) { - /* Temporary Remove all planar reflections (avoid lag effect). */ - int tmp_num_planar = pinfo->num_planar; - pinfo->num_planar = 0; - - render_scene_to_planar(sldata, vedata, i, ped->viewmat, ped->persmat, ped->planer_eq_offset); - /* Restore */ - pinfo->num_planar = tmp_num_planar; + pinfo->updated_bounce++; + pinfo->num_render_grid = pinfo->num_grid; - ped->need_update = false; - ped->probe_id = i; + if (pinfo->updated_bounce < pinfo->num_bounce) { + /* Retag all grids to update for next bounce */ + for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) { + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); + ped->need_update = true; + ped->updated_cells = 0; + ped->updated_lvl = 0; + } + /* Reset the next buffer so we can see the progress. */ + /* irradiance_rt is already the next rt because of the previous SWAP */ + DRW_framebuffer_texture_detach(sldata->probe_pool); + DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); + DRW_framebuffer_bind(sldata->probe_filter_fb); + DRW_draw_pass(psl->probe_grid_fill); + DRW_framebuffer_texture_detach(sldata->irradiance_rt); + DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); + /* Swap AFTER */ + SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); } } + /* Refresh cube probe when needed. */ + lightprobes_refresh_cube(sldata, vedata); +} - /* If there is at least one planar probe */ - if (pinfo->num_planar > 0 && (vedata->stl->effects->enabled_effects & EFFECT_SSR) != 0) { - const int max_lod = 9; - DRW_stats_group_start("Planar Probe Downsample"); - DRW_framebuffer_recursive_downsample(vedata->fbl->downsample_fb, txl->planar_pool, max_lod, &downsample_planar, vedata); - /* For shading, save max level of the planar map */ - pinfo->lod_planar_max = (float)(max_lod); - DRW_stats_group_end(); +void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + /* Render world in priority */ + if (e_data.update_world) { + lightprobes_refresh_world(sldata, vedata); + } + else if (true) { /* TODO if at least one probe needs refresh */ + lightprobes_refresh_all_no_world(sldata, vedata); } } @@ -1522,6 +1655,7 @@ void EEVEE_lightprobes_free(void) DRW_SHADER_FREE_SAFE(e_data.probe_default_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh); + DRW_SHADER_FREE_SAFE(e_data.probe_filter_visibility_sh); DRW_SHADER_FREE_SAFE(e_data.probe_grid_fill_sh); DRW_SHADER_FREE_SAFE(e_data.probe_grid_display_sh); DRW_SHADER_FREE_SAFE(e_data.probe_planar_display_sh); diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 2293b4208ad..22465c04cfa 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -255,11 +255,7 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) } else { Lamp *la = (Lamp *)ob->data; - EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob); - - if ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0) { - led->need_update = true; - } + EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); MEM_SAFE_FREE(led->storage); @@ -834,7 +830,7 @@ static void delete_pruned_shadowcaster(EEVEE_LampEngineData *led) static void light_tag_shadow_update(Object *lamp, Object *ob) { Lamp *la = lamp->data; - EEVEE_LampEngineData *led = EEVEE_lamp_data_get(lamp); + EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(lamp); bool is_inside_range = cube_bbox_intersect(lamp->obmat[3], la->clipend, BKE_object_boundbox_get(ob), ob->obmat); ShadowCaster *ldata = search_object_in_list(&led->shadow_caster_list, ob); @@ -848,7 +844,7 @@ static void light_tag_shadow_update(Object *lamp, Object *ob) led->need_update = true; } else { - EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(ob); + EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob); if (oedata->need_update) { led->need_update = true; } @@ -872,6 +868,8 @@ static void eevee_lights_shcaster_updated(EEVEE_ViewLayerData *sldata, Object *o for (int i = 0; (lamp = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) { light_tag_shadow_update(lamp, ob); } + EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob); + oedata->need_update = false; } void EEVEE_lights_update(EEVEE_ViewLayerData *sldata) @@ -883,7 +881,7 @@ void EEVEE_lights_update(EEVEE_ViewLayerData *sldata) /* Prune shadow casters to remove if object does not exists anymore (unprune them if object exists) */ Object *lamp; for (i = 0; (lamp = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) { - EEVEE_LampEngineData *led = EEVEE_lamp_data_get(lamp); + EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(lamp); if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) { led->need_update = true; @@ -899,12 +897,12 @@ void EEVEE_lights_update(EEVEE_ViewLayerData *sldata) } for (i = 0; (ob = linfo->light_ref[i]) && (i < MAX_LIGHT); i++) { - EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob); + EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); eevee_light_setup(ob, linfo, led); } for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) { - EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob); + EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); eevee_shadow_cube_setup(ob, linfo, led); delete_pruned_shadowcaster(led); } @@ -923,80 +921,82 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) DRW_framebuffer_texture_attach(sldata->shadow_target_fb, sldata->shadow_cube_target, 0, 0); /* Render each shadow to one layer of the array */ for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) { - EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob); + EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); Lamp *la = (Lamp *)ob->data; float cube_projmat[4][4]; perspective_m4(cube_projmat, -la->clipsta, la->clipsta, -la->clipsta, la->clipsta, la->clipsta, la->clipend); - if (led->need_update) { - EEVEE_ShadowRender *srd = &linfo->shadow_render_data; - EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->storage; + if (!led->need_update) { + continue; + } - srd->clip_near = la->clipsta; - srd->clip_far = la->clipend; - copy_v3_v3(srd->position, ob->obmat[3]); - for (int j = 0; j < 6; j++) { - float tmp[4][4]; + EEVEE_ShadowRender *srd = &linfo->shadow_render_data; + EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->storage; - unit_m4(tmp); - negate_v3_v3(tmp[3], ob->obmat[3]); - mul_m4_m4m4(srd->viewmat[j], cubefacemat[j], tmp); + srd->clip_near = la->clipsta; + srd->clip_far = la->clipend; + copy_v3_v3(srd->position, ob->obmat[3]); + for (int j = 0; j < 6; j++) { + float tmp[4][4]; - mul_m4_m4m4(srd->shadowmat[j], cube_projmat, srd->viewmat[j]); - } - DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); - - DRW_framebuffer_bind(sldata->shadow_target_fb); - DRW_framebuffer_clear(true, true, false, clear_col, 1.0f); - - /* Render shadow cube */ - DRW_draw_pass(psl->shadow_cube_pass); - - /* 0.001f is arbitrary, but it should be relatively small so that filter size is not too big. */ - float filter_texture_size = la->soft * 0.001f; - float filter_pixel_size = ceil(filter_texture_size / linfo->shadow_render_data.cube_texel_size); - linfo->filter_size = linfo->shadow_render_data.cube_texel_size * ((filter_pixel_size > 1.0f) ? 1.5f : 0.0f); - - /* TODO: OPTI: Filter all faces in one/two draw call */ - for (linfo->current_shadow_face = 0; - linfo->current_shadow_face < 6; - linfo->current_shadow_face++) - { - /* Copy using a small 3x3 box filter */ - DRW_framebuffer_cubeface_attach(sldata->shadow_store_fb, sldata->shadow_cube_blur, 0, linfo->current_shadow_face, 0); - DRW_framebuffer_bind(sldata->shadow_store_fb); - DRW_draw_pass(psl->shadow_cube_copy_pass); - DRW_framebuffer_texture_detach(sldata->shadow_cube_blur); - } + unit_m4(tmp); + negate_v3_v3(tmp[3], ob->obmat[3]); + mul_m4_m4m4(srd->viewmat[j], cubefacemat[j], tmp); - /* Push it to shadowmap array */ + mul_m4_m4m4(srd->shadowmat[j], cube_projmat, srd->viewmat[j]); + } + DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); - /* Adjust constants if concentric samples change. */ - const float max_filter_size = 7.5f; - const float previous_box_filter_size = 9.0f; /* Dunno why but that works. */ - const int max_sample = 256; + DRW_framebuffer_bind(sldata->shadow_target_fb); + DRW_framebuffer_clear(true, true, false, clear_col, 1.0f); - if (filter_pixel_size > 2.0f) { - linfo->filter_size = linfo->shadow_render_data.cube_texel_size * max_filter_size * previous_box_filter_size; - filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f); - /* Compute number of concentric samples. Depends directly on filter size. */ - float pix_size_sqr = filter_pixel_size * filter_pixel_size; - srd->shadow_samples_ct = min_ii(max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr)); - } - else { - linfo->filter_size = 0.0f; - srd->shadow_samples_ct = 4; - } - srd->shadow_inv_samples_ct = 1.0f / (float)srd->shadow_samples_ct; - DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); + /* Render shadow cube */ + DRW_draw_pass(psl->shadow_cube_pass); - DRW_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_pool, 0, evscd->layer_id, 0); + /* 0.001f is arbitrary, but it should be relatively small so that filter size is not too big. */ + float filter_texture_size = la->soft * 0.001f; + float filter_pixel_size = ceil(filter_texture_size / linfo->shadow_render_data.cube_texel_size); + linfo->filter_size = linfo->shadow_render_data.cube_texel_size * ((filter_pixel_size > 1.0f) ? 1.5f : 0.0f); + + /* TODO: OPTI: Filter all faces in one/two draw call */ + for (linfo->current_shadow_face = 0; + linfo->current_shadow_face < 6; + linfo->current_shadow_face++) + { + /* Copy using a small 3x3 box filter */ + DRW_framebuffer_cubeface_attach(sldata->shadow_store_fb, sldata->shadow_cube_blur, 0, linfo->current_shadow_face, 0); DRW_framebuffer_bind(sldata->shadow_store_fb); - DRW_draw_pass(psl->shadow_cube_store_pass); + DRW_draw_pass(psl->shadow_cube_copy_pass); + DRW_framebuffer_texture_detach(sldata->shadow_cube_blur); + } + + /* Push it to shadowmap array */ + + /* Adjust constants if concentric samples change. */ + const float max_filter_size = 7.5f; + const float previous_box_filter_size = 9.0f; /* Dunno why but that works. */ + const int max_sample = 256; - led->need_update = false; + if (filter_pixel_size > 2.0f) { + linfo->filter_size = linfo->shadow_render_data.cube_texel_size * max_filter_size * previous_box_filter_size; + filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f); + /* Compute number of concentric samples. Depends directly on filter size. */ + float pix_size_sqr = filter_pixel_size * filter_pixel_size; + srd->shadow_samples_ct = min_ii(max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr)); } + else { + linfo->filter_size = 0.0f; + srd->shadow_samples_ct = 4; + } + srd->shadow_inv_samples_ct = 1.0f / (float)srd->shadow_samples_ct; + DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); + + DRW_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_pool, 0, evscd->layer_id, 0); + DRW_framebuffer_bind(sldata->shadow_store_fb); + DRW_draw_pass(psl->shadow_cube_store_pass); + + led->need_update = false; } linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE; @@ -1007,7 +1007,7 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) DRW_stats_group_start("Cascaded Shadow Maps"); DRW_framebuffer_texture_attach(sldata->shadow_target_fb, sldata->shadow_cascade_target, 0, 0); for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) { - EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob); + EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); Lamp *la = (Lamp *)ob->data; EEVEE_ShadowCascadeData *evscd = (EEVEE_ShadowCascadeData *)led->storage; diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 38f2aab4443..c25ab1e7859 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -374,6 +374,7 @@ static void add_standard_uniforms( DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool); DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool); DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool); + DRW_shgroup_uniform_int(shgrp, "irradianceVisibilitySize", &sldata->probes->irradiance_vis_size, 1); DRW_shgroup_uniform_buffer(shgrp, "shadowTexture", &sldata->shadow_pool); DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1); DRW_shgroup_uniform_vec4(shgrp, "aoParameters[0]", &vedata->stl->effects->ao_dist, 2); @@ -1295,7 +1296,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld /* Do not render surface if we are rendering a volume object * and do not have a surface closure. */ if (use_volume_material && - (gpumat_array[i] && !GPU_material_use_domain_surface(gpumat_array[i]))) + (gpumat_array[i] && !GPU_material_use_domain_surface(gpumat_array[i]))) { continue; } diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index 43aaec1b4ba..d5e0a05f9ed 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -19,7 +19,7 @@ * */ -/** \file eevee_effects.c +/** \file eevee_motion_blur.c * \ingroup draw_engine * * Gather all screen space effects technique such as Bloom, Motion Blur, DoF, SSAO, SSR, ... diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 8e754e71506..98fc6d6a6e4 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -47,11 +47,11 @@ extern struct DrawEngineType draw_engine_eevee_type; #define IRRADIANCE_HL2 #if defined(IRRADIANCE_SH_L2) -#define SHADER_IRRADIANCE "#define IRRADIANCE_SH_L2\n" +# define SHADER_IRRADIANCE "#define IRRADIANCE_SH_L2\n" #elif defined(IRRADIANCE_CUBEMAP) -#define SHADER_IRRADIANCE "#define IRRADIANCE_CUBEMAP\n" +# define SHADER_IRRADIANCE "#define IRRADIANCE_CUBEMAP\n" #elif defined(IRRADIANCE_HL2) -#define SHADER_IRRADIANCE "#define IRRADIANCE_HL2\n" +# define SHADER_IRRADIANCE "#define IRRADIANCE_HL2\n" #endif #define SHADER_DEFINES \ @@ -141,6 +141,7 @@ typedef struct EEVEE_PassList { struct DRWPass *probe_background; struct DRWPass *probe_glossy_compute; struct DRWPass *probe_diffuse_compute; + struct DRWPass *probe_visibility_compute; struct DRWPass *probe_grid_fill; struct DRWPass *probe_display; struct DRWPass *probe_planar_downsample_ps; @@ -369,6 +370,7 @@ typedef struct EEVEE_LightGrid { float increment_x[3], attenuation_bias; /* world space vector between 2 opposite cells */ float increment_y[3], level_bias; float increment_z[3], pad4; + float visibility_bias, visibility_bleed, visibility_range, pad5; } EEVEE_LightGrid; typedef struct EEVEE_PlanarReflection { @@ -386,11 +388,14 @@ typedef struct EEVEE_LightProbesInfo { int num_cube, cache_num_cube; int num_grid, cache_num_grid; int num_planar, cache_num_planar; + int total_irradiance_samples; /* Total for all grids */ + int cache_irradiance_size[3]; int update_flag; int updated_bounce; int num_bounce; int cubemap_res; int target_size; + int irradiance_vis_size; int grid_initialized; /* Actual number of probes that have datas. */ int num_render_cube; @@ -402,9 +407,13 @@ typedef struct EEVEE_LightProbesInfo { float padding_size; float samples_ct; float invsamples_ct; + float near_clip; + float far_clip; float roughness; float lodfactor; float lod_rt_max, lod_cube_max, lod_planar_max; + float visibility_range; + float visibility_blur; int shres; int shnbr; bool specular_toggle; @@ -550,6 +559,7 @@ typedef struct EEVEE_ViewLayerData { struct GPUFrameBuffer *probe_filter_fb; struct GPUTexture *probe_rt; + struct GPUTexture *probe_depth_rt; struct GPUTexture *probe_pool; struct GPUTexture *irradiance_pool; struct GPUTexture *irradiance_rt; @@ -568,7 +578,19 @@ typedef struct EEVEE_LampEngineData { } EEVEE_LampEngineData; typedef struct EEVEE_LightProbeEngineData { + /* NOTE: need_full_update is set by dependency graph when the probe or it's + * object is updated. This triggers full probe update, including it's + * "progressive" GI refresh. + * + * need_update is always set to truth when need_full_update is tagged, but + * might also be forced to be kept truth during GI refresh stages. + * + * TODO(sergey): Is there a way to avoid two flags here, or at least make + * it more clear what's going on here? + */ + bool need_full_update; bool need_update; + bool ready_to_shade; int updated_cells; int updated_lvl; @@ -629,9 +651,13 @@ typedef struct EEVEE_PrivateData { /* eevee_data.c */ EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void); +EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void); EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob); +EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob); EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob); +EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob); EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob); +EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob); /* eevee_materials.c */ struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */ diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index 72b8c85b7a7..5faac4c42cc 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -56,9 +56,9 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); if (BKE_collection_engine_property_value_get_int(props, "taa_samples") != 1 && - /* FIXME the motion blur camera evaluation is tagging view_updated - * thus making the TAA always reset and never stopping rendering. */ - (effects->enabled_effects & EFFECT_MOTION_BLUR) == 0) + /* FIXME the motion blur camera evaluation is tagging view_updated + * thus making the TAA always reset and never stopping rendering. */ + (effects->enabled_effects & EFFECT_MOTION_BLUR) == 0) { const float *viewport_size = DRW_viewport_size_get(); float persmat[4][4], viewmat[4][4]; diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 14383e28cc7..dae4503dc32 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -19,7 +19,7 @@ * */ -/** \file eevee_volume.c +/** \file eevee_volumes.c * \ingroup draw_engine * * Volumetric effects rendering using frostbite approach. @@ -86,8 +86,8 @@ static void eevee_create_shader_volumes(void) ds_frag = BLI_dynstr_new(); BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl); BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl); BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl); BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl); e_data.volumetric_common_lamps_lib = BLI_dynstr_get_cstring(ds_frag); diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index aecb1e6dde4..37ed2235c6f 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -432,6 +432,78 @@ vec3 normal_decode(vec2 enc, vec3 view) return n; } +/* ---- RGBM (shared multiplier) encoding ---- */ +/* From http://iwasbeingirony.blogspot.fr/2010/06/difference-between-rgbm-and-rgbd.html */ + +/* Higher RGBM_MAX_RANGE gives imprecision issues in low intensity. */ +#define RGBM_MAX_RANGE 512.0 + +vec4 rgbm_encode(vec3 rgb) +{ + float maxRGB = max_v3(rgb); + float M = maxRGB / RGBM_MAX_RANGE; + M = ceil(M * 255.0) / 255.0; + return vec4(rgb / (M * RGBM_MAX_RANGE), M); +} + +vec3 rgbm_decode(vec4 data) +{ + return data.rgb * (data.a * RGBM_MAX_RANGE); +} + +/* ---- RGBE (shared exponent) encoding ---- */ +vec4 rgbe_encode(vec3 rgb) +{ + float maxRGB = max_v3(rgb); + float fexp = ceil(log2(maxRGB)); + return vec4(rgb / exp2(fexp), (fexp + 128.0) / 255.0); +} + +vec3 rgbe_decode(vec4 data) +{ + float fexp = data.a * 255.0 - 128.0; + return data.rgb * exp2(fexp); +} + +#if 1 +#define irradiance_encode rgbe_encode +#define irradiance_decode rgbe_decode +#else /* No ecoding (when using floating point format) */ +#define irradiance_encode(X) (X).rgbb +#define irradiance_decode(X) (X).rgb +#endif + +/* Irradiance Visibility Encoding */ +#if 1 +vec4 visibility_encode(vec2 accum, float range) +{ + accum /= range; + + vec4 data; + data.x = fract(accum.x); + data.y = floor(accum.x) / 255.0; + data.z = fract(accum.y); + data.w = floor(accum.y) / 255.0; + + return data; +} + +vec2 visibility_decode(vec4 data, float range) +{ + return (data.xz + data.yw * 255.0) * range; +} +#else /* No ecoding (when using floating point format) */ +vec4 visibility_encode(vec2 accum, float range) +{ + return accum.xyxy; +} + +vec2 visibility_decode(vec4 data, float range) +{ + return data.xy; +} +#endif + /* Fresnel monochromatic, perfect mirror */ float F_eta(float eta, float cos_theta) { diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl index f58dac6c0a0..13586619fe9 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl @@ -54,7 +54,7 @@ vec3 sample_ggx(vec3 rand, float a2) { /* Theta is the aperture angle of the cone */ float z = sqrt( (1.0 - rand.x) / ( 1.0 + a2 * rand.x - rand.x ) ); /* cos theta */ - float r = sqrt( 1.0 - z * z ); /* sin theta */ + float r = sqrt(max(0.0, 1.0f - z*z)); /* sin theta */ float x = r * rand.y; float y = r * rand.z; @@ -82,7 +82,21 @@ vec3 sample_hemisphere(float nsample, vec3 N, vec3 T, vec3 B) vec3 Xi = hammersley_3d(nsample); float z = Xi.x; /* cos theta */ - float r = sqrt( 1.0f - z*z ); /* sin theta */ + float r = sqrt(max(0.0, 1.0f - z*z)); /* sin theta */ + float x = r * Xi.y; + float y = r * Xi.z; + + vec3 Ht = vec3(x, y, z); + + return tangent_to_world(Ht, N, T, B); +} + +vec3 sample_cone(float nsample, float angle, vec3 N, vec3 T, vec3 B) +{ + vec3 Xi = hammersley_3d(nsample); + + float z = cos(angle * Xi.x); /* cos theta */ + float r = sqrt(max(0.0, 1.0f - z*z)); /* sin theta */ float x = r * Xi.y; float y = r * Xi.z; diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl index 91746a6f082..45c5c88e763 100644 --- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl @@ -13,7 +13,7 @@ Closure nodetree_exec(void) vec3 out_diff, out_spec, ssr_spec; eevee_closure_default(N, albedo, f0, 0, roughness, 1.0, out_diff, out_spec, ssr_spec); - Closure result = Closure(out_spec + out_diff, 1.0, vec4(ssr_spec, roughness), normal_encode(normalize(viewNormal), viewCameraVec), 0); + Closure result = Closure(out_spec + out_diff * albedo, 1.0, vec4(ssr_spec, roughness), normal_encode(normalize(viewNormal), viewCameraVec), 0); return result; } diff --git a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl index 95e7af41398..76d20486d3d 100644 --- a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl @@ -1,5 +1,6 @@ -uniform sampler2D irradianceGrid; +uniform sampler2DArray irradianceGrid; +uniform int irradianceVisibilitySize; #define IRRADIANCE_LIB @@ -36,7 +37,7 @@ IrradianceData load_irradiance_cell(int cell, vec3 N) uvs += vec2(cell_co) / vec2(textureSize(irradianceGrid, 0)); IrradianceData ir; - ir.color = texture(irradianceGrid, uvs).rgb; + ir.color = texture(irradianceGrid, vec3(uvs, 0.0)).rgb; #elif defined(IRRADIANCE_SH_L2) @@ -48,15 +49,15 @@ IrradianceData load_irradiance_cell(int cell, vec3 N) ivec3 ofs = ivec3(0, 1, 2); IrradianceData ir; - ir.shcoefs[0] = texelFetch(irradianceGrid, cell_co + ofs.xx, 0).rgb; - ir.shcoefs[1] = texelFetch(irradianceGrid, cell_co + ofs.yx, 0).rgb; - ir.shcoefs[2] = texelFetch(irradianceGrid, cell_co + ofs.zx, 0).rgb; - ir.shcoefs[3] = texelFetch(irradianceGrid, cell_co + ofs.xy, 0).rgb; - ir.shcoefs[4] = texelFetch(irradianceGrid, cell_co + ofs.yy, 0).rgb; - ir.shcoefs[5] = texelFetch(irradianceGrid, cell_co + ofs.zy, 0).rgb; - ir.shcoefs[6] = texelFetch(irradianceGrid, cell_co + ofs.xz, 0).rgb; - ir.shcoefs[7] = texelFetch(irradianceGrid, cell_co + ofs.yz, 0).rgb; - ir.shcoefs[8] = texelFetch(irradianceGrid, cell_co + ofs.zz, 0).rgb; + ir.shcoefs[0] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xx, 0), 0).rgb; + ir.shcoefs[1] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yx, 0), 0).rgb; + ir.shcoefs[2] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zx, 0), 0).rgb; + ir.shcoefs[3] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xy, 0), 0).rgb; + ir.shcoefs[4] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yy, 0), 0).rgb; + ir.shcoefs[5] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zy, 0), 0).rgb; + ir.shcoefs[6] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xz, 0), 0).rgb; + ir.shcoefs[7] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yz, 0), 0).rgb; + ir.shcoefs[8] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zz, 0), 0).rgb; #else /* defined(IRRADIANCE_HL2) */ @@ -68,15 +69,51 @@ IrradianceData load_irradiance_cell(int cell, vec3 N) ivec3 is_negative = ivec3(step(0.0, -N)); IrradianceData ir; - ir.cubesides[0] = texelFetch(irradianceGrid, cell_co + ivec2(0, is_negative.x), 0).rgb; - ir.cubesides[1] = texelFetch(irradianceGrid, cell_co + ivec2(1, is_negative.y), 0).rgb; - ir.cubesides[2] = texelFetch(irradianceGrid, cell_co + ivec2(2, is_negative.z), 0).rgb; + ir.cubesides[0] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(0, is_negative.x), 0), 0)); + ir.cubesides[1] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(1, is_negative.y), 0), 0)); + ir.cubesides[2] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(2, is_negative.z), 0), 0)); #endif return ir; } +float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed_bias, float range) +{ + /* Keep in sync with diffuse_filter_probe() */ + ivec2 cell_co = ivec2(irradianceVisibilitySize); + ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / irradianceVisibilitySize; + cell_co.x *= (cell % cell_per_row_col.x); + cell_co.y *= (cell / cell_per_row_col.x) % cell_per_row_col.y; + float layer = 1.0 + float((cell / cell_per_row_col.x) / cell_per_row_col.y); + + vec2 texel_size = 1.0 / vec2(textureSize(irradianceGrid, 0).xy); + vec2 co = vec2(cell_co) * texel_size; + + vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(irradianceVisibilitySize))); + uv *= vec2(irradianceVisibilitySize) * texel_size; + + vec4 data = texture(irradianceGrid, vec3(co + uv, layer)); + + /* Decoding compressed data */ + vec2 moments = visibility_decode(data, range); + + /* Doing chebishev test */ + float variance = abs(moments.x * moments.x - moments.y); + variance = max(variance, bias / 10.0); + + float d = dist - moments.x; + float p_max = variance / (variance + d * d); + + /* Increase contrast in the weight by squaring it */ + p_max *= p_max; + + /* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */ + p_max = clamp((p_max - bleed_bias) / (1.0 - bleed_bias), 0.0, 1.0); + + return (dist <= moments.x) ? 1.0 : p_max; +} + /* http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ */ vec3 spherical_harmonics_L1(vec3 N, vec3 shcoefs[4]) { diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl index 0b97548c8df..eb4315c93a3 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl @@ -192,6 +192,6 @@ void main() } } - FragColor = vec4(out_radiance / weight, 1.0); + FragColor = irradiance_encode(out_radiance / weight); #endif }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl new file mode 100644 index 00000000000..0727e73f507 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl @@ -0,0 +1,88 @@ + +uniform samplerCube probeDepth; +uniform int outputSize; +uniform float lodFactor; +uniform float storedTexelSize; +uniform float lodMax; +uniform float nearClip; +uniform float farClip; +uniform float visibilityRange; +uniform float visibilityBlur; + +out vec4 FragColor; + +vec3 octahedral_to_cubemap_proj(vec2 co) +{ + co = co * 2.0 - 1.0; + + vec2 abs_co = abs(co); + vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y)); + + if ( abs_co.x + abs_co.y > 1.0 ) { + v.xy = (abs(co.yx) - 1.0) * -sign(co.xy); + } + + return v; +} + +float linear_depth(float z) +{ + return (nearClip * farClip) / (z * (nearClip - farClip) + farClip); +} + +float get_world_distance(float depth, vec3 cos) +{ + float is_background = step(1.0, depth); + depth = linear_depth(depth); + depth += 1e1 * is_background; + cos = normalize(abs(cos)); + float cos_vec = max(cos.x, max(cos.y, cos.z)); + return depth / cos_vec; +} + +void main() +{ + ivec2 texel = ivec2(gl_FragCoord.xy) % ivec2(outputSize); + + vec3 cos; + + cos.xy = (vec2(texel) + 0.5) * storedTexelSize; + + /* add a 2 pixel border to ensure filtering is correct */ + cos.xy *= 1.0 + storedTexelSize * 2.0; + cos.xy -= storedTexelSize; + + float pattern = 1.0; + + /* edge mirroring : only mirror if directly adjacent + * (not diagonally adjacent) */ + vec2 m = abs(cos.xy - 0.5) + 0.5; + vec2 f = floor(m); + if (f.x - f.y != 0.0) { + cos.xy = 1.0 - cos.xy; + } + + /* clamp to [0-1] */ + cos.xy = fract(cos.xy); + + /* get cubemap vector */ + cos = normalize(octahedral_to_cubemap_proj(cos.xy)); + + vec3 T, B; + make_orthonormal_basis(cos, T, B); /* Generate tangent space */ + + vec2 accum = vec2(0.0); + + for (float i = 0; i < sampleCount; i++) { + vec3 sample = sample_cone(i, M_PI_2 * visibilityBlur, cos, T, B); + float depth = texture(probeDepth, sample).r; + depth = get_world_distance(depth, sample); + accum += vec2(depth, depth * depth); + } + + accum *= invSampleCount; + accum = abs(accum); + + /* Encode to normalized RGBA 8 */ + FragColor = visibility_encode(accum, visibilityRange); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl index cea1ca5e7b0..c9e66ceffb2 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl @@ -1,4 +1,4 @@ -uniform sampler2D gridTexture; +uniform sampler2DArray irradianceGrid; out vec4 FragColor; @@ -12,7 +12,7 @@ void main() const ivec2 data_size = ivec2(3, 2); #endif ivec2 coord = ivec2(gl_FragCoord.xy) % data_size; - FragColor = texelFetch(gridTexture, coord, 0); + FragColor = texelFetch(irradianceGrid, ivec3(coord, 0), 0); if (any(greaterThanEqual(ivec2(gl_FragCoord.xy), data_size))) { FragColor = vec4(0.0, 0.0, 0.0, 1.0); diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl index 834bacc118b..e914228aded 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl @@ -49,6 +49,7 @@ struct GridData { vec4 ws_increment_x_atten_bias; /* world space vector between 2 opposite cells */ vec4 ws_increment_y_lvl_bias; vec4 ws_increment_z; + vec4 vis_bias_bleed_range; }; #define g_corner ws_corner_atten_scale.xyz @@ -60,6 +61,9 @@ struct GridData { #define g_increment_z ws_increment_z.xyz #define g_resolution resolution_offset.xyz #define g_offset resolution_offset.w +#define g_vis_bias vis_bias_bleed_range.x +#define g_vis_bleed vis_bias_bleed_range.y +#define g_vis_range vis_bias_bleed_range.z #ifndef MAX_PROBE #define MAX_PROBE 1 @@ -227,14 +231,18 @@ vec3 probe_evaluate_grid(GridData gd, vec3 W, vec3 N, vec3 localpos) gd.g_increment_y * cell_cos.y + gd.g_increment_z * cell_cos.z); - // vec3 ws_point_to_cell = ws_cell_location - W; - // vec3 ws_light = normalize(ws_point_to_cell); + vec3 ws_point_to_cell = ws_cell_location - W; + float ws_dist_point_to_cell = length(ws_point_to_cell); + vec3 ws_light = ws_point_to_cell / ws_dist_point_to_cell; vec3 trilinear = mix(1 - trilinear_weight, trilinear_weight, offset); float weight = trilinear.x * trilinear.y * trilinear.z; + /* Precomputed visibility */ + weight *= load_visibility_cell(cell, ws_light, ws_dist_point_to_cell, gd.g_vis_bias, gd.g_vis_bleed, gd.g_vis_range); + /* Smooth backface test */ - // weight *= sqrt(max(0.002, dot(ws_light, N))); + weight *= sqrt(max(0.002, dot(ws_light, N))); /* Avoid zero weight */ weight = max(0.00001, weight); diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl index b3f5e8b60ad..1376c53d633 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl @@ -128,12 +128,16 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D v #ifdef IRRADIANCE_LIB vec3 irradiance_volumetric(vec3 wpos) { +#ifdef IRRADIANCE_HL2 IrradianceData ir_data = load_irradiance_cell(0, vec3(1.0)); vec3 irradiance = ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2]; ir_data = load_irradiance_cell(0, vec3(-1.0)); irradiance += ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2]; irradiance *= 0.16666666; /* 1/6 */ return irradiance; +#else + return vec3(0.0); +#endif } #endif diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index 76f5b4d9840..851d0ef9eb7 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -96,7 +96,7 @@ typedef struct EXTERNAL_PrivateData { /* Functions */ -static void EXTERNAL_engine_init(void *UNUSED(vedata)) +static void external_engine_init(void *UNUSED(vedata)) { /* Depth prepass */ if (!e_data.depth_sh) { @@ -104,7 +104,7 @@ static void EXTERNAL_engine_init(void *UNUSED(vedata)) } } -static void EXTERNAL_cache_init(void *vedata) +static void external_cache_init(void *vedata) { EXTERNAL_PassList *psl = ((EXTERNAL_Data *)vedata)->psl; EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl; @@ -121,7 +121,7 @@ static void EXTERNAL_cache_init(void *vedata) } } -static void EXTERNAL_cache_populate(void *vedata, Object *ob) +static void external_cache_populate(void *vedata, Object *ob) { EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl; @@ -135,11 +135,11 @@ static void EXTERNAL_cache_populate(void *vedata, Object *ob) } } -static void EXTERNAL_cache_finish(void *UNUSED(vedata)) +static void external_cache_finish(void *UNUSED(vedata)) { } -static void external_draw_scene(void *vedata) +static void external_draw_scene_do(void *vedata) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; @@ -151,7 +151,7 @@ static void external_draw_scene(void *vedata) /* Create render engine. */ if (!rv3d->render_engine) { - RenderEngineType *engine_type = draw_ctx->engine; + RenderEngineType *engine_type = draw_ctx->engine_type; if (!(engine_type->view_update && engine_type->render_to_view)) { return; @@ -184,7 +184,7 @@ static void external_draw_scene(void *vedata) } } -static void EXTERNAL_draw_scene(void *vedata) +static void external_draw_scene(void *vedata) { const DRWContextState *draw_ctx = DRW_context_state_get(); EXTERNAL_PassList *psl = ((EXTERNAL_Data *)vedata)->psl; @@ -193,29 +193,30 @@ static void EXTERNAL_draw_scene(void *vedata) * OpenGL render is used for quick preview (thumbnails or sequencer preview) * where using the rendering engine to preview doesn't make so much sense. */ if (draw_ctx->evil_C) { - external_draw_scene(vedata); + external_draw_scene_do(vedata); } DRW_draw_pass(psl->depth_pass); } -static void EXTERNAL_engine_free(void) +static void external_engine_free(void) { /* All shaders are builtin. */ } -static const DrawEngineDataSize EXTERNAL_data_size = DRW_VIEWPORT_DATA_SIZE(EXTERNAL_Data); +static const DrawEngineDataSize external_data_size = DRW_VIEWPORT_DATA_SIZE(EXTERNAL_Data); DrawEngineType draw_engine_external_type = { NULL, NULL, N_("External"), - &EXTERNAL_data_size, - &EXTERNAL_engine_init, - &EXTERNAL_engine_free, - &EXTERNAL_cache_init, - &EXTERNAL_cache_populate, - &EXTERNAL_cache_finish, + &external_data_size, + &external_engine_init, + &external_engine_free, + &external_cache_init, + &external_cache_populate, + &external_cache_finish, + NULL, + &external_draw_scene, NULL, - &EXTERNAL_draw_scene, NULL, }; diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 8d89454fa6a..0753dbc7a1a 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -138,6 +138,7 @@ typedef struct DrawEngineType { void (*draw_scene)(void *vedata); void (*view_update)(void *vedata); + void (*id_update)(void *vedata, struct ID *id); } DrawEngineType; #ifndef __DRW_ENGINE_H__ @@ -383,12 +384,14 @@ struct DefaultTextureList *DRW_viewport_texture_list_get(void); void DRW_viewport_request_redraw(void); /* ViewLayers */ -void **DRW_view_layer_engine_data_get(DrawEngineType *engine_type, void (*callback)(void *storage)); +void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type); +void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*callback)(void *storage)); /* Objects */ -void **DRW_object_engine_data_get( +void *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type); +void **DRW_object_engine_data_ensure( Object *ob, DrawEngineType *engine_type, void (*callback)(void *storage)); -struct LampEngineData *DRW_lamp_engine_data_get(Object *ob, struct RenderEngineType *engine_type); +struct LampEngineData *DRW_lamp_engine_data_ensure(Object *ob, struct RenderEngineType *engine_type); void DRW_lamp_engine_data_free(struct LampEngineData *led); /* Settings */ @@ -443,7 +446,7 @@ typedef struct DRWContextState { /* Use 'scene->obedit' for edit-mode */ struct Object *obact; /* 'OBACT' */ - struct RenderEngineType *engine; + struct RenderEngineType *engine_type; /* Last resort (some functions take this as an arg so we can't easily avoid). * May be NULL when used for selection or depth buffer. */ diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index 58cf3aaf6cc..c7a88f7689e 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -98,7 +98,7 @@ static struct { * \{ */ /* Octahedral */ -static void DRW_shgroup_bone_octahedral_solid(const float (*bone_mat)[4], const float color[4]) +static void drw_shgroup_bone_octahedral_solid(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_octahedral_solid == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_octahedral_get(); @@ -108,7 +108,7 @@ static void DRW_shgroup_bone_octahedral_solid(const float (*bone_mat)[4], const DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_solid, bone_mat, color); } -static void DRW_shgroup_bone_octahedral_wire(const float (*bone_mat)[4], const float color[4]) +static void drw_shgroup_bone_octahedral_wire(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_octahedral_wire == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_octahedral_wire_outline_get(); @@ -119,7 +119,7 @@ static void DRW_shgroup_bone_octahedral_wire(const float (*bone_mat)[4], const f } /* Box / B-Bone */ -static void DRW_shgroup_bone_box_solid(const float (*bone_mat)[4], const float color[4]) +static void drw_shgroup_bone_box_solid(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_box_solid == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_box_get(); @@ -129,7 +129,7 @@ static void DRW_shgroup_bone_box_solid(const float (*bone_mat)[4], const float c DRW_shgroup_call_dynamic_add(g_data.bone_box_solid, bone_mat, color); } -static void DRW_shgroup_bone_box_wire(const float (*bone_mat)[4], const float color[4]) +static void drw_shgroup_bone_box_wire(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_box_wire == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_box_wire_outline_get(); @@ -140,7 +140,7 @@ static void DRW_shgroup_bone_box_wire(const float (*bone_mat)[4], const float co } /* Wire */ -static void DRW_shgroup_bone_wire_wire(const float (*bone_mat)[4], const float color[4]) +static void drw_shgroup_bone_wire_wire(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_wire_wire == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_wire_wire_outline_get(); @@ -151,7 +151,7 @@ static void DRW_shgroup_bone_wire_wire(const float (*bone_mat)[4], const float c } /* Envelope */ -static void DRW_shgroup_bone_envelope_distance( +static void drw_shgroup_bone_envelope_distance( const float (*bone_mat)[4], const float color[4], const float *radius_head, const float *radius_tail, const float *distance) { @@ -166,7 +166,7 @@ static void DRW_shgroup_bone_envelope_distance( } } -static void DRW_shgroup_bone_envelope_solid( +static void drw_shgroup_bone_envelope_solid( const float (*bone_mat)[4], const float color[4], const float *radius_head, const float *radius_tail) { @@ -178,7 +178,7 @@ static void DRW_shgroup_bone_envelope_solid( DRW_shgroup_call_dynamic_add(g_data.bone_envelope_solid, bone_mat, color, radius_head, radius_tail); } -static void DRW_shgroup_bone_envelope_wire( +static void drw_shgroup_bone_envelope_wire( const float (*bone_mat)[4], const float color[4], const float *radius_head, const float *radius_tail, const float *distance) { @@ -190,7 +190,7 @@ static void DRW_shgroup_bone_envelope_wire( DRW_shgroup_call_dynamic_add(g_data.bone_envelope_wire, bone_mat, color, radius_head, radius_tail, distance); } -static void DRW_shgroup_bone_envelope_head_wire( +static void drw_shgroup_bone_envelope_head_wire( const float (*bone_mat)[4], const float color[4], const float *radius_head, const float *radius_tail, const float *distance) { @@ -204,7 +204,7 @@ static void DRW_shgroup_bone_envelope_head_wire( /* Custom (geometry) */ -static void DRW_shgroup_bone_custom_solid(const float (*bone_mat)[4], const float color[4], Object *custom) +static void drw_shgroup_bone_custom_solid(const float (*bone_mat)[4], const float color[4], Object *custom) { /* grr, not re-using instances! */ struct Gwn_Batch *geom = DRW_cache_object_surface_get(custom); @@ -214,7 +214,7 @@ static void DRW_shgroup_bone_custom_solid(const float (*bone_mat)[4], const floa } } -static void DRW_shgroup_bone_custom_wire(const float (*bone_mat)[4], const float color[4], Object *custom) +static void drw_shgroup_bone_custom_wire(const float (*bone_mat)[4], const float color[4], Object *custom) { /* grr, not re-using instances! */ struct Gwn_Batch *geom = DRW_cache_object_wire_outline_get(custom); @@ -225,7 +225,7 @@ static void DRW_shgroup_bone_custom_wire(const float (*bone_mat)[4], const float } /* Head and tail sphere */ -static void DRW_shgroup_bone_point_solid(const float (*bone_mat)[4], const float color[4]) +static void drw_shgroup_bone_point_solid(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_point_solid == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_point_get(); @@ -235,7 +235,7 @@ static void DRW_shgroup_bone_point_solid(const float (*bone_mat)[4], const float DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, bone_mat, color); } -static void DRW_shgroup_bone_point_wire(const float (*bone_mat)[4], const float color[4]) +static void drw_shgroup_bone_point_wire(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_point_wire == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_point_wire_outline_get(); @@ -246,7 +246,7 @@ static void DRW_shgroup_bone_point_wire(const float (*bone_mat)[4], const float } /* Axes */ -static void DRW_shgroup_bone_axes(const float (*bone_mat)[4], const float color[4]) +static void drw_shgroup_bone_axes(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_axes == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_arrows_get(); @@ -257,7 +257,7 @@ static void DRW_shgroup_bone_axes(const float (*bone_mat)[4], const float color[ } /* Relationship lines */ -static void UNUSED_FUNCTION(DRW_shgroup_bone_relationship_lines)(const float head[3], const float tail[3]) +static void UNUSED_FUNCTION(drw_shgroup_bone_relationship_lines)(const float head[3], const float tail[3]) { DRW_shgroup_call_dynamic_add(g_data.relationship_lines, head); DRW_shgroup_call_dynamic_add(g_data.relationship_lines, tail); @@ -918,7 +918,7 @@ static void draw_axes(EditBone *eBone, bPoseChannel *pchan) const float *col = (g_theme.const_color) ? g_theme.const_color : (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? g_theme.text_hi_color : g_theme.text_color; - DRW_shgroup_bone_axes(BONE_VAR(eBone, pchan, disp_mat), col); + drw_shgroup_bone_axes(BONE_VAR(eBone, pchan, disp_mat), col); } static void draw_points( @@ -971,14 +971,14 @@ static void draw_points( if (eBone) { if (!((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent))) { if (is_envelope_draw) { - DRW_shgroup_bone_envelope_solid(eBone->disp_mat, col_solid_root, + drw_shgroup_bone_envelope_solid(eBone->disp_mat, col_solid_root, &eBone->rad_head, &envelope_ignore); - DRW_shgroup_bone_envelope_head_wire(eBone->disp_mat, col_wire_root, + drw_shgroup_bone_envelope_head_wire(eBone->disp_mat, col_wire_root, &eBone->rad_head, &envelope_ignore, &envelope_ignore); } else { - DRW_shgroup_bone_point_solid(eBone->disp_mat, col_solid_root); - DRW_shgroup_bone_point_wire(eBone->disp_mat, col_wire_root); + drw_shgroup_bone_point_solid(eBone->disp_mat, col_solid_root); + drw_shgroup_bone_point_wire(eBone->disp_mat, col_wire_root); } } } @@ -986,14 +986,14 @@ static void draw_points( Bone *bone = pchan->bone; if (!((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)))) { if (is_envelope_draw) { - DRW_shgroup_bone_envelope_solid(pchan->disp_mat, col_solid_root, + drw_shgroup_bone_envelope_solid(pchan->disp_mat, col_solid_root, &bone->rad_head, &envelope_ignore); - DRW_shgroup_bone_envelope_head_wire(pchan->disp_mat, col_wire_root, + drw_shgroup_bone_envelope_head_wire(pchan->disp_mat, col_wire_root, &bone->rad_head, &envelope_ignore, &envelope_ignore); } else { - DRW_shgroup_bone_point_solid(pchan->disp_mat, col_solid_root); - DRW_shgroup_bone_point_wire(pchan->disp_mat, col_wire_root); + drw_shgroup_bone_point_solid(pchan->disp_mat, col_solid_root); + drw_shgroup_bone_point_wire(pchan->disp_mat, col_wire_root); } } } @@ -1006,14 +1006,14 @@ static void draw_points( if (is_envelope_draw) { const float *rad_tail = eBone ? &eBone->rad_tail : &pchan->bone->rad_tail; - DRW_shgroup_bone_envelope_solid( + drw_shgroup_bone_envelope_solid( BONE_VAR(eBone, pchan, disp_mat), col_solid_tail, &envelope_ignore, rad_tail); - DRW_shgroup_bone_envelope_head_wire( + drw_shgroup_bone_envelope_head_wire( BONE_VAR(eBone, pchan, disp_mat), col_wire_tail, &envelope_ignore, rad_tail, &envelope_ignore); } else { - DRW_shgroup_bone_point_solid(BONE_VAR(eBone, pchan, disp_tail_mat), col_solid_tail); - DRW_shgroup_bone_point_wire(BONE_VAR(eBone, pchan, disp_tail_mat), col_wire_tail); + drw_shgroup_bone_point_solid(BONE_VAR(eBone, pchan, disp_tail_mat), col_solid_tail); + drw_shgroup_bone_point_wire(BONE_VAR(eBone, pchan, disp_tail_mat), col_wire_tail); } if (select_id != -1) { @@ -1042,8 +1042,8 @@ static void draw_bone_custom_shape( DRW_select_load_id(select_id | BONESEL_BONE); } - DRW_shgroup_bone_custom_solid(disp_mat, col_solid, pchan->custom); - DRW_shgroup_bone_custom_wire(disp_mat, col_wire, pchan->custom); + drw_shgroup_bone_custom_solid(disp_mat, col_solid, pchan->custom); + drw_shgroup_bone_custom_wire(disp_mat, col_wire, pchan->custom); if (select_id != -1) { DRW_select_load_id(-1); @@ -1075,15 +1075,15 @@ static void draw_bone_envelope( if ((boneflag & BONE_NO_DEFORM) == 0 && ((boneflag & BONE_SELECTED) || (eBone && (boneflag & (BONE_ROOTSEL | BONE_TIPSEL))))) { - DRW_shgroup_bone_envelope_distance(BONE_VAR(eBone, pchan, disp_mat), col_white, rad_head, rad_tail, distance); + drw_shgroup_bone_envelope_distance(BONE_VAR(eBone, pchan, disp_mat), col_white, rad_head, rad_tail, distance); } if (select_id != -1) { DRW_select_load_id(select_id | BONESEL_BONE); } - DRW_shgroup_bone_envelope_solid(BONE_VAR(eBone, pchan, disp_mat), col_solid, rad_head, rad_tail); - DRW_shgroup_bone_envelope_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire, rad_head, rad_tail, distance); + drw_shgroup_bone_envelope_solid(BONE_VAR(eBone, pchan, disp_mat), col_solid, rad_head, rad_tail); + drw_shgroup_bone_envelope_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire, rad_head, rad_tail, distance); if (select_id != -1) { DRW_select_load_id(-1); @@ -1116,12 +1116,12 @@ static void draw_bone_wire( BLI_assert(bbones_mat != NULL); for (int i = pchan->bone->segments; i--; bbones_mat++) { - DRW_shgroup_bone_wire_wire(bbones_mat->mat, col_wire); + drw_shgroup_bone_wire_wire(bbones_mat->mat, col_wire); } } else if (eBone) { for (int i = 0; i < eBone->segments; i++) { - DRW_shgroup_bone_wire_wire(eBone->disp_bbone_mat[i], col_wire); + drw_shgroup_bone_wire_wire(eBone->disp_bbone_mat[i], col_wire); } } @@ -1151,14 +1151,14 @@ static void draw_bone_box( BLI_assert(bbones_mat != NULL); for (int i = pchan->bone->segments; i--; bbones_mat++) { - DRW_shgroup_bone_box_solid(bbones_mat->mat, col_solid); - DRW_shgroup_bone_box_wire(bbones_mat->mat, col_wire); + drw_shgroup_bone_box_solid(bbones_mat->mat, col_solid); + drw_shgroup_bone_box_wire(bbones_mat->mat, col_wire); } } else if (eBone) { for (int i = 0; i < eBone->segments; i++) { - DRW_shgroup_bone_box_solid(eBone->disp_bbone_mat[i], col_solid); - DRW_shgroup_bone_box_wire(eBone->disp_bbone_mat[i], col_wire); + drw_shgroup_bone_box_solid(eBone->disp_bbone_mat[i], col_solid); + drw_shgroup_bone_box_wire(eBone->disp_bbone_mat[i], col_wire); } } @@ -1183,8 +1183,8 @@ static void draw_bone_octahedral( DRW_select_load_id(select_id | BONESEL_BONE); } - DRW_shgroup_bone_octahedral_solid(BONE_VAR(eBone, pchan, disp_mat), col_solid); - DRW_shgroup_bone_octahedral_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire); + drw_shgroup_bone_octahedral_solid(BONE_VAR(eBone, pchan, disp_mat), col_solid); + drw_shgroup_bone_octahedral_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire); if (select_id != -1) { DRW_select_load_id(-1); @@ -1397,7 +1397,7 @@ static void draw_armature_pose(Object *ob, const float const_color[4]) /** * This function set the object space to use for all subsequent `DRW_shgroup_bone_*` calls. */ -static void DRW_shgroup_armature( +static void drw_shgroup_armature( Object *ob, DRWPass *pass_bone_solid, DRWPass *pass_bone_wire, DRWPass *pass_bone_envelope, DRWShadingGroup *shgrp_relationship_lines) { @@ -1419,7 +1419,7 @@ void DRW_shgroup_armature_object( float *color; DRW_object_wire_theme_get(ob, view_layer, &color); - DRW_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, NULL, shgrp_relationship_lines); + drw_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, NULL, shgrp_relationship_lines); draw_armature_pose(ob, color); } @@ -1427,7 +1427,7 @@ void DRW_shgroup_armature_pose( Object *ob, DRWPass *pass_bone_solid, DRWPass *pass_bone_wire, DRWPass *pass_bone_envelope, DRWShadingGroup *shgrp_relationship_lines) { - DRW_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, pass_bone_envelope, shgrp_relationship_lines); + drw_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, pass_bone_envelope, shgrp_relationship_lines); draw_armature_pose(ob, NULL); } @@ -1435,7 +1435,7 @@ void DRW_shgroup_armature_edit( Object *ob, DRWPass *pass_bone_solid, DRWPass *pass_bone_wire, DRWPass *pass_bone_envelope, DRWShadingGroup *shgrp_relationship_lines) { - DRW_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, pass_bone_envelope, shgrp_relationship_lines); + drw_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, pass_bone_envelope, shgrp_relationship_lines); draw_armature_edit(ob); } diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c index e8ad3e62139..e2dba8e626e 100644 --- a/source/blender/draw/intern/draw_cache_impl_metaball.c +++ b/source/blender/draw/intern/draw_cache_impl_metaball.c @@ -45,44 +45,6 @@ static void metaball_batch_cache_clear(MetaBall *mb); /* ---------------------------------------------------------------------- */ -/* MetaBall Interface, indirect, partially cached access to complex data. */ - -typedef struct MetaBallRenderData { - int types; - - /* borrow from 'Object' */ - CurveCache *ob_curve_cache; -} MetaBallRenderData; - -enum { - /* Geometry */ - MBALL_DATATYPE_SURFACE = 1 << 0, -// MBALL_DATATYPE_WIRE = 1 << 1, -// MBALL_DATATYPE_SHADING = 1 << 2, -}; - -static MetaBallRenderData *metaball_render_data_create( - MetaBall *UNUSED(mb), CurveCache *ob_curve_cache, const int types) -{ - MetaBallRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__); - rdata->types = types; - rdata->ob_curve_cache = ob_curve_cache; - -/* - **TODO** - if (types & MBALL_DATATYPE_WIRE) {} - if (types & MBALL_DATATYPE_SHADING) {} -*/ - - return rdata; -} - -static void metaball_render_data_free(MetaBallRenderData *rdata) -{ - MEM_freeN(rdata); -} - -/* ---------------------------------------------------------------------- */ /* MetaBall Gwn_Batch Cache */ typedef struct MetaBallBatchCache { @@ -158,24 +120,6 @@ void DRW_mball_batch_cache_free(MetaBall *mb) /* -------------------------------------------------------------------- */ -/** \name Private MetaBall Cache API - * \{ */ - -/* Gwn_Batch cache usage. */ - -static Gwn_Batch *metaball_batch_cache_get_pos_and_normals(MetaBallRenderData *rdata, MetaBallBatchCache *cache) -{ - BLI_assert(rdata->types & MBALL_DATATYPE_SURFACE); - if (cache->batch == NULL) { - cache->batch = BLI_displist_batch_calc_surface(&rdata->ob_curve_cache->disp); - } - return cache->batch; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ - /** \name Public Object/MetaBall API * \{ */ @@ -188,9 +132,7 @@ Gwn_Batch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob) MetaBallBatchCache *cache = metaball_batch_cache_get(mb); if (cache->batch == NULL) { - MetaBallRenderData *rdata = metaball_render_data_create(mb, ob->curve_cache, MBALL_DATATYPE_SURFACE); - metaball_batch_cache_get_pos_and_normals(rdata, cache); - metaball_render_data_free(rdata); + cache->batch = BLI_displist_batch_calc_surface(&ob->curve_cache->disp); } return cache->batch; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 1e0061bc29c..264fc079e42 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -101,29 +101,29 @@ #define USE_PROFILE #ifdef USE_PROFILE -#include "PIL_time.h" +# include "PIL_time.h" -#define PROFILE_TIMER_FALLOFF 0.1 +# define PROFILE_TIMER_FALLOFF 0.1 -#define PROFILE_START(time_start) \ +# define PROFILE_START(time_start) \ double time_start = PIL_check_seconds_timer(); -#define PROFILE_END_ACCUM(time_accum, time_start) { \ +# define PROFILE_END_ACCUM(time_accum, time_start) { \ time_accum += (PIL_check_seconds_timer() - time_start) * 1e3; \ } ((void)0) /* exp average */ -#define PROFILE_END_UPDATE(time_update, time_start) { \ +# define PROFILE_END_UPDATE(time_update, time_start) { \ double _time_delta = (PIL_check_seconds_timer() - time_start) * 1e3; \ time_update = (time_update * (1.0 - PROFILE_TIMER_FALLOFF)) + \ (_time_delta * PROFILE_TIMER_FALLOFF); \ } ((void)0) -#else +#else /* USE_PROFILE */ -#define PROFILE_START(time_start) ((void)0) -#define PROFILE_END_ACCUM(time_accum, time_start) ((void)0) -#define PROFILE_END_UPDATE(time_update, time_start) ((void)0) +# define PROFILE_START(time_start) ((void)0) +# define PROFILE_END_ACCUM(time_accum, time_start) ((void)0) +# define PROFILE_END_UPDATE(time_update, time_start) ((void)0) #endif /* USE_PROFILE */ @@ -150,7 +150,7 @@ extern char datatoc_gpu_shader_3D_vert_glsl[]; extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; /* Prototypes. */ -static void DRW_engines_enable_external(void); +static void drw_engines_enable_external(void); /* Structures */ typedef enum { @@ -658,7 +658,7 @@ void DRW_shader_free(GPUShader *shader) /** \name Interface (DRW_interface) * \{ */ -static void DRW_interface_create(DRWInterface *interface, GPUShader *shader) +static void drw_interface_create(DRWInterface *interface, GPUShader *shader) { interface->model = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL); interface->modelinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL_INV); @@ -691,7 +691,7 @@ static void DRW_interface_create(DRWInterface *interface, GPUShader *shader) } -static void DRW_interface_uniform(DRWShadingGroup *shgroup, const char *name, +static void drw_interface_uniform(DRWShadingGroup *shgroup, const char *name, DRWUniformType type, const void *value, int length, int arraysize) { int location; @@ -725,7 +725,7 @@ static void DRW_interface_uniform(DRWShadingGroup *shgroup, const char *name, shgroup->interface.uniforms = uni; } -static void DRW_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType type, int size, bool dummy) +static void drw_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType type, int size, bool dummy) { DRWAttrib *attrib = BLI_mempool_alloc(DST.vmempool->attribs); GLuint program = GPU_shader_get_program(shgroup->shader); @@ -788,7 +788,7 @@ DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass) pass->shgroups_last = shgroup; shgroup->next = NULL; - DRW_interface_create(&shgroup->interface, shader); + drw_interface_create(&shgroup->interface, shader); shgroup->type = DRW_SHG_NORMAL; shgroup->shader = shader; @@ -900,7 +900,7 @@ DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create( if (shgroup) { shgroup->type = DRW_SHG_TRIANGLE_BATCH; shgroup->interface.instance_count = size * 3; - DRW_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true); + drw_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true); } return shgroup; @@ -945,7 +945,7 @@ DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DR shgroup->type = DRW_SHG_TRIANGLE_BATCH; shgroup->interface.instance_count = size * 3; - DRW_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true); + drw_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true); return shgroup; } @@ -1143,82 +1143,82 @@ void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, unsigned int mask) void DRW_shgroup_attrib_float(DRWShadingGroup *shgroup, const char *name, int size) { - DRW_interface_attrib(shgroup, name, DRW_ATTRIB_FLOAT, size, false); + drw_interface_attrib(shgroup, name, DRW_ATTRIB_FLOAT, size, false); } void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1); } void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1); } void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 1); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 1); } void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize); } void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize); } void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize); } void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize); } void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize); } void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_INT, value, 1, arraysize); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_INT, value, 1, arraysize); } void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_FLOAT, value, 1, arraysize); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_FLOAT, value, 1, arraysize); } void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize); } void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize); } void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize); } void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_MAT3, value, 9, 1); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_MAT3, value, 9, 1); } void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value) { - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_MAT4, value, 16, 1); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_MAT4, value, 16, 1); } /* Creates a VBO containing OGL primitives for all DRWCallDynamic */ @@ -1449,7 +1449,7 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass) DRWShadingGroup *last = pass->shgroups; while ((last = last->next)) { /* Do nothing */ - }; + } pass->shgroups_last = last; } } @@ -1462,7 +1462,7 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass) /** \name Draw (DRW_draw) * \{ */ -static void DRW_state_set(DRWState state) +static void drw_state_set(DRWState state) { if (DST.state == state) { return; @@ -1711,7 +1711,7 @@ static void DRW_state_set(DRWState state) DST.state = state; } -static void DRW_stencil_set(unsigned int mask) +static void drw_stencil_set(unsigned int mask) { if (DST.stencil_mask != mask) { /* Stencil Write */ @@ -1954,8 +1954,8 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) release_texture_slots(); release_ubo_slots(); - DRW_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra); - DRW_stencil_set(shgroup->stencil_mask); + drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra); + drw_stencil_set(shgroup->stencil_mask); /* Binding Uniform */ /* Don't check anything, Interface should already contain the least uniform as possible */ @@ -2044,8 +2044,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) } } else { - for (DRWCall *call = shgroup->calls_first; call; call = call->head.prev) - { + for (DRWCall *call = shgroup->calls_first; call; call = call->head.prev) { bool neg_scale = is_negative_m4(call->obmat); /* Negative scale objects */ @@ -2076,12 +2075,12 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) DRW_state_reset(); } -static void DRW_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group) +static void drw_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group) { /* Start fresh */ DST.shader = NULL; - DRW_state_set(pass->state); + drw_state_set(pass->state); DRW_stats_query_start(pass->name); @@ -2111,13 +2110,13 @@ static void DRW_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWSha void DRW_draw_pass(DRWPass *pass) { - DRW_draw_pass_ex(pass, pass->shgroups, pass->shgroups_last); + drw_draw_pass_ex(pass, pass->shgroups, pass->shgroups_last); } /* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */ void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group) { - DRW_draw_pass_ex(pass, start_group, end_group); + drw_draw_pass_ex(pass, start_group, end_group); } void DRW_draw_callbacks_pre_scene(void) @@ -2140,7 +2139,7 @@ void DRW_draw_callbacks_post_scene(void) void DRW_state_reset_ex(DRWState state) { DST.state = ~state; - DRW_state_set(state); + drw_state_set(state); } void DRW_state_reset(void) @@ -2428,7 +2427,7 @@ void DRW_framebuffer_viewport_size(struct GPUFrameBuffer *UNUSED(fb_read), int x /* Use color management profile to draw texture to framebuffer */ void DRW_transform_to_display(GPUTexture *tex) { - DRW_state_set(DRW_STATE_WRITE_COLOR); + drw_state_set(DRW_STATE_WRITE_COLOR); Gwn_VertFormat *vert_format = immVertexFormat(); unsigned int pos = GWN_vertformat_attr_add(vert_format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); @@ -2489,7 +2488,7 @@ void DRW_transform_to_display(GPUTexture *tex) /** \name Viewport (DRW_viewport) * \{ */ -static void *DRW_viewport_engine_data_get(void *engine_type) +static void *DRW_viewport_engine_data_ensure(void *engine_type) { void *data = GPU_viewport_engine_data_get(DST.viewport, engine_type); @@ -2534,7 +2533,7 @@ const float *DRW_viewport_pixelsize_get(void) return &DST.pixsize; } -static void DRW_viewport_cache_resize(void) +static void drw_viewport_cache_resize(void) { /* Release the memiter before clearing the mempools that references them */ GPU_viewport_cache_release(DST.viewport); @@ -2554,7 +2553,7 @@ static void DRW_viewport_cache_resize(void) * This is because a cache uniform only store reference * to its value. And we don't want to invalidate the cache * if this value change per viewport */ -static void DRW_viewport_var_init(void) +static void drw_viewport_var_init(void) { RegionView3D *rv3d = DST.draw_ctx.rv3d; @@ -2702,7 +2701,17 @@ void DRW_viewport_request_redraw(void) /** \name ViewLayers (DRW_scenelayer) * \{ */ -void **DRW_view_layer_engine_data_get(DrawEngineType *engine_type, void (*callback)(void *storage)) +void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type) +{ + for (ViewLayerEngineData *sled = DST.draw_ctx.view_layer->drawdata.first; sled; sled = sled->next) { + if (sled->engine_type == engine_type) { + return sled->storage; + } + } + return NULL; +} + +void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*callback)(void *storage)) { ViewLayerEngineData *sled; @@ -2728,7 +2737,17 @@ void **DRW_view_layer_engine_data_get(DrawEngineType *engine_type, void (*callba /** \name Objects (DRW_object) * \{ */ -void **DRW_object_engine_data_get( +void *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type) +{ + for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) { + if (oed->engine_type == engine_type) { + return oed->storage; + } + } + return NULL; +} + +void **DRW_object_engine_data_ensure( Object *ob, DrawEngineType *engine_type, void (*callback)(void *storage)) { ObjectEngineData *oed; @@ -2747,9 +2766,9 @@ void **DRW_object_engine_data_get( return &oed->storage; } -/* XXX There is definitly some overlap between this and DRW_object_engine_data_get. +/* XXX There is definitly some overlap between this and DRW_object_engine_data_ensure. * We should get rid of one of the two. */ -LampEngineData *DRW_lamp_engine_data_get(Object *ob, RenderEngineType *engine_type) +LampEngineData *DRW_lamp_engine_data_ensure(Object *ob, RenderEngineType *engine_type) { BLI_assert(ob->type == OB_LAMP); @@ -2773,11 +2792,11 @@ void DRW_lamp_engine_data_free(LampEngineData *led) /** \name Rendering (DRW_engines) * \{ */ -static void DRW_engines_init(void) +static void drw_engines_init(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); PROFILE_START(stime); if (engine->engine_init) { @@ -2788,11 +2807,11 @@ static void DRW_engines_init(void) } } -static void DRW_engines_cache_init(void) +static void drw_engines_cache_init(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); if (data->text_draw_cache) { DRW_text_cache_destroy(data->text_draw_cache); @@ -2808,11 +2827,11 @@ static void DRW_engines_cache_init(void) } } -static void DRW_engines_cache_populate(Object *ob) +static void drw_engines_cache_populate(Object *ob) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); if (engine->cache_populate) { engine->cache_populate(data, ob); @@ -2820,11 +2839,11 @@ static void DRW_engines_cache_populate(Object *ob) } } -static void DRW_engines_cache_finish(void) +static void drw_engines_cache_finish(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); if (engine->cache_finish) { engine->cache_finish(data); @@ -2832,11 +2851,11 @@ static void DRW_engines_cache_finish(void) } } -static void DRW_engines_draw_background(void) +static void drw_engines_draw_background(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); if (engine->draw_background) { PROFILE_START(stime); @@ -2854,11 +2873,11 @@ static void DRW_engines_draw_background(void) DRW_draw_background(); } -static void DRW_engines_draw_scene(void) +static void drw_engines_draw_scene(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); PROFILE_START(stime); if (engine->draw_scene) { @@ -2871,11 +2890,11 @@ static void DRW_engines_draw_scene(void) } } -static void DRW_engines_draw_text(void) +static void drw_engines_draw_text(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); PROFILE_START(stime); if (data->text_draw_cache) { @@ -2896,7 +2915,7 @@ int DRW_draw_region_engine_info_offset(void) int lines = 0; for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); /* Count the number of lines. */ if (data->info[0] != '\0') { @@ -2931,7 +2950,7 @@ void DRW_draw_region_engine_info(void) for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); if (data->info[0] != '\0') { char *chr_current = data->info; @@ -2978,24 +2997,24 @@ static void use_drw_engine(DrawEngineType *engine) /* TODO revisit this when proper layering is implemented */ /* Gather all draw engines needed and store them in DST.enabled_engines * That also define the rendering order of engines */ -static void DRW_engines_enable_from_engine(RenderEngineType *engine) +static void drw_engines_enable_from_engine(RenderEngineType *engine_type) { /* TODO layers */ - if (engine->draw_engine != NULL) { - use_drw_engine(engine->draw_engine); + if (engine_type->draw_engine != NULL) { + use_drw_engine(engine_type->draw_engine); } - if ((engine->flag & RE_INTERNAL) == 0) { - DRW_engines_enable_external(); + if ((engine_type->flag & RE_INTERNAL) == 0) { + drw_engines_enable_external(); } } -static void DRW_engines_enable_from_object_mode(void) +static void drw_engines_enable_from_object_mode(void) { use_drw_engine(&draw_engine_object_type); } -static void DRW_engines_enable_from_mode(int mode) +static void drw_engines_enable_from_mode(int mode) { switch (mode) { case CTX_MODE_EDIT_MESH: @@ -3049,7 +3068,7 @@ static void DRW_engines_enable_from_mode(int mode) /** * Use for select and depth-drawing. */ -static void DRW_engines_enable_basic(void) +static void drw_engines_enable_basic(void) { use_drw_engine(DRW_engine_viewport_basic_type.draw_engine); } @@ -3057,25 +3076,25 @@ static void DRW_engines_enable_basic(void) /** * Use for external render engines. */ -static void DRW_engines_enable_external(void) +static void drw_engines_enable_external(void) { use_drw_engine(DRW_engine_viewport_external_type.draw_engine); } -static void DRW_engines_enable(const Scene *scene, ViewLayer *view_layer, RenderEngineType *engine) +static void drw_engines_enable(const Scene *scene, ViewLayer *view_layer, RenderEngineType *engine_type) { Object *obact = OBACT(view_layer); const int mode = CTX_data_mode_enum_ex(scene->obedit, obact); - DRW_engines_enable_from_engine(engine); + drw_engines_enable_from_engine(engine_type); if (DRW_state_draw_support()) { - DRW_engines_enable_from_object_mode(); - DRW_engines_enable_from_mode(mode); + drw_engines_enable_from_object_mode(); + drw_engines_enable_from_mode(mode); } } -static void DRW_engines_disable(void) +static void drw_engines_disable(void) { BLI_freelistN(&DST.enabled_engines); } @@ -3101,7 +3120,7 @@ static void draw_stat(rcti *rect, int u, int v, const char *txt, const int size) } /* CPU stats */ -static void DRW_debug_cpu_stats(void) +static void drw_debug_cpu_stats(void) { int u, v; double init_tot_time = 0.0, background_tot_time = 0.0, render_tot_time = 0.0, tot_time = 0.0; @@ -3133,7 +3152,7 @@ static void DRW_debug_cpu_stats(void) for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { u = 0; DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); draw_stat(&rect, u++, v, engine->idname, sizeof(engine->idname)); @@ -3177,7 +3196,7 @@ static void DRW_debug_cpu_stats(void) } /* Display GPU time for each passes */ -static void DRW_debug_gpu_stats(void) +static void drw_debug_gpu_stats(void) { /* local coordinate visible rect inside region, to accomodate overlapping ui */ rcti rect; @@ -3219,15 +3238,14 @@ static void DRW_debug_gpu_stats(void) /** \name View Update * \{ */ -void DRW_notify_view_update(const bContext *C) +void DRW_notify_view_update(const DRWUpdateContext *update_ctx) { - struct Depsgraph *graph = CTX_data_depsgraph(C); - ARegion *ar = CTX_wm_region(C); - View3D *v3d = CTX_wm_view3d(C); + RenderEngineType *engine_type = update_ctx->engine_type; + ARegion *ar = update_ctx->ar; + View3D *v3d = update_ctx->v3d; RegionView3D *rv3d = ar->regiondata; - Scene *scene = DEG_get_evaluated_scene(graph); - RenderEngineType *engine = CTX_data_engine(C); - ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = update_ctx->scene; + ViewLayer *view_layer = update_ctx->view_layer; if (rv3d->viewport == NULL) { return; @@ -3239,14 +3257,14 @@ void DRW_notify_view_update(const bContext *C) DST.viewport = rv3d->viewport; DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine, C, + ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, NULL, }; - DRW_engines_enable(scene, view_layer, engine); + drw_engines_enable(scene, view_layer, engine_type); for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *draw_engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_get(draw_engine); + ViewportEngineData *data = DRW_viewport_engine_data_ensure(draw_engine); if (draw_engine->view_update) { draw_engine->view_update(data); @@ -3255,7 +3273,47 @@ void DRW_notify_view_update(const bContext *C) DST.viewport = NULL; - DRW_engines_disable(); + drw_engines_disable(); +} + +/** \} */ + +/** \name ID Update + * \{ */ + +/* TODO(sergey): This code is run for each changed ID (including the ones which + * are changed indirectly via update flush. Need to find a way to make this to + * run really fast, hopefully without any memory allocations on a heap + * Idea here could be to run every known engine's id_update() and make them + * do nothing if there is no engine-specific data yet. + */ +void DRW_notify_id_update(const DRWUpdateContext *update_ctx, ID *id) +{ + RenderEngineType *engine_type = update_ctx->engine_type; + ARegion *ar = update_ctx->ar; + View3D *v3d = update_ctx->v3d; + RegionView3D *rv3d = ar->regiondata; + Scene *scene = update_ctx->scene; + ViewLayer *view_layer = update_ctx->view_layer; + if (rv3d->viewport == NULL) { + return; + } + /* Reset before using it. */ + memset(&DST, 0x0, sizeof(DST)); + DST.viewport = rv3d->viewport; + DST.draw_ctx = (DRWContextState){ + ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, NULL, + }; + drw_engines_enable(scene, view_layer, engine_type); + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + DrawEngineType *draw_engine = link->data; + ViewportEngineData *data = DRW_viewport_engine_data_ensure(draw_engine); + if (draw_engine->id_update) { + draw_engine->id_update(data, id); + } + } + DST.viewport = NULL; + drw_engines_disable(); } /** \} */ @@ -3271,13 +3329,13 @@ void DRW_notify_view_update(const bContext *C) void DRW_draw_view(const bContext *C) { struct Depsgraph *graph = CTX_data_depsgraph(C); - RenderEngineType *engine = CTX_data_engine(C); + RenderEngineType *engine_type = CTX_data_engine_type(C); ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); /* Reset before using it. */ memset(&DST, 0x0, sizeof(DST)); - DRW_draw_render_loop_ex(graph, engine, ar, v3d, C); + DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, C); } /** @@ -3286,7 +3344,7 @@ void DRW_draw_view(const bContext *C) */ void DRW_draw_render_loop_ex( struct Depsgraph *graph, - RenderEngineType *engine, + RenderEngineType *engine_type, ARegion *ar, View3D *v3d, const bContext *evil_C) { @@ -3303,39 +3361,37 @@ void DRW_draw_render_loop_ex( GPU_viewport_engines_data_validate(DST.viewport, DRW_engines_get_hash()); DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine, + ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, /* reuse if caller sets */ DST.draw_ctx.evil_C, }; - DRW_viewport_var_init(); + drw_viewport_var_init(); /* Get list of enabled engines */ - DRW_engines_enable(scene, view_layer, engine); + drw_engines_enable(scene, view_layer, engine_type); /* Update ubos */ DRW_globals_update(); /* Init engines */ - DRW_engines_init(); + drw_engines_init(); /* TODO : tag to refresh by the deps graph */ /* ideally only refresh when objects are added/removed */ /* or render properties / materials change */ { PROFILE_START(stime); - DRW_engines_cache_init(); + drw_engines_cache_init(); - DEG_OBJECT_ITER(graph, ob, DEG_OBJECT_ITER_FLAG_ALL); + DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_ALL); { - DRW_engines_cache_populate(ob); - /* XXX find a better place for this. maybe Depsgraph? */ - ob->deg_update_flag = 0; + drw_engines_cache_populate(ob); } DEG_OBJECT_ITER_END - DRW_engines_cache_finish(); + drw_engines_cache_finish(); PROFILE_END_ACCUM(DST.cache_time, stime); } @@ -3343,7 +3399,7 @@ void DRW_draw_render_loop_ex( /* Start Drawing */ DRW_state_reset(); - DRW_engines_draw_background(); + drw_engines_draw_background(); /* WIP, single image drawn over the camera view (replace) */ bool do_bg_image = false; @@ -3358,7 +3414,7 @@ void DRW_draw_render_loop_ex( } extern void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, - const bool do_foreground, const bool do_camera_frame); + const bool do_foreground, const bool do_camera_frame); if (do_bg_image) { view3d_draw_bgpic_test(scene, ar, v3d, false, true); } @@ -3369,7 +3425,7 @@ void DRW_draw_render_loop_ex( ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.ar, REGION_DRAW_PRE_VIEW); } - DRW_engines_draw_scene(); + drw_engines_draw_scene(); DRW_draw_callbacks_post_scene(); if (DST.draw_ctx.evil_C) { @@ -3378,7 +3434,7 @@ void DRW_draw_render_loop_ex( DRW_state_reset(); - DRW_engines_draw_text(); + drw_engines_draw_text(); if (DST.draw_ctx.evil_C) { /* needed so manipulator isn't obscured */ @@ -3396,14 +3452,14 @@ void DRW_draw_render_loop_ex( } if (G.debug_value > 20) { - DRW_debug_cpu_stats(); - DRW_debug_gpu_stats(); + drw_debug_cpu_stats(); + drw_debug_gpu_stats(); } DRW_state_reset(); - DRW_engines_disable(); + drw_engines_disable(); - DRW_viewport_cache_resize(); + drw_viewport_cache_resize(); #ifdef DEBUG /* Avoid accidental reuse. */ @@ -3419,13 +3475,13 @@ void DRW_draw_render_loop( memset(&DST, 0x0, sizeof(DST)); Scene *scene = DEG_get_evaluated_scene(graph); - RenderEngineType *engine = RE_engines_find(scene->view_render.engine_id); + RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id); - DRW_draw_render_loop_ex(graph, engine, ar, v3d, NULL); + DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, NULL); } void DRW_draw_render_loop_offscreen( - struct Depsgraph *graph, RenderEngineType *engine, + struct Depsgraph *graph, RenderEngineType *engine_type, ARegion *ar, View3D *v3d, GPUOffScreen *ofs) { RegionView3D *rv3d = ar->regiondata; @@ -3440,7 +3496,7 @@ void DRW_draw_render_loop_offscreen( /* Reset before using it. */ memset(&DST, 0x0, sizeof(DST)); DST.options.is_image_render = true; - DRW_draw_render_loop_ex(graph, engine, ar, v3d, NULL); + DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, NULL); /* restore */ { @@ -3465,7 +3521,7 @@ void DRW_draw_select_loop( bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect) { Scene *scene = DEG_get_evaluated_scene(graph); - RenderEngineType *engine = RE_engines_find(scene->view_render.engine_id); + RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id); ViewLayer *view_layer = DEG_get_evaluated_view_layer(graph); #ifndef USE_GPU_SELECT UNUSED_VARS(vc, scene, view_layer, v3d, ar, rect); @@ -3505,11 +3561,11 @@ void DRW_draw_select_loop( /* Get list of enabled engines */ if (use_obedit) { - DRW_engines_enable_from_mode(obedit_mode); + drw_engines_enable_from_mode(obedit_mode); } else { - DRW_engines_enable_basic(); - DRW_engines_enable_from_object_mode(); + drw_engines_enable_basic(); + drw_engines_enable_from_object_mode(); } /* Setup viewport */ @@ -3517,49 +3573,48 @@ void DRW_draw_select_loop( /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */ DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine, (bContext *)NULL, + ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, (bContext *)NULL, }; - DRW_viewport_var_init(); + drw_viewport_var_init(); /* Update ubos */ DRW_globals_update(); /* Init engines */ - DRW_engines_init(); + drw_engines_init(); /* TODO : tag to refresh by the deps graph */ /* ideally only refresh when objects are added/removed */ /* or render properties / materials change */ if (cache_is_dirty) { - - DRW_engines_cache_init(); + drw_engines_cache_init(); if (use_obedit) { - DRW_engines_cache_populate(scene->obedit); + drw_engines_cache_populate(scene->obedit); } else { - DEG_OBJECT_ITER(graph, ob, DEG_OBJECT_ITER_FLAG_DUPLI) + DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_DUPLI) { if ((ob->base_flag & BASE_SELECTABLED) != 0) { DRW_select_load_id(ob->select_color); - DRW_engines_cache_populate(ob); + drw_engines_cache_populate(ob); } } DEG_OBJECT_ITER_END } - DRW_engines_cache_finish(); + drw_engines_cache_finish(); } /* Start Drawing */ DRW_state_reset(); DRW_draw_callbacks_pre_scene(); - DRW_engines_draw_scene(); + drw_engines_draw_scene(); DRW_draw_callbacks_post_scene(); DRW_state_reset(); - DRW_engines_disable(); + drw_engines_disable(); #ifdef DEBUG /* Avoid accidental reuse. */ @@ -3583,7 +3638,7 @@ void DRW_draw_depth_loop( ARegion *ar, View3D *v3d) { Scene *scene = DEG_get_evaluated_scene(graph); - RenderEngineType *engine = RE_engines_find(scene->view_render.engine_id); + RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id); ViewLayer *view_layer = DEG_get_evaluated_view_layer(graph); RegionView3D *rv3d = ar->regiondata; @@ -3605,8 +3660,8 @@ void DRW_draw_depth_loop( /* Get list of enabled engines */ { - DRW_engines_enable_basic(); - DRW_engines_enable_from_object_mode(); + drw_engines_enable_basic(); + drw_engines_enable_from_object_mode(); } /* Setup viewport */ @@ -3614,41 +3669,40 @@ void DRW_draw_depth_loop( /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */ DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine, (bContext *)NULL, + ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, (bContext *)NULL, }; - DRW_viewport_var_init(); + drw_viewport_var_init(); /* Update ubos */ DRW_globals_update(); /* Init engines */ - DRW_engines_init(); + drw_engines_init(); /* TODO : tag to refresh by the deps graph */ /* ideally only refresh when objects are added/removed */ /* or render properties / materials change */ if (cache_is_dirty) { + drw_engines_cache_init(); - DRW_engines_cache_init(); - - DEG_OBJECT_ITER(graph, ob, DEG_OBJECT_ITER_FLAG_ALL) + DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_ALL) { - DRW_engines_cache_populate(ob); + drw_engines_cache_populate(ob); } DEG_OBJECT_ITER_END - DRW_engines_cache_finish(); + drw_engines_cache_finish(); } /* Start Drawing */ DRW_state_reset(); DRW_draw_callbacks_pre_scene(); - DRW_engines_draw_scene(); + drw_engines_draw_scene(); DRW_draw_callbacks_post_scene(); DRW_state_reset(); - DRW_engines_disable(); + drw_engines_disable(); #ifdef DEBUG /* Avoid accidental reuse. */ diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c index 1d542fc8e7e..1ecf1a60a35 100644 --- a/source/blender/draw/modes/edit_curve_mode.c +++ b/source/blender/draw/modes/edit_curve_mode.c @@ -89,7 +89,7 @@ typedef struct EDIT_CURVE_StorageList { } EDIT_CURVE_StorageList; typedef struct EDIT_CURVE_Data { - /* Struct returned by DRW_viewport_engine_data_get. + /* Struct returned by DRW_viewport_engine_data_ensure. * If you don't use one of these, just make it a (void *) */ // void *fbl; void *engine_type; /* Required */ diff --git a/source/blender/draw/modes/edit_lattice_mode.c b/source/blender/draw/modes/edit_lattice_mode.c index 675ea925a39..ff4c557326e 100644 --- a/source/blender/draw/modes/edit_lattice_mode.c +++ b/source/blender/draw/modes/edit_lattice_mode.c @@ -85,7 +85,7 @@ typedef struct EDIT_LATTICE_StorageList { } EDIT_LATTICE_StorageList; typedef struct EDIT_LATTICE_Data { - /* Struct returned by DRW_viewport_engine_data_get. + /* Struct returned by DRW_viewport_engine_data_ensure. * If you don't use one of these, just make it a (void *) */ // void *fbl; void *engine_type; /* Required */ diff --git a/source/blender/draw/modes/edit_metaball_mode.c b/source/blender/draw/modes/edit_metaball_mode.c index fb61114686b..a83f5ae33bc 100644 --- a/source/blender/draw/modes/edit_metaball_mode.c +++ b/source/blender/draw/modes/edit_metaball_mode.c @@ -81,7 +81,7 @@ typedef struct EDIT_METABALL_StorageList { } EDIT_METABALL_StorageList; typedef struct EDIT_METABALL_Data { - /* Struct returned by DRW_viewport_engine_data_get. + /* Struct returned by DRW_viewport_engine_data_ensure. * If you don't use one of these, just make it a (void *) */ // void *fbl; void *engine_type; /* Required */ diff --git a/source/blender/draw/modes/edit_surface_mode.c b/source/blender/draw/modes/edit_surface_mode.c index e99973144aa..4e60c4abff5 100644 --- a/source/blender/draw/modes/edit_surface_mode.c +++ b/source/blender/draw/modes/edit_surface_mode.c @@ -76,7 +76,7 @@ typedef struct EDIT_SURFACE_StorageList { } EDIT_SURFACE_StorageList; typedef struct EDIT_SURFACE_Data { - /* Struct returned by DRW_viewport_engine_data_get. + /* Struct returned by DRW_viewport_engine_data_ensure. * If you don't use one of these, just make it a (void *) */ // void *fbl; void *engine_type; /* Required */ diff --git a/source/blender/draw/modes/edit_text_mode.c b/source/blender/draw/modes/edit_text_mode.c index 476a2ab9ac2..b375bad84b5 100644 --- a/source/blender/draw/modes/edit_text_mode.c +++ b/source/blender/draw/modes/edit_text_mode.c @@ -83,7 +83,7 @@ typedef struct EDIT_TEXT_StorageList { } EDIT_TEXT_StorageList; typedef struct EDIT_TEXT_Data { - /* Struct returned by DRW_viewport_engine_data_get. + /* Struct returned by DRW_viewport_engine_data_ensure. * If you don't use one of these, just make it a (void *) */ // void *fbl; void *engine_type; /* Required */ diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index a1bb12aec25..91b64818eff 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -1110,7 +1110,7 @@ static void DRW_shgroup_lamp(OBJECT_StorageList *stl, Object *ob, ViewLayer *vie int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color); static float zero = 0.0f; - float **la_mats = (float **)DRW_object_engine_data_get(ob, &draw_engine_object_type, NULL); + float **la_mats = (float **)DRW_object_engine_data_ensure(ob, &draw_engine_object_type, NULL); if (*la_mats == NULL) { /* we need 2 matrices */ *la_mats = MEM_mallocN(sizeof(float) * 16 * 2, "Lamp Object Mode Matrices"); @@ -1456,7 +1456,7 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl DRW_object_wire_theme_get(ob, view_layer, &color); OBJECT_LightProbeEngineData *prb_data; - OBJECT_LightProbeEngineData **prb_data_pt = (OBJECT_LightProbeEngineData **)DRW_object_engine_data_get(ob, &draw_engine_object_type, NULL); + OBJECT_LightProbeEngineData **prb_data_pt = (OBJECT_LightProbeEngineData **)DRW_object_engine_data_ensure(ob, &draw_engine_object_type, NULL); if (*prb_data_pt == NULL) { *prb_data_pt = MEM_mallocN(sizeof(OBJECT_LightProbeEngineData), "Probe Clip distances Matrices"); } diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c index f898770acef..b49da0cba2f 100644 --- a/source/blender/draw/modes/paint_texture_mode.c +++ b/source/blender/draw/modes/paint_texture_mode.c @@ -90,7 +90,7 @@ typedef struct PAINT_TEXTURE_StorageList { } PAINT_TEXTURE_StorageList; typedef struct PAINT_TEXTURE_Data { - /* Struct returned by DRW_viewport_engine_data_get. + /* Struct returned by DRW_viewport_engine_data_ensure. * If you don't use one of these, just make it a (void *) */ // void *fbl; void *engine_type; /* Required */ diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c index be076815f4c..6a3e53a72c2 100644 --- a/source/blender/draw/modes/particle_mode.c +++ b/source/blender/draw/modes/particle_mode.c @@ -70,7 +70,7 @@ typedef struct PARTICLE_StorageList { } PARTICLE_StorageList; typedef struct PARTICLE_Data { - /* Struct returned by DRW_viewport_engine_data_get. + /* Struct returned by DRW_viewport_engine_data_ensure. * If you don't use one of these, just make it a (void *) */ // void *fbl; void *engine_type; /* Required */ diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c index f38e6565065..d9f1f5ebe91 100644 --- a/source/blender/draw/modes/sculpt_mode.c +++ b/source/blender/draw/modes/sculpt_mode.c @@ -80,7 +80,7 @@ typedef struct SCULPT_StorageList { } SCULPT_StorageList; typedef struct SCULPT_Data { - /* Struct returned by DRW_viewport_engine_data_get. + /* Struct returned by DRW_viewport_engine_data_ensure. * If you don't use one of these, just make it a (void *) */ // void *fbl; void *engine_type; /* Required */ diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index e32324d25f9..b87942fed84 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -807,6 +807,7 @@ enum { SIMEDBONE_PREFIX, SIMEDBONE_SUFFIX, SIMEDBONE_LAYER, + SIMEDBONE_GROUP, SIMEDBONE_SHAPE, }; @@ -819,6 +820,7 @@ static const EnumPropertyItem prop_similar_types[] = { {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""}, {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""}, {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""}, + {SIMEDBONE_GROUP, "GROUP", 0, "Group", ""}, {SIMEDBONE_SHAPE, "SHAPE", 0, "Shape", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1009,6 +1011,9 @@ static int armature_select_similar_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } +#define STRUCT_SIZE_AND_OFFSET(_struct, _member) \ + sizeof(((_struct *)NULL)->_member), offsetof(_struct, _member) + switch (type) { case SIMEDBONE_CHILDREN: select_similar_children(arm, ebone_act); @@ -1034,13 +1039,20 @@ static int armature_select_similar_exec(bContext *C, wmOperator *op) case SIMEDBONE_LAYER: select_similar_layer(arm, ebone_act); break; + case SIMEDBONE_GROUP: + select_similar_data_pchan( + arm, obedit, ebone_act, + STRUCT_SIZE_AND_OFFSET(bPoseChannel, agrp_index)); + break; case SIMEDBONE_SHAPE: select_similar_data_pchan( arm, obedit, ebone_act, - sizeof(void *), offsetof(bPoseChannel, custom)); + STRUCT_SIZE_AND_OFFSET(bPoseChannel, custom)); break; } +#undef STRUCT_SIZE_AND_OFFSET + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); return OPERATOR_FINISHED; diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index a240d6b190f..4dd8e4bd6fa 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -998,7 +998,7 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S * the ideal would be to call this function only at the beginning of the snap operation, * or at the beginning of the operator itself */ struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine(C), 0, + CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine_type(C), 0, CTX_wm_region(C), CTX_wm_view3d(C)); float mvalf[2] = {UNPACK2(dd->mval)}; diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index e8c784f15d5..79b63f36b76 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -5020,7 +5020,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) const float mval[2] = {UNPACK2(event->mval)}; struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), vc.scene, vc.view_layer, vc.engine, 0, + CTX_data_main(C), vc.scene, vc.view_layer, vc.engine_type, 0, vc.ar, vc.v3d); ED_transform_snap_object_project_view3d_mixed( diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 92daa802601..f3b12b9bc85 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1156,7 +1156,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG */ ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info); cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE); - BKE_collection_object_add(scene, sc, ob); + BKE_collection_object_add(&scene->id, sc, ob); base_new = BKE_view_layer_base_find(view_layer, ob); cu->flag |= CU_3D; diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 1c8cf0665b3..1fd7756df77 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -76,7 +76,6 @@ struct BMFace *EDBM_verts_mirror_get_face(struct BMEditMesh *em, struct BMFace * void EDBM_verts_mirror_cache_clear(struct BMEditMesh *em, struct BMVert *v); void EDBM_verts_mirror_cache_end(struct BMEditMesh *em); -void EDBM_mesh_ensure_valid_dm_hack(struct Scene *scene, struct BMEditMesh *em); void EDBM_mesh_normals_update(struct BMEditMesh *em); void EDBM_mesh_clear(struct BMEditMesh *em); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 066c4e5a692..8d2ff327c51 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -82,7 +82,7 @@ typedef enum eParentType { PAR_VERTEX_TRI, } eParentType; -typedef enum eObjectSelect_Mode{ +typedef enum eObjectSelect_Mode { BA_DESELECT = 0, BA_SELECT = 1, BA_INVERT = 2, diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index 707d7c6c693..b7317d75cd4 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -31,6 +31,7 @@ #include "DNA_vec_types.h" struct bContext; +struct DEGEditorUpdateContext; struct ID; struct Main; struct MTex; @@ -43,13 +44,15 @@ struct wmWindowManager; void ED_operatortypes_render(void); -/* render_shading.c */ +/* render_update.c */ -void ED_render_id_flush_update(struct Main *bmain, struct ID *id); void ED_render_engine_changed(struct Main *bmain); void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *sa); -void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated); -void ED_render_scene_update_pre(struct Main *bmain, struct Scene *scene, bool time); + +/* Callbacks handling data update events coming from depsgraph. */ + +void ED_render_id_flush_update(const struct DEGEditorUpdateContext *update_ctx, struct ID *id); +void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, int updated); void ED_viewport_render_kill_jobs(struct wmWindowManager *wm, struct Main *bmain, bool free_database); struct Scene *ED_render_job_get_scene(const struct bContext *C); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 6cb20c818fd..d931109b941 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -55,6 +55,9 @@ struct ARegion; struct uiBlock; struct rcti; struct Main; +struct wmMsgBus; +struct wmMsgSubscribeKey; +struct wmMsgSubscribeValue; /* regions */ void ED_region_do_listen( @@ -86,6 +89,18 @@ void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy); float ED_region_blend_factor(struct ARegion *ar); void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect); +/* message_bus callbacks */ +void ED_region_do_msg_notify_tag_redraw( + struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val); +void ED_area_do_msg_notify_tag_refresh( + struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val); + +/* message bus */ +void ED_region_message_subscribe( + struct bContext *C, + struct WorkSpace *workspace, struct Scene *scene, + struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus); /* spaces */ void ED_spacetypes_keymap(struct wmKeyConfig *keyconf); @@ -153,6 +168,7 @@ void ED_screen_preview_render(const struct bScreen *screen, int size_x, int s struct WorkSpace *ED_workspace_add( struct Main *bmain, const char *name, + Scene *scene, ViewLayer *act_render_layer, struct ViewRender *view_render) ATTR_NONNULL(); bool ED_workspace_change( @@ -169,7 +185,8 @@ bool ED_workspace_delete( void ED_workspace_scene_data_sync( struct WorkSpaceInstanceHook *hook, Scene *scene) ATTR_NONNULL(); void ED_workspace_view_layer_unset( - const struct Main *bmain, const ViewLayer *layer_unset, ViewLayer *layer_new) ATTR_NONNULL(1, 2); + const struct Main *bmain, struct Scene *scene, + const ViewLayer *layer_unset, ViewLayer *layer_new) ATTR_NONNULL(1, 2); struct WorkSpaceLayout *ED_workspace_layout_add( struct WorkSpace *workspace, struct wmWindow *win, diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index 49e85600819..8761f2c5361 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -76,9 +76,9 @@ struct SnapObjectParams { typedef struct SnapObjectContext SnapObjectContext; SnapObjectContext *ED_transform_snap_object_context_create( - struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine, int flag); + struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine_type, int flag); SnapObjectContext *ED_transform_snap_object_context_create_view3d( - struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine, int flag, + struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine_type, int flag, /* extra args for view3d */ const struct ARegion *ar, const struct View3D *v3d); void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index feb3686db9f..69061bdcd26 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -78,7 +78,7 @@ typedef struct ViewContext { struct Depsgraph *depsgraph; struct Scene *scene; struct ViewLayer *view_layer; - struct RenderEngineType *engine; + struct RenderEngineType *engine_type; struct Object *obact; struct Object *obedit; struct ARegion *ar; diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 51a98c47718..9a816f21fb8 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -73,6 +73,7 @@ struct bNodeSocket; struct wmDropBox; struct wmDrag; struct wmEvent; +struct wmMsgBus; typedef struct uiBut uiBut; typedef struct uiBlock uiBlock; @@ -183,6 +184,8 @@ enum { UI_BUT_UPDATE_DELAY = (1 << 28), /* don't run updates while dragging (needed in rare cases). */ UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */ UI_BUT_VALUE_CLEAR = (1 << 30), /* show 'x' icon to clear/unlink value of text or search button */ + + UI_BUT_OVERRIDEN = (1 << 31), /* RNA property of the button is overriden from linked reference data. */ }; #define UI_PANEL_WIDTH 340 @@ -901,6 +904,8 @@ uiLayout *UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int s void UI_block_layout_set_current(uiBlock *block, uiLayout *layout); void UI_block_layout_resolve(uiBlock *block, int *x, int *y); +void UI_region_message_subscribe(struct ARegion *ar, struct wmMsgBus *mbus); + uiBlock *uiLayoutGetBlock(uiLayout *layout); void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 09007681455..a5ef2943387 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -41,6 +41,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_userdef_types.h" +#include "DNA_workspace_types.h" #include "BLI_math.h" #include "BLI_listbase.h" @@ -69,11 +70,14 @@ #include "WM_api.h" #include "WM_types.h" #include "wm_subwindow.h" +#include "WM_message.h" #include "RNA_access.h" #include "BPY_extern.h" +#include "ED_screen.h" + #include "IMB_colormanagement.h" #include "interface_intern.h" @@ -1216,6 +1220,20 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) } } +void ui_but_override_flag(uiBut *but) +{ + bool is_overridden; + + RNA_property_override_status(&but->rnapoin, but->rnaprop, but->rnaindex, NULL, &is_overridden, NULL, NULL); + + if (is_overridden) { + but->flag |= UI_BUT_OVERRIDEN; + } + else { + but->flag &= ~UI_BUT_OVERRIDEN; + } +} + void UI_block_update_from_old(const bContext *C, uiBlock *block) { uiBut *but_old; @@ -1280,6 +1298,7 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x } ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f); + ui_but_override_flag(but); } @@ -1438,6 +1457,40 @@ void UI_block_draw(const bContext *C, uiBlock *block) ui_draw_links(block); } +static void ui_block_message_subscribe(ARegion *ar, struct wmMsgBus *mbus, uiBlock *block) +{ + uiBut *but_prev = NULL; + /* possibly we should keep the region this block is contained in? */ + for (uiBut *but = block->buttons.first; but; but = but->next) { + if (but->rnapoin.type && but->rnaprop) { + /* quick check to avoid adding buttons representing a vector, multiple times. */ + if ((but_prev && + (but_prev->rnaprop == but->rnaprop) && + (but_prev->rnapoin.type == but->rnapoin.type) && + (but_prev->rnapoin.data == but->rnapoin.data) && + (but_prev->rnapoin.id.data == but->rnapoin.id.data)) == false) + { + /* TODO: could make this into utility function. */ + WM_msg_subscribe_rna( + mbus, &but->rnapoin, but->rnaprop, + &(const wmMsgSubscribeValue){ + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }, __func__); + but_prev = but; + } + } + } +} + +void UI_region_message_subscribe(ARegion *ar, struct wmMsgBus *mbus) +{ + for (uiBlock *block = ar->uiblocks.first; block; block = block->next) { + ui_block_message_subscribe(ar, mbus, block); + } +} + /* ************* EVENTS ************* */ /** diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 908fa19e3b1..53505fc39a4 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -6800,6 +6800,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) MenuType *mt = WM_menutype_find("WM_MT_button_context", true); bool is_array, is_array_component; uiStringInfo label = {BUT_GET_LABEL, NULL}; + wmOperatorType *ot; + PointerRNA op_ptr; /* if ((but->rnapoin.data && but->rnaprop) == 0 && but->optype == NULL)*/ /* return 0;*/ @@ -6826,11 +6828,11 @@ static bool ui_but_menu(bContext *C, uiBut *but) const PropertySubType subtype = RNA_property_subtype(prop); bool is_anim = RNA_property_animateable(ptr, prop); bool is_editable = RNA_property_editable(ptr, prop); + bool is_overridable; /*bool is_idprop = RNA_property_is_idprop(prop);*/ /* XXX does not work as expected, not strictly needed */ bool is_set = RNA_property_is_set(ptr, prop); - /* Set the (button_pointer, button_prop) and pointer data for Python access to the hovered ui element. */ - uiLayoutSetContextFromBut(layout, but); + RNA_property_override_status(ptr, prop, -1, &is_overridable, NULL, NULL, NULL); /* second slower test, saved people finding keyframe items in menus when its not possible */ if (is_anim) @@ -6959,11 +6961,57 @@ static bool ui_but_menu(bContext *C, uiBut *but) ICON_NONE, "ANIM_OT_keyingset_button_remove"); } } - + + if (is_overridable) { + /* Override Operators */ + uiItemS(layout); + + if (but->flag & UI_BUT_OVERRIDEN) { + if (is_array_component) { + ot = WM_operatortype_find("UI_OT_override_type_set_button", false); + uiItemFullO_ptr(layout, ot, "Overrides Type", ICON_NONE, + NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_boolean_set(&op_ptr, "all", true); + uiItemFullO_ptr(layout, ot, "Single Override Type", ICON_NONE, + NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_boolean_set(&op_ptr, "all", false); + + uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Overrides"), + ICON_X, "UI_OT_override_remove_button", "all", true); + uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Single Override"), + ICON_X, "UI_OT_override_remove_button", "all", false); + } + else { + uiItemFullO(layout, "UI_OT_override_type_set_button", "Override Type", ICON_NONE, + NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_boolean_set(&op_ptr, "all", false); + + uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Override"), + ICON_X, "UI_OT_override_remove_button", "all", true); + } + } + else { + if (is_array_component) { + ot = WM_operatortype_find("UI_OT_override_type_set_button", false); + uiItemFullO_ptr(layout, ot, "Define Overrides", ICON_NONE, + NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_boolean_set(&op_ptr, "all", true); + uiItemFullO_ptr(layout, ot, "Define Single Override", ICON_NONE, + NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_boolean_set(&op_ptr, "all", false); + } + else { + uiItemFullO(layout, "UI_OT_override_type_set_button", "Define Override", ICON_NONE, + NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_boolean_set(&op_ptr, "all", false); + } + } + } + uiItemS(layout); - + /* Property Operators */ - + /* Copy Property Value * Paste Property Value */ @@ -8241,6 +8289,7 @@ void UI_context_update_anim_flag(const bContext *C) for (block = ar->uiblocks.first; block; block = block->next) { for (but = block->buttons.first; but; but = but->next) { ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f); + ui_but_override_flag(but); ED_region_tag_redraw(ar); if (but->active) { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 424063953a7..6f450093d30 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -514,6 +514,7 @@ extern bool ui_but_supports_cycling(const uiBut *but) ATTR_WARN_UNUSED_RESULT; extern int ui_but_is_pushed_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT; extern int ui_but_is_pushed(uiBut *but) ATTR_WARN_UNUSED_RESULT; +void ui_but_override_flag(uiBut *but); extern void ui_block_bounds_calc(uiBlock *block); extern void ui_block_translate(uiBlock *block, int x, int y); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 5913f1c48f5..bbcd10270d5 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -46,6 +46,7 @@ #include "BKE_layer.h" #include "BKE_screen.h" #include "BKE_global.h" +#include "BKE_library_override.h" #include "BKE_node.h" #include "BKE_text.h" /* for UI_OT_reports_to_text */ #include "BKE_report.h" @@ -452,6 +453,215 @@ static void UI_OT_unuse_property_button(wmOperatorType *ot) ot->flag = OPTYPE_UNDO; } + + + + +/* Note that we use different values for UI/UX than 'real' override operations, user does not care + * whether it's added or removed for the differential operation e.g. */ +enum { + UIOverride_Type_NOOP = 0, + UIOverride_Type_Replace = 1, + UIOverride_Type_Difference = 2, /* Add/subtract */ + UIOverride_Type_Factor = 3, /* Multiply */ + /* TODO: should/can we expose insert/remove ones for collections? Doubt it... */ +}; + +static EnumPropertyItem override_type_items[] = { + {UIOverride_Type_NOOP, "NOOP", 0, "NoOp", + "'No-Operation', place holder preventing automatic override to ever affect the property"}, + {UIOverride_Type_Replace, "REPLACE", 0, "Replace", "Completely replace value from linked data by local one"}, + {UIOverride_Type_Difference, "DIFFERENCE", 0, "Difference", "Store difference to linked data value"}, + {UIOverride_Type_Factor, "FACTOR", 0, "Factor", "Store factor to linked data value (useful e.g. for scale)"}, + {0, NULL, 0, NULL, NULL} +}; + + +static int override_type_set_button_poll(bContext *C) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index; + bool is_overridable; + + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + + RNA_property_override_status(&ptr, prop, index, &is_overridable, NULL, NULL, NULL); + + return (ptr.data && prop && is_overridable); +} + +static int override_type_set_button_exec(bContext *C, wmOperator *op) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index; + bool created; + const bool all = RNA_boolean_get(op->ptr, "all"); + const int op_type = RNA_enum_get(op->ptr, "type"); + + short operation; + + switch (op_type) { + case UIOverride_Type_NOOP: + operation = IDOVERRIDESTATIC_OP_NOOP; + break; + case UIOverride_Type_Replace: + operation = IDOVERRIDESTATIC_OP_REPLACE; + break; + case UIOverride_Type_Difference: + operation = IDOVERRIDESTATIC_OP_ADD; /* override code will automatically switch to subtract if needed. */ + break; + case UIOverride_Type_Factor: + operation = IDOVERRIDESTATIC_OP_MULTIPLY; + break; + default: + operation = IDOVERRIDESTATIC_OP_REPLACE; + BLI_assert(0); + break; + } + + /* try to reset the nominated setting to its default value */ + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + + BLI_assert(ptr.id.data != NULL); + + if (all) { + index = -1; + } + + IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_get( + &ptr, prop, operation, index, true, NULL, &created); + if (!created) { + opop->operation = operation; + } + + return operator_button_property_finish(C, &ptr, prop); +} + +static int override_type_set_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT); +} + +static void UI_OT_override_type_set_button(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Define Override Type"; + ot->idname = "UI_OT_override_type_set_button"; + ot->description = "Create an override operation, or set the type of an existing one"; + + /* callbacks */ + ot->poll = override_type_set_button_poll; + ot->exec = override_type_set_button_exec; + ot->invoke = override_type_set_button_invoke; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); + ot->prop = RNA_def_enum(ot->srna, "type", override_type_items, UIOverride_Type_Replace, + "Type", "Type of override operation"); + /* TODO: add itemf callback, not all aoptions are available for all data types... */ +} + + +static int override_remove_button_poll(bContext *C) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index; + bool is_overridden; + + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + + RNA_property_override_status(&ptr, prop, index, NULL, &is_overridden, NULL, NULL); + + return (ptr.data && ptr.id.data && prop && is_overridden); +} + +static int override_remove_button_exec(bContext *C, wmOperator *op) +{ + PointerRNA ptr, id_refptr, src; + PropertyRNA *prop; + int index; + const bool all = RNA_boolean_get(op->ptr, "all"); + + /* try to reset the nominated setting to its default value */ + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + + ID *id = ptr.id.data; + IDOverrideStaticProperty *oprop = RNA_property_override_property_find(&ptr, prop); + BLI_assert(oprop != NULL); + BLI_assert(id != NULL && id->override_static != NULL); + + const bool is_template = (id->override_static->reference == NULL); + + /* We need source (i.e. linked data) to restore values of deleted overrides... + * If this is an override template, we obviously do not need to restore anything. */ + if (!is_template) { + RNA_id_pointer_create(id->override_static->reference, &id_refptr); + if (!RNA_path_resolve(&id_refptr, oprop->rna_path, &src, NULL)) { + BLI_assert(0 && "Failed to create matching source (linked data) RNA pointer"); + } + } + + if (!all && index != -1) { + bool is_strict_find; + /* Remove override operation for given item, add singular operations for the other items as needed. */ + IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find( + oprop, NULL, NULL, index, index, false, &is_strict_find); + BLI_assert(opop != NULL); + if (!is_strict_find) { + /* No specific override operation, we have to get generic one, + * and create item-specific override operations for all but given index, before removing generic one. */ + for (int idx = RNA_property_array_length(&ptr, prop); idx--; ) { + if (idx != index) { + BKE_override_static_property_operation_get(oprop, opop->operation, NULL, NULL, idx, idx, true, NULL, NULL); + } + } + } + BKE_override_static_property_operation_delete(oprop, opop); + if (!is_template) { + RNA_property_copy(&ptr, &src, prop, index); + } + if (BLI_listbase_is_empty(&oprop->operations)) { + BKE_override_static_property_delete(id->override_static, oprop); + } + } + else { + /* Just remove whole generic override operation of this property. */ + BKE_override_static_property_delete(id->override_static, oprop); + if (!is_template) { + RNA_property_copy(&ptr, &src, prop, -1); + } + } + + return operator_button_property_finish(C, &ptr, prop); +} + +static void UI_OT_override_remove_button(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Override"; + ot->idname = "UI_OT_override_remove_button"; + ot->description = "Remove an override operation"; + + /* callbacks */ + ot->poll = override_remove_button_poll; + ot->exec = override_remove_button_exec; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); +} + + + + /* Copy To Selected Operator ------------------------ */ bool UI_context_copy_to_selected_list( @@ -1243,6 +1453,8 @@ void ED_operatortypes_ui(void) WM_operatortype_append(UI_OT_unset_property_button); WM_operatortype_append(UI_OT_use_property_button); WM_operatortype_append(UI_OT_unuse_property_button); + WM_operatortype_append(UI_OT_override_type_set_button); + WM_operatortype_append(UI_OT_override_remove_button); WM_operatortype_append(UI_OT_copy_to_selected_button); WM_operatortype_append(UI_OT_reports_to_textblock); /* XXX: temp? */ WM_operatortype_append(UI_OT_drop_color); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index c7e1a60b05c..78874076b92 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1075,8 +1075,10 @@ void uiTemplateSearch( const char *newop, const char *unlinkop) { TemplateSearch *template_search = template_search_setup(ptr, propname, searchptr, searchpropname); - template_search_buttons(C, layout, template_search, newop, unlinkop); - MEM_freeN(template_search); + if (template_search != NULL) { + template_search_buttons(C, layout, template_search, newop, unlinkop); + MEM_freeN(template_search); + } } void uiTemplateSearchPreview( @@ -1088,13 +1090,15 @@ void uiTemplateSearchPreview( { TemplateSearch *template_search = template_search_setup(ptr, propname, searchptr, searchpropname); - template_search->use_previews = true; - template_search->preview_rows = rows; - template_search->preview_cols = cols; + if (template_search != NULL) { + template_search->use_previews = true; + template_search->preview_rows = rows; + template_search->preview_cols = cols; - template_search_buttons(C, layout, template_search, newop, unlinkop); + template_search_buttons(C, layout, template_search, newop, unlinkop); - MEM_freeN(template_search); + MEM_freeN(template_search); + } } /********************* RNA Path Builder Template ********************/ diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 375f4f95697..8c894c7852e 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1710,6 +1710,8 @@ static struct uiWidgetStateColors wcol_state_colors = { {215, 211, 75, 255}, {180, 0, 255, 255}, {153, 0, 230, 255}, + {74, 137, 137, 255}, + {49, 112, 112, 255}, 0.5f, 0.0f }; @@ -2062,6 +2064,8 @@ static void widget_state(uiWidgetType *wt, int state) widget_state_blend(wt->wcol.inner, wcol_state->inner_anim_sel, wcol_state->blend); else if (state & UI_BUT_DRIVEN) widget_state_blend(wt->wcol.inner, wcol_state->inner_driven_sel, wcol_state->blend); + else if (state & UI_BUT_OVERRIDEN) + widget_state_blend(wt->wcol.inner, wcol_state->inner_overridden_sel, wcol_state->blend); copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel); @@ -2075,6 +2079,8 @@ static void widget_state(uiWidgetType *wt, int state) widget_state_blend(wt->wcol.inner, wcol_state->inner_anim, wcol_state->blend); else if (state & UI_BUT_DRIVEN) widget_state_blend(wt->wcol.inner, wcol_state->inner_driven, wcol_state->blend); + else if (state & UI_BUT_OVERRIDEN) + widget_state_blend(wt->wcol.inner, wcol_state->inner_overridden, wcol_state->blend); if (state & UI_ACTIVE) { /* mouse over? */ wt->wcol.inner[0] = wt->wcol.inner[0] >= 240 ? 255 : wt->wcol.inner[0] + 15; @@ -2120,7 +2126,9 @@ static void widget_state_numslider(uiWidgetType *wt, int state) widget_state_blend(wt->wcol.item, wcol_state->inner_anim_sel, blend); else if (state & UI_BUT_DRIVEN) widget_state_blend(wt->wcol.item, wcol_state->inner_driven_sel, blend); - + else if (state & UI_BUT_OVERRIDEN) + widget_state_blend(wt->wcol.item, wcol_state->inner_overridden_sel, blend); + if (state & UI_SELECT) SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown); } @@ -2131,6 +2139,8 @@ static void widget_state_numslider(uiWidgetType *wt, int state) widget_state_blend(wt->wcol.item, wcol_state->inner_anim, blend); else if (state & UI_BUT_DRIVEN) widget_state_blend(wt->wcol.item, wcol_state->inner_driven, blend); + else if (state & UI_BUT_OVERRIDEN) + widget_state_blend(wt->wcol.item, wcol_state->inner_overridden, blend); } } @@ -3157,7 +3167,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat ui_but_v3_get(but, col); - if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) { + if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_OVERRIDEN | UI_BUT_REDALERT)) { /* draw based on state - color for keyed etc */ widgetbase_draw(&wtb, wcol); diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index e541df8ffa3..d4d7d92d5ad 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -58,8 +58,7 @@ #define MVAL_PIXEL_MARGIN 5.0f -/* until implement profile = 0 case, need to clamp somewhat above zero */ -#define PROFILE_HARD_MIN 0.15f +#define PROFILE_HARD_MIN 0.0f #define SEGMENTS_HARD_MAX 1000 @@ -623,6 +622,7 @@ void MESH_OT_bevel(wmOperatorType *ot) RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures"); prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f); RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); RNA_def_int(ot->srna, "segments", 1, 1, SEGMENTS_HARD_MAX, "Segments", "Segments for curved edge", 1, 8); RNA_def_float(ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile", "Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f); diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index 3e0747f055f..afe52ec69f4 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -80,8 +80,10 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C) { InsetData *opdata = op->customdata; - const char *str = IFACE_("Confirm: Enter/LClick, Cancel: (Esc/RClick), Thickness: %s, " - "Depth (Ctrl to tweak): %s (%s), Outset (O): (%s), Boundary (B): (%s), Individual (I): (%s)"); + const char *str = IFACE_( + "Confirm: Enter/LClick, Cancel: (Esc/RClick), Thickness: %s, " + "Depth (Ctrl to tweak): %s (%s), Outset (O): (%s), Boundary (B): (%s), Individual (I): (%s)" + ); char msg[UI_MAX_DRAW_STR]; ScrArea *sa = CTX_wm_area(C); @@ -141,7 +143,8 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal) ARegion *ar = CTX_wm_region(C); opdata->mesh_backup = EDBM_redo_state_store(em); - opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); + opdata->draw_handle_pixel = ED_region_draw_cb_activate( + ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); G.moving = G_TRANSFORM_EDIT; if (v3d) { opdata->twtype = v3d->twtype; @@ -506,16 +509,27 @@ void MESH_OT_inset(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; /* properties */ - RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries"); - RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness"); - RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry"); - RNA_def_boolean(ot->srna, "use_edge_rail", false, "Edge Rail", "Inset the region along existing edges"); + RNA_def_boolean( + ot->srna, "use_boundary", + true, "Boundary", "Inset face boundaries"); + RNA_def_boolean( + ot->srna, "use_even_offset", + true, "Offset Even", "Scale the offset to give more even thickness"); + RNA_def_boolean( + ot->srna, "use_relative_offset", + false, "Offset Relative", "Scale the offset by surrounding geometry"); + RNA_def_boolean( + ot->srna, "use_edge_rail", + false, "Edge Rail", "Inset the region along existing edges"); prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, 0.0f, 1e12f, "Thickness", "", 0.0f, 10.0f); /* use 1 rather then 10 for max else dragging the button moves too far */ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_float_distance(ot->srna, "depth", 0.0f, -1e12f, 1e12f, "Depth", "", -10.0f, 10.0f); RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.01, 4); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); RNA_def_boolean(ot->srna, "use_outset", false, "Outset", "Outset rather than inset"); RNA_def_boolean(ot->srna, "use_select_inset", false, "Select Outer", "Select the new inset faces"); diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 876d63ef64a..3ab56f2ebcb 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -534,9 +534,6 @@ static int ringsel_init(bContext *C, wmOperator *op, bool do_cut) lcd->num.unit_type[0] = B_UNIT_NONE; lcd->num.unit_type[1] = B_UNIT_NONE; - /* XXX, temp, workaround for [# ] */ - EDBM_mesh_ensure_valid_dm_hack(scene, lcd->em); - em_setup_viewcontext(C, &lcd->vc); ED_region_tag_redraw(lcd->ar); diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c index bfabd64396f..f398f087da9 100644 --- a/source/blender/editors/mesh/editmesh_polybuild.c +++ b/source/blender/editors/mesh/editmesh_polybuild.c @@ -132,7 +132,7 @@ static int edbm_polybuild_face_at_cursor_invoke( BMEdge *e_iter = v_act->e; do { if ((BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) && - (allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter))) + (allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter))) { if (i == 2) { e_pair[0] = e_pair[1] = NULL; @@ -489,9 +489,9 @@ static int edbm_polybuild_hover_invoke( /* pass */ } else if (vc.win->tweak || - (vc.win->eventstate->check_click && - vc.win->eventstate->prevval == KM_PRESS && - ISMOUSE(vc.win->eventstate->prevtype))) + (vc.win->eventstate->check_click && + vc.win->eventstate->prevval == KM_PRESS && + ISMOUSE(vc.win->eventstate->prevtype))) { return OPERATOR_PASS_THROUGH; } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 0a0a8ff2de3..3e0afd3095e 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -640,9 +640,17 @@ BMEdge *EDBM_edge_find_nearest_ex( unsigned int index; BMEdge *eed; + /* Make sure that the edges also are considered to find nearest. + * TODO: cleanup: add `selectmode` as a parameter */ + const short ts_selectmode = vc->scene->toolsettings->selectmode; + vc->scene->toolsettings->selectmode |= SCE_SELECT_EDGE; + /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ ED_view3d_backbuf_validate(eval_ctx, vc); + /* restore `selectmode` */ + vc->scene->toolsettings->selectmode = ts_selectmode; + index = ED_view3d_backbuf_sample_rect(eval_ctx, vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test); eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL; @@ -1583,9 +1591,17 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de mvalf[1] = (float)(vc.mval[1] = mval[1]); em = vc.em; + /* Make sure that the edges are also considered for selection. + * TODO: cleanup: add `selectmode` as a parameter */ + const short ts_selectmode = vc.scene->toolsettings->selectmode; + vc.scene->toolsettings->selectmode |= SCE_SELECT_EDGE; + /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */ ED_view3d_backbuf_validate(&eval_ctx, &vc); + /* restore `selectmode` */ + vc.scene->toolsettings->selectmode = ts_selectmode; + eed = EDBM_edge_find_nearest_ex(&eval_ctx, &vc, &dist, NULL, true, true, NULL); if (eed == NULL) { return false; diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 74bd4e978e7..75a13a916e6 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -311,7 +311,7 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) ED_view3d_init_mats_rv3d(obedit, ar->regiondata); struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine(C), 0, + CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine_type(C), 0, ar, CTX_wm_view3d(C)); BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 230f46abad1..27fe93b049a 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -53,7 +53,7 @@ #include "DEG_depsgraph.h" -#include "BKE_object.h" /* XXX. only for EDBM_mesh_ensure_valid_dm_hack() which will be removed */ +#include "BKE_object.h" /* XXX. only for EDBM_mesh_load(). */ #include "WM_api.h" #include "WM_types.h" @@ -108,21 +108,6 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess) BKE_editmesh_tessface_calc(em); } -/* hack to workaround multiple operators being called within the same event loop without an update - * see: [#31811] */ -void EDBM_mesh_ensure_valid_dm_hack(Scene *scene, BMEditMesh *em) -{ - if ((((ID *)em->ob->data)->tag & LIB_TAG_ID_RECALC) || - (em->ob->recalc & OB_RECALC_DATA)) - { - /* since we may not have done selection flushing */ - if ((em->ob->recalc & OB_RECALC_DATA) == 0) { - DEG_id_tag_update(&em->ob->id, OB_RECALC_DATA); - } - BKE_object_handle_update(G.main->eval_ctx, scene, em->ob); - } -} - void EDBM_mesh_normals_update(BMEditMesh *em) { BM_mesh_normals_update(em->bm); @@ -413,6 +398,7 @@ void EDBM_mesh_load(Object *ob) * of freed data on scene update, especially in cases when there are dependency * cycles. */ + /* for (Object *other_object = G.main->object.first; other_object != NULL; other_object = other_object->id.next) @@ -421,6 +407,7 @@ void EDBM_mesh_load(Object *ob) BKE_object_free_derived_caches(other_object); } } + */ } /** diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 77b30951dee..e8807432328 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -449,10 +449,13 @@ Object *ED_object_add_type( ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_CHARACTER | OB_OCCLUDER | OB_DYNAMIC | OB_NAVMESH); /* copied from rna_object.c */ } + /* TODO(sergey): This is weird to manually tag objects for update, better to + * use DEG_id_tag_update here perhaps. + */ DEG_id_type_tag(bmain, ID_OB); DEG_relations_tag_update(bmain); - if (ob->data) { - ED_render_id_flush_update(bmain, ob->data); + if (ob->data != NULL) { + DEG_id_tag_update_ex(bmain, (ID *)ob->data, DEG_TAG_EDITORS_UPDATE); } if (enter_editmode) @@ -1218,7 +1221,7 @@ void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob) DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_BASE_FLAGS_UPDATE); object_delete_check_glsl_update(ob); - BKE_collections_object_remove(bmain, scene, ob, true); + BKE_collections_object_remove(bmain, &scene->id, ob, true); } static int object_delete_exec(bContext *C, wmOperator *op) @@ -2340,8 +2343,8 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, ViewLayer *view_layer, /* DAG_relations_tag_update(bmain); */ /* caller must do */ - if (ob->data) { - ED_render_id_flush_update(bmain, ob->data); + if (ob->data != NULL) { + DEG_id_tag_update_ex(bmain, (ID *)ob->data, DEG_TAG_EDITORS_UPDATE); } BKE_main_id_clear_newpoins(bmain); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 804d0ed1f0d..5697c48d381 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1516,15 +1516,13 @@ bool ED_object_mode_compat_set(bContext *C, Object *ob, int mode, ReportList *re { bool ok; if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) { - WorkSpace *workspace = CTX_wm_workspace(C); const char *opstring = object_mode_op_string(ob->mode); WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); #ifdef USE_WORKSPACE_MODE - BKE_workspace_object_mode_set(workspace, ob->mode); -#else - UNUSED_VARS(workspace); + BKE_workspace_object_mode_set(CTX_wm_workspace(C), CTX_data_scene(C), ob->mode); #endif + ok = ELEM(ob->mode, mode, OB_MODE_OBJECT); if (!ok) { wmOperatorType *ot = WM_operatortype_find(opstring, false); @@ -1648,7 +1646,7 @@ void ED_object_toggle_modes(bContext *C, int mode) #ifdef USE_WORKSPACE_MODE Object *ob = CTX_data_active_object(C); if (ob) { - BKE_workspace_object_mode_set(workspace, ob->mode); + BKE_workspace_object_mode_set(workspace, CTX_data_scene(C), ob->mode); } #endif } diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 3e655fa04a4..c38a7d58904 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -68,6 +68,7 @@ void OBJECT_OT_track_clear(struct wmOperatorType *ot); void OBJECT_OT_slow_parent_set(struct wmOperatorType *ot); void OBJECT_OT_slow_parent_clear(struct wmOperatorType *ot); void OBJECT_OT_make_local(struct wmOperatorType *ot); +void OBJECT_OT_make_override(struct wmOperatorType *ot); void OBJECT_OT_make_single_user(struct wmOperatorType *ot); void OBJECT_OT_make_links_scene(struct wmOperatorType *ot); void OBJECT_OT_make_links_data(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index c87df877d5c..ceea3b9c0ac 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -84,6 +84,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_slow_parent_set); WM_operatortype_append(OBJECT_OT_slow_parent_clear); WM_operatortype_append(OBJECT_OT_make_local); + WM_operatortype_append(OBJECT_OT_make_override); WM_operatortype_append(OBJECT_OT_make_single_user); WM_operatortype_append(OBJECT_OT_make_links_scene); WM_operatortype_append(OBJECT_OT_make_links_data); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 9854b61813b..436364ec6c3 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -77,8 +77,10 @@ #include "BKE_lattice.h" #include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" +#include "BKE_lightprobe.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" @@ -340,17 +342,15 @@ static int make_proxy_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Object *ob, *gob = ED_object_active_context(C); - GroupObject *go; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); if (gob->dup_group != NULL) { - go = BLI_findlink(&gob->dup_group->gobject, RNA_enum_get(op->ptr, "object")); - ob = go->ob; + Base *base = BLI_findlink(&gob->dup_group->view_layer->object_bases, RNA_enum_get(op->ptr, "object")); + ob = base->object; } else { ob = gob; - gob = NULL; } if (ob) { @@ -395,17 +395,18 @@ static const EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA int totitem = 0; int i = 0; Object *ob = ED_object_active_context(C); - GroupObject *go; if (!ob || !ob->dup_group) return DummyRNA_DEFAULT_items; /* find the object to affect */ - for (go = ob->dup_group->gobject.first; go; go = go->next) { - item_tmp.identifier = item_tmp.name = go->ob->id.name + 2; + FOREACH_GROUP_OBJECT(ob->dup_group, object) + { + item_tmp.identifier = item_tmp.name = object->id.name + 2; item_tmp.value = i++; RNA_enum_item_add(&item, &totitem, &item_tmp); } + FOREACH_GROUP_OBJECT_END RNA_enum_item_end(&item, &totitem); *r_free = true; @@ -1366,10 +1367,10 @@ static int make_links_scene_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - SceneCollection *sc_to = BKE_collection_master(scene_to); + SceneCollection *sc_to = BKE_collection_master(&scene_to->id); CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - BKE_collection_object_add(scene_to, sc_to, base->object); + BKE_collection_object_add(&scene_to->id, sc_to, base->object); } CTX_DATA_END; @@ -1689,12 +1690,11 @@ static void single_object_users_scene_collection(Main *bmain, Scene *scene, Scen static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups) { Group *group, *groupn; - GroupObject *go; clear_sca_new_poins(); /* BGE logic */ /* duplicate all the objects of the scene */ - SceneCollection *msc = BKE_collection_master(scene); + SceneCollection *msc = BKE_collection_master(&scene->id); single_object_users_scene_collection(bmain, scene, msc, flag, copy_groups); /* loop over ViewLayers and assign the pointers accordingly */ @@ -1706,22 +1706,26 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in /* duplicate groups that consist entirely of duplicated objects */ for (group = bmain->group.first; group; group = group->id.next) { - if (copy_groups && group->gobject.first) { + if (copy_groups && group->view_layer->object_bases.first) { bool all_duplicated = true; - for (go = group->gobject.first; go; go = go->next) { - if (!(go->ob && (go->ob->id.newid))) { + FOREACH_GROUP_OBJECT(group, object) + { + if (object->id.newid == NULL) { all_duplicated = false; break; } } + FOREACH_GROUP_OBJECT_END if (all_duplicated) { groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group)); - for (go = groupn->gobject.first; go; go = go->next) { - go->ob = (Object *)go->ob->id.newid; + FOREACH_GROUP_BASE(groupn, base) + { + base->object = (Object *)base->object->id.newid; } + FOREACH_GROUP_BASE_END } } } @@ -1840,9 +1844,15 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer case OB_SPEAKER: ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data)); break; + case OB_LIGHTPROBE: + ob->data = ID_NEW_SET(ob->data, BKE_lightprobe_copy(bmain, ob->data)); + break; default: - if (G.debug & G_DEBUG) - printf("ERROR %s: can't copy %s\n", __func__, id->name); + printf("ERROR %s: can't copy %s\n", __func__, id->name); + BLI_assert(!"This should never happen."); + + /* We need to end the FOREACH_OBJECT_FLAG iterator to prevent memory leak. */ + BKE_scene_objects_iterator_end(&iter_macro); return; } @@ -2143,7 +2153,7 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene, id_us_plus(&ob->id); - BKE_collection_object_add(scene, sc, ob); + BKE_collection_object_add(&scene->id, sc, ob); base = BKE_view_layer_base_find(view_layer, ob); base->flag |= BASE_SELECTED; BKE_scene_object_base_flag_sync_from_base(base); @@ -2325,6 +2335,44 @@ void OBJECT_OT_make_local(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", ""); } +static int make_override_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + Object *locobj, *refobj = CTX_data_active_object(C); + + locobj = (Object *)BKE_override_static_create_from(bmain, &refobj->id); + UNUSED_VARS(locobj); + + WM_event_add_notifier(C, NC_WINDOW, NULL); + + return OPERATOR_FINISHED; +} + +static int make_override_poll(bContext *C) +{ + Object *obact = CTX_data_active_object(C); + + /* Object must be directly linked to be overridable. */ + return (ED_operator_objectmode(C) && obact && obact->id.lib != NULL && obact->id.tag & LIB_TAG_EXTERN); +} + +void OBJECT_OT_make_override(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Make Override"; + ot->description = "Make local override of this library linked data-block"; + ot->idname = "OBJECT_OT_make_override"; + + /* api callbacks */ + ot->exec = make_override_exec; + ot->poll = make_override_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ +} + enum { MAKE_SINGLE_USER_ALL = 1, MAKE_SINGLE_USER_SELECTED = 2, diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 47e63cb43e5..552380cebdb 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -123,8 +123,7 @@ void ED_object_base_activate(bContext *C, Base *base) if (base) { #ifdef USE_WORKSPACE_MODE - WorkSpace *workspace = CTX_wm_workspace(C); - BKE_workspace_object_mode_set(workspace, base->object->mode); + BKE_workspace_object_mode_set(CTX_wm_workspace(C), CTX_data_scene(C), base->object->mode); #endif WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, view_layer); } diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 2c659d2b985..4e75ca3e6f1 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -832,7 +832,7 @@ static void clean_viewport_memory(Main *bmain, Scene *scene) } } - for (SETLOOPER_SET_ONLY(scene, sce_iter, base)) { + for (SETLOOPER_SET_ONLY(scene, sce_iter, base)) { clean_viewport_memory_base(base); } } diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 8956ef79958..a391b13a000 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -70,6 +70,8 @@ #include "ED_render.h" #include "ED_view3d.h" +#include "DEG_depsgraph.h" + #include "WM_api.h" #include "render_intern.h" // own include @@ -78,10 +80,13 @@ extern Material defmaterial; /***************************** Render Engines ********************************/ -void ED_render_scene_update(Main *bmain, Scene *scene, int updated) +void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int updated) { /* viewport rendering update on data changes, happens after depsgraph * updates if there was any change. context is set to the 3d view */ + Main *bmain = update_ctx->bmain; + Scene *scene = update_ctx->scene; + ViewLayer *view_layer = update_ctx->view_layer; bContext *C; wmWindowManager *wm; wmWindow *win; @@ -123,15 +128,11 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated) continue; for (ar = sa->regionbase.first; ar; ar = ar->next) { - RegionView3D *rv3d; - RenderEngine *engine; - - if (ar->regiontype != RGN_TYPE_WINDOW) + if (ar->regiontype != RGN_TYPE_WINDOW) { continue; - - rv3d = ar->regiondata; - engine = rv3d->render_engine; - + } + RegionView3D *rv3d = ar->regiondata; + RenderEngine *engine = rv3d->render_engine; /* call update if the scene changed, or if the render engine * tagged itself for update (e.g. because it was busy at the * time of the last update) */ @@ -145,13 +146,20 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated) engine->type->view_update(engine, C); } - else if ((RE_engines_find(view_render->engine_id)->flag & RE_USE_LEGACY_PIPELINE) == 0) { - if (updated) { - CTX_wm_screen_set(C, sc); - CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, ar); - - DRW_notify_view_update(C); + else { + RenderEngineType *engine_type = RE_engines_find(view_render->engine_id); + if ((engine_type->flag & RE_USE_LEGACY_PIPELINE) == 0) { + if (updated) { + DRW_notify_view_update( + (&(DRWUpdateContext){ + .bmain = bmain, + .scene = scene, + .view_layer = view_layer, + .ar = ar, + .v3d = (View3D *)sa->spacedata.first, + .engine_type = engine_type + })); + } } } } @@ -163,23 +171,6 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated) recursive_check = false; } -void ED_render_scene_update_pre(Main *bmain, Scene *scene, bool time) -{ - /* Blender internal might access to the data which is gonna to be freed - * by the scene update functions. This applies for example to simulation - * data like smoke and fire. - */ - if (time && !BKE_scene_use_new_shading_nodes(scene)) { - bScreen *sc; - ScrArea *sa; - for (sc = bmain->screen.first; sc; sc = sc->id.next) { - for (sa = sc->areabase.first; sa; sa = sa->next) { - ED_render_engine_area_exit(bmain, sa); - } - } - } -} - void ED_render_engine_area_exit(Main *bmain, ScrArea *sa) { /* clear all render engines in this area */ @@ -199,18 +190,21 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *sa) void ED_render_engine_changed(Main *bmain) { /* on changing the render engine type, clear all running render engines */ - bScreen *sc; - ScrArea *sa; - Scene *scene; - - for (sc = bmain->screen.first; sc; sc = sc->id.next) - for (sa = sc->areabase.first; sa; sa = sa->next) + for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) { + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { ED_render_engine_area_exit(bmain, sa); - + } + } RE_FreePersistentData(); - - for (scene = bmain->scene.first; scene; scene = scene->id.next) { - ED_render_id_flush_update(bmain, &scene->id); + /* Inform all render engines and draw managers. */ + DEGEditorUpdateContext update_ctx = {NULL}; + update_ctx.bmain = bmain; + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + update_ctx.scene = scene; + LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { + update_ctx.view_layer = view_layer; + ED_render_id_flush_update(&update_ctx, &scene->id); + } if (scene->nodetree) { ntreeCompositUpdateRLayers(scene->nodetree); } @@ -536,14 +530,18 @@ static void scene_changed(Main *bmain, Scene *scene) } } -void ED_render_id_flush_update(Main *bmain, ID *id) +void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, ID *id) { /* this can be called from render or baking thread when a python script makes * changes, in that case we don't want to do any editor updates, and making * GPU changes is not possible because OpenGL only works in the main thread */ - if (!BLI_thread_is_main()) + if (!BLI_thread_is_main()) { return; - + } + Main *bmain = update_ctx->bmain; + Scene *scene = update_ctx->scene; + ViewLayer *view_layer = update_ctx->view_layer; + /* Internal ID update handlers. */ switch (GS(id->name)) { case ID_MA: material_changed(bmain, (Material *)id); @@ -569,7 +567,42 @@ void ED_render_id_flush_update(Main *bmain, ID *id) render_engine_flag_changed(bmain, RE_ENGINE_UPDATE_OTHER); break; } - + /* Inform all draw managers about changes. + * + * TODO(sergey): This code is run for every updated ID, via flushing + * mechanism. How can we avoid iterating over the whole interface for + * every of those IDs? One of the ideas would be to call draw manager's + * ID update which is not bound to any of contexts. + */ + { + wmWindowManager *wm = bmain->wm.first; + for (wmWindow *win = wm->windows.first; win; win = win->next) { + bScreen *sc = WM_window_get_active_screen(win); + WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); + ViewRender *view_render = BKE_viewrender_get(win->scene, workspace); + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + if (sa->spacetype != SPACE_VIEW3D) { + continue; + } + for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype != RGN_TYPE_WINDOW) { + continue; + } + RenderEngineType *engine_type = RE_engines_find(view_render->engine_id); + DRW_notify_id_update( + (&(DRWUpdateContext){ + .bmain = bmain, + .scene = scene, + .view_layer = view_layer, + .ar = ar, + .v3d = (View3D *)sa->spacedata.first, + .engine_type = engine_type + }), + id); + } + } + } + } } diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c index c7f04a0e2f9..812f9a736bf 100644 --- a/source/blender/editors/scene/scene_edit.c +++ b/source/blender/editors/scene/scene_edit.c @@ -118,16 +118,20 @@ void ED_scene_exit(bContext *C) ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO); } +static ViewLayer *scene_change_get_new_view_layer(const WorkSpace *workspace, const Scene *scene_new) +{ + ViewLayer *layer_new = BKE_workspace_view_layer_get(workspace, scene_new); + return layer_new ? layer_new : BKE_view_layer_from_scene_get(scene_new); +} + void ED_scene_changed_update(Main *bmain, bContext *C, Scene *scene_new, const bScreen *active_screen) { - /* XXX Just using active scene render-layer for workspace when switching, - * but workspace should remember the last one set. Could store render-layer - * per window-workspace combination (using WorkSpaceDataRelation) */ - ViewLayer *layer_new = BLI_findlink(&scene_new->view_layers, scene_new->active_view_layer); + WorkSpace *workspace = CTX_wm_workspace(C); + ViewLayer *layer_new = scene_change_get_new_view_layer(workspace, scene_new); Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene_new, layer_new, true); CTX_data_scene_set(C, scene_new); - BKE_workspace_view_layer_set(CTX_wm_workspace(C), layer_new); + BKE_workspace_view_layer_set(workspace, layer_new, scene_new); BKE_scene_set_background(bmain, scene_new); DEG_graph_relations_update(depsgraph, bmain, scene_new, layer_new); DEG_on_visible_update(bmain, false); @@ -186,7 +190,8 @@ bool ED_scene_view_layer_delete( BLI_assert(BLI_listbase_is_empty(&scene->view_layers) == false); scene->active_view_layer = 0; - ED_workspace_view_layer_unset(bmain, layer, scene->view_layers.first); + ED_workspace_view_layer_unset(bmain, scene, layer, scene->view_layers.first); + BKE_workspace_view_layer_remove_references(bmain, layer); view_layer_remove_unset_nodetrees(bmain, scene, layer); BKE_view_layer_free(layer); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index e5ed2ff1d67..dbeac782e10 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -51,6 +51,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "wm_subwindow.h" #include "ED_screen.h" @@ -511,6 +512,33 @@ void ED_region_set(const bContext *C, ARegion *ar) ED_region_pixelspace(ar); } +/* Follow wmMsgNotifyFn spec */ +void ED_region_do_msg_notify_tag_redraw( + bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val) +{ + ARegion *ar = msg_val->owner; + ED_region_tag_redraw(ar); + + /* This avoids _many_ situations where header/properties control display settings. + * the common case is space properties in the header */ + if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_UI)) { + while (ar && ar->prev) { + ar = ar->prev; + } + for (; ar; ar = ar->next) { + if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_CHANNELS)) { + ED_region_tag_redraw(ar); + } + } + } +} +/* Follow wmMsgNotifyFn spec */ +void ED_area_do_msg_notify_tag_refresh( + bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val) +{ + ScrArea *sa = msg_val->user_data; + ED_area_tag_refresh(sa); +} /* only exported for WM */ void ED_region_do_draw(bContext *C, ARegion *ar) @@ -589,6 +617,37 @@ void ED_region_do_draw(bContext *C, ARegion *ar) region_draw_emboss(ar, &ar->winrct); } } + + /* We may want to detach message-subscriptions from drawing. */ + { + WorkSpace *workspace = CTX_wm_workspace(C); + wmWindowManager *wm = CTX_wm_manager(C); + bScreen *screen = WM_window_get_active_screen(win); + Scene *scene = CTX_data_scene(C); + struct wmMsgBus *mbus = wm->message_bus; + WM_msgbus_clear_by_owner(mbus, ar); + + /* Cheat, always subscribe to this space type properties. + * + * This covers most cases and avoids copy-paste similar code for each space type. + */ + if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_CHANNELS, RGN_TYPE_UI, RGN_TYPE_TOOLS)) { + SpaceLink *sl = sa->spacedata.first; + + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_Space, sl, &ptr); + + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + /* All properties for this space type. */ + WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_region_tag_redraw, __func__); + } + + ED_region_message_subscribe(C, workspace, scene, screen, sa, ar, mbus); + } } /* ********************************** @@ -2695,3 +2754,25 @@ void ED_region_cache_draw_cached_segments(const ARegion *ar, const int num_segme immUnbindProgram(); } } + +/** + * Generate subscriptions for this region. + */ +void ED_region_message_subscribe( + bContext *C, + struct WorkSpace *workspace, struct Scene *scene, + struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus) +{ + if (ar->manipulator_map != NULL) { + WM_manipulatormap_message_subscribe(C, ar->manipulator_map, ar, mbus); + } + + if (BLI_listbase_is_empty(&ar->uiblocks)) { + UI_region_message_subscribe(ar, mbus); + } + + if (ar->type->message_subscribe != NULL) { + ar->type->message_subscribe(C, workspace, scene, screen, sa, ar, mbus); + } +} diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index d84f256bc32..4c62253bef6 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -91,7 +91,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); ViewLayer *view_layer = BKE_view_layer_from_workspace_get(scene, workspace); Object *obedit = scene->obedit; - Object *obact = view_layer->basact ? view_layer->basact->object : NULL; + Object *obact = (view_layer && view_layer->basact) ? view_layer->basact->object : NULL; if (CTX_data_dir(member)) { CTX_data_dir_set(result, screen_context_dir); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index c1ea219ad04..4b5ce2f4b81 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -66,6 +66,8 @@ #include "UI_interface.h" +#include "WM_message.h" + /* XXX actually should be not here... solve later */ #include "wm_subwindow.h" @@ -897,6 +899,8 @@ void ED_region_exit(bContext *C, ARegion *ar) ar->regiontimer = NULL; } + WM_msgbus_clear_by_owner(wm->message_bus, ar); + CTX_wm_region_set(C, prevar); } diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index fb113816144..da9cb69b528 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -71,15 +71,16 @@ * \{ */ WorkSpace *ED_workspace_add( - Main *bmain, const char *name, ViewLayer *act_view_layer, ViewRender *view_render) + Main *bmain, const char *name, Scene *scene, + ViewLayer *act_view_layer, ViewRender *view_render) { WorkSpace *workspace = BKE_workspace_add(bmain, name); - BKE_workspace_view_layer_set(workspace, act_view_layer); + BKE_workspace_view_layer_set(workspace, act_view_layer, scene); BKE_viewrender_copy(&workspace->view_render, view_render); #ifdef USE_WORKSPACE_MODE - BKE_workspace_object_mode_set(workspace, OB_MODE_OBJECT); + BKE_workspace_object_mode_set(workspace, scene, OB_MODE_OBJECT); #endif return workspace; @@ -94,8 +95,9 @@ static void workspace_change_update_mode( const WorkSpace *workspace_old, const WorkSpace *workspace_new, bContext *C, Object *ob_act, ReportList *reports) { - eObjectMode mode_old = BKE_workspace_object_mode_get(workspace_old); - eObjectMode mode_new = BKE_workspace_object_mode_get(workspace_new); + const Scene *scene = CTX_data_scene(C); + eObjectMode mode_old = BKE_workspace_object_mode_get(workspace_old, scene); + eObjectMode mode_new = BKE_workspace_object_mode_get(workspace_new, scene); if (mode_old != mode_new) { ED_object_mode_compat_set(C, ob_act, mode_new, reports); @@ -105,10 +107,11 @@ static void workspace_change_update_mode( #endif static void workspace_change_update_view_layer( - WorkSpace *workspace_new, const WorkSpace *workspace_old) + WorkSpace *workspace_new, const WorkSpace *workspace_old, + Scene *scene) { - if (!BKE_workspace_view_layer_get(workspace_new)) { - BKE_workspace_view_layer_set(workspace_new, BKE_workspace_view_layer_get(workspace_old)); + if (!BKE_workspace_view_layer_get(workspace_new, scene)) { + BKE_workspace_view_layer_set(workspace_new, BKE_workspace_view_layer_get(workspace_old, scene), scene); } } @@ -117,7 +120,7 @@ static void workspace_change_update( bContext *C, wmWindowManager *wm) { /* needs to be done before changing mode! (to ensure right context) */ - workspace_change_update_view_layer(workspace_new, workspace_old); + workspace_change_update_view_layer(workspace_new, workspace_old, CTX_data_scene(C)); #ifdef USE_WORKSPACE_MODE workspace_change_update_mode(workspace_old, workspace_new, C, CTX_data_active_object(C), &wm->reports); #else @@ -199,7 +202,7 @@ bool ED_workspace_change( screen_changed_update(C, win, screen_new); workspace_change_update(workspace_new, workspace_old, C, wm); - BLI_assert(BKE_workspace_view_layer_get(workspace_new) != NULL); + BLI_assert(BKE_workspace_view_layer_get(workspace_new, CTX_data_scene(C)) != NULL); BLI_assert(CTX_wm_workspace(C) == workspace_new); WM_toolsystem_unlink(C, workspace_old); @@ -220,15 +223,16 @@ WorkSpace *ED_workspace_duplicate( { WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook); ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old); + Scene *scene = WM_window_get_active_scene(win); WorkSpace *workspace_new = ED_workspace_add( - bmain, workspace_old->id.name + 2, - BKE_workspace_view_layer_get(workspace_old), + bmain, workspace_old->id.name + 2, scene, + BKE_workspace_view_layer_get(workspace_old, scene), &workspace_old->view_render); ListBase *transform_orientations_old = BKE_workspace_transform_orientations_get(workspace_old); ListBase *transform_orientations_new = BKE_workspace_transform_orientations_get(workspace_new); #ifdef USE_WORKSPACE_MODE - BKE_workspace_object_mode_set(workspace_new, BKE_workspace_object_mode_get(workspace_old)); + BKE_workspace_object_mode_set(workspace_new, scene, BKE_workspace_object_mode_get(workspace_old, scene)); #endif BLI_duplicatelist(transform_orientations_new, transform_orientations_old); @@ -279,11 +283,12 @@ void ED_workspace_scene_data_sync( } void ED_workspace_view_layer_unset( - const Main *bmain, const ViewLayer *layer_unset, ViewLayer *layer_new) + const Main *bmain, Scene *scene, + const ViewLayer *layer_unset, ViewLayer *layer_new) { for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { - if (BKE_workspace_view_layer_get(workspace) == layer_unset) { - BKE_workspace_view_layer_set(workspace, layer_new); + if (BKE_workspace_view_layer_get(workspace, scene) == layer_unset) { + BKE_workspace_view_layer_set(workspace, layer_new, scene); } } } diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 183d715a93e..8866c6b6c40 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -39,6 +39,7 @@ #include "BLT_translation.h" #include "DNA_armature_types.h" +#include "DNA_group_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -177,7 +178,7 @@ static int buttons_context_path_workspace(ButsContextPath *path) return RNA_struct_is_a(ptr->type, &RNA_WorkSpace); } -static int buttons_context_path_collection(ButsContextPath *path) +static int buttons_context_path_collection(ButsContextPath *path, eSpaceButtons_Collection_Context collection_context) { PointerRNA *ptr = &path->ptr[path->len - 1]; @@ -187,10 +188,21 @@ static int buttons_context_path_collection(ButsContextPath *path) } ViewLayer *view_layer = ptr->data; - LayerCollection *sc = BKE_layer_collection_get_active(view_layer); - if (sc) { - RNA_pointer_create(NULL, &RNA_LayerCollection, sc, &path->ptr[path->len]); + if (collection_context == SB_COLLECTION_CTX_GROUP) { + Object *ob = OBACT(view_layer); + if (ob && ob->dup_group) { + view_layer = ob->dup_group->view_layer; + + /* Replace the view layer by the group in the context path. */ + RNA_pointer_create(NULL, &RNA_Group, ob->dup_group, &path->ptr[path->len - 1]); + } + } + + LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); + + if (layer_collection) { + RNA_pointer_create(NULL, &RNA_LayerCollection, layer_collection, &path->ptr[path->len]); path->len++; return 1; } @@ -650,7 +662,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma found = buttons_context_path_workspace(path); break; case BCONTEXT_COLLECTION: - found = buttons_context_path_collection(path); + found = buttons_context_path_collection(path, sbuts->collection_context); break; case BCONTEXT_OBJECT: case BCONTEXT_PHYSICS: diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h index 7fc35a6b1e7..e6d19caad47 100644 --- a/source/blender/editors/space_buttons/buttons_intern.h +++ b/source/blender/editors/space_buttons/buttons_intern.h @@ -65,6 +65,7 @@ typedef struct ButsContextPath { int len; int flag; int tex_ctx; + int collection_ctx; } ButsContextPath; typedef struct ButsTextureUser { diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 74b20360a53..d2f407bfa8c 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -44,6 +44,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "RNA_access.h" diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index cca33cdd1a7..217ce8f1d9a 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -151,15 +151,25 @@ static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill /* if desired, fill the selection up from the last selected file to the current one */ if (fill && (sel.last >= 0) && (sel.last < numfiles) ) { - int f = sel.last; - while (f >= 0) { + int f; + /* Try to find a smaller-index selected item. */ + for (f = sel.last; f >= 0; f--) { if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL) ) break; - f--; } if (f >= 0) { sel.first = f + 1; } + /* If none found, try to find a higher-index selected item. */ + else { + for (f = sel.first; f < numfiles; f++) { + if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL) ) + break; + } + if (f < numfiles) { + sel.last = f - 1; + } + } } return sel; } diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 780c2ec5a47..3f26604c23a 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -49,6 +49,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "ED_space_api.h" #include "ED_screen.h" @@ -354,6 +355,33 @@ static void file_main_region_listener( } } +static void file_main_region_message_subscribe( + const struct bContext *UNUSED(C), + struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), + struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus) +{ + SpaceFile *sfile = sa->spacedata.first; + FileSelectParams *params = ED_fileselect_get_params(sfile); + /* This is a bit odd that a region owns the subscriber for an area, + * keep for now since all subscribers for WM are regions. + * May be worth re-visiting later. */ + wmMsgSubscribeValue msg_sub_value_area_tag_refresh = { + .owner = ar, + .user_data = sa, + .notify = ED_area_do_msg_notify_tag_refresh, + }; + + /* FileSelectParams */ + { + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &ptr); + + /* All properties for this space type. */ + WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__); + } +} + static void file_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ @@ -731,6 +759,7 @@ void ED_spacetype_file(void) art->init = file_main_region_init; art->draw = file_main_region_draw; art->listener = file_main_region_listener; + art->message_subscribe = file_main_region_message_subscribe; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 53709e4cea7..3cf833756ef 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -270,6 +270,39 @@ static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats) stats->tottri = ob->sculpt->bm->totface; } +static void stats_dupli_object_group_count(SceneCollection *scene_collection, int *count) +{ + for (LinkData *link = scene_collection->objects.first; link; link = link->next) { + (*count)++; + } + + SceneCollection *scene_collection_nested; + for (scene_collection_nested = scene_collection->scene_collections.first; + scene_collection_nested; + scene_collection_nested = scene_collection_nested->next) + { + stats_dupli_object_group_count(scene_collection_nested, count); + } +} + +static void stats_dupli_object_group_doit(SceneCollection *scene_collection, SceneStats *stats, ParticleSystem *psys, + const int totgroup, int *cur) +{ + for (LinkData *link = scene_collection->objects.first; link; link = link->next) { + int tot = count_particles_mod(psys, totgroup, *cur); + stats_object(link->data, 0, tot, stats); + (*cur)++; + } + + SceneCollection *scene_collection_nested; + for (scene_collection_nested = scene_collection->scene_collections.first; + scene_collection_nested; + scene_collection_nested = scene_collection_nested->next) + { + stats_dupli_object_group_doit(scene_collection_nested, stats, psys, totgroup, cur); + } +} + static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) { if (base->flag & BASE_SELECTED) stats->totobjsel++; @@ -287,17 +320,11 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) stats_object(part->dup_ob, 0, tot, stats); } else if (part->draw_as == PART_DRAW_GR && part->dup_group) { - GroupObject *go; - int tot, totgroup = 0, cur = 0; - - for (go = part->dup_group->gobject.first; go; go = go->next) - totgroup++; - - for (go = part->dup_group->gobject.first; go; go = go->next) { - tot = count_particles_mod(psys, totgroup, cur); - stats_object(go->ob, 0, tot, stats); - cur++; - } + int totgroup = 0, cur = 0; + + SceneCollection *scene_collection = part->dup_group->collection; + stats_dupli_object_group_count(scene_collection, &totgroup); + stats_dupli_object_group_doit(scene_collection, stats, psys, totgroup, &cur); } } diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index adf7e1dc5d3..d5c833a7b5f 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -36,6 +36,8 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DNA_group_types.h" + #include "ED_screen.h" #include "WM_api.h" @@ -110,7 +112,7 @@ static int collection_link_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc_master = BKE_collection_master(&scene->id); SceneCollection *sc; int scene_collection_index = RNA_enum_get(op->ptr, "scene_collection"); @@ -136,7 +138,9 @@ static int collection_link_exec(bContext *C, wmOperator *op) static int collection_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (BKE_collection_master(CTX_data_scene(C))->scene_collections.first == NULL) { + Scene *scene = CTX_data_scene(C); + SceneCollection *master_collection = BKE_collection_master(&scene->id); + if (master_collection->scene_collections.first == NULL) { RNA_enum_set(op->ptr, "scene_collection", 0); return collection_link_exec(C, op); } @@ -169,7 +173,7 @@ static const EnumPropertyItem *collection_scene_collection_itemf( int value = 0, totitem = 0; Scene *scene = CTX_data_scene(C); - SceneCollection *sc = BKE_collection_master(scene); + SceneCollection *sc = BKE_collection_master(&scene->id); collection_scene_collection_itemf_recursive(&tmp, &item, &totitem, &value, sc); RNA_enum_item_end(&item, &totitem); @@ -257,15 +261,18 @@ void OUTLINER_OT_collection_unlink(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/**********************************************************************************/ +/* Add new collection. */ + static int collection_new_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); + SceneCollection *scene_collection = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL); + BKE_collection_link(view_layer, scene_collection); - SceneCollection *sc = BKE_collection_add(scene, NULL, NULL); - BKE_collection_link(view_layer, sc); - - DEG_relations_tag_update(CTX_data_main(C)); + DEG_relations_tag_update(bmain); WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); return OPERATOR_FINISHED; } @@ -275,7 +282,7 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot) /* identifiers */ ot->name = "New Collection"; ot->idname = "OUTLINER_OT_collection_new"; - ot->description = "Add a new collection to the scene, and link it to the active layer"; + ot->description = "Add a new collection to the scene"; /* api callbacks */ ot->exec = collection_new_exec; @@ -284,6 +291,8 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/**********************************************************************************/ + /** * Returns true is selected element is a collection */ @@ -325,9 +334,10 @@ void OUTLINER_OT_collection_override_new(wmOperatorType *ot) struct CollectionDeleteData { Scene *scene; SpaceOops *soops; + GSet *collections_to_delete; }; -static TreeTraversalAction collection_delete_cb(TreeElement *te, void *customdata) +static TreeTraversalAction collection_find_data_to_delete(TreeElement *te, void *customdata) { struct CollectionDeleteData *data = customdata; SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te); @@ -336,12 +346,12 @@ static TreeTraversalAction collection_delete_cb(TreeElement *te, void *customdat return TRAVERSE_SKIP_CHILDS; } - if (scene_collection == BKE_collection_master(data->scene)) { + if (scene_collection == BKE_collection_master(&data->scene->id)) { /* skip - showing warning/error message might be missleading * when deleting multiple collections, so just do nothing */ } else { - BKE_collection_remove(data->scene, scene_collection); + BLI_gset_add(data->collections_to_delete, scene_collection); } return TRAVERSE_CONTINUE; @@ -353,8 +363,22 @@ static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op)) SpaceOops *soops = CTX_wm_space_outliner(C); struct CollectionDeleteData data = {.scene = scene, .soops = soops}; + data.collections_to_delete = BLI_gset_ptr_new(__func__); + TODO_LAYER_OVERRIDE; /* handle overrides */ - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_delete_cb, &data); + + /* We first walk over and find the SceneCollections we actually want to delete (ignoring duplicates). */ + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_delete, &data); + + /* Effectively delete the collections. */ + GSetIterator collections_to_delete_iter; + GSET_ITER(collections_to_delete_iter, data.collections_to_delete) { + + SceneCollection *sc = BLI_gsetIterator_getKey(&collections_to_delete_iter); + BKE_collection_remove(&data.scene->id, sc); + } + + BLI_gset_free(data.collections_to_delete, NULL); DEG_relations_tag_update(CTX_data_main(C)); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 8b4ed61f148..670fc4e6627 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -250,9 +250,16 @@ static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), voi static void enablebutton_collection_flag_cb(bContext *C, void *poin, void *poin2) { Main *bmain = CTX_data_main(C); - Scene *scene = poin; + Scene *scene = CTX_data_scene(C); + ID *id = poin; LayerCollection *layer_collection = poin2; - ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection); + ViewLayer *view_layer = BKE_view_layer_find_from_collection(id, layer_collection); + + /* TODO: This breaks when you see the collections of a group. (dfelinto) */ + if (view_layer == NULL) { + WM_reportf(RPT_INFO, "Enable/disable of group collections disabled for now"); + return; + } /* We need to toggle the flag since this is called after the flag is already set. */ layer_collection->flag ^= COLLECTION_DISABLED; @@ -273,11 +280,16 @@ static void enablebutton_collection_flag_cb(bContext *C, void *poin, void *poin2 static void restrictbutton_collection_flag_cb(bContext *C, void *poin, void *UNUSED(poin2)) { - Scene *scene = poin; + ID *id = (ID *)poin; + /* hide and deselect bases that are directly influenced by this LayerCollection */ /* TODO(sergey): Use proper flag for tagging here. */ - DEG_id_tag_update(&scene->id, 0); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + DEG_id_tag_update(id, 0); + + if (GS(id->name) == ID_SCE) { + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, id); + } + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL); } @@ -595,22 +607,24 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_ENABLEX), te->ys, UI_UNIT_X, UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, TIP_("Enable/Disable collection from depsgraph")); - UI_but_func_set(bt, enablebutton_collection_flag_cb, scene, collection); + UI_but_func_set(bt, enablebutton_collection_flag_cb, tselem->id, collection); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VISIBLE, 0, ICON_RESTRICT_VIEW_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, TIP_("Restrict/Allow 3D View visibility of objects in the collection")); - UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection); + UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, - TIP_("Restrict/Allow 3D View selection of objects in the collection")); - UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (collection->scene_collection->type == COLLECTION_TYPE_NONE) { + bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, + TIP_("Restrict/Allow 3D View selection of objects in the collection")); + UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } UI_block_emboss_set(block, UI_EMBOSS); } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 4858b6cb120..8cd76179f23 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -274,7 +274,7 @@ static void do_item_rename(const Scene *scene, ARegion *ar, TreeElement *te, Tre BKE_report(reports, RPT_WARNING, "Cannot edit sequence name"); } else if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) { - SceneCollection *master = BKE_collection_master(scene); + SceneCollection *master = BKE_collection_master(&scene->id); if ((tselem->type == TSE_SCENE_COLLECTION && te->directdata == master) || (((LayerCollection *)te->directdata)->scene_collection == master)) @@ -1940,7 +1940,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) BLI_assert(scene); RNA_string_get(op->ptr, "child", childname); ob = (Object *)BKE_libblock_find_name(ID_OB, childname); - BKE_collection_object_add(scene, sc, ob); + BKE_collection_object_add(&scene->id, sc, ob); DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); @@ -2166,13 +2166,13 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) SceneCollection *sc; if (scene != CTX_data_scene(C)) { /* when linking to an inactive scene link to the master collection */ - sc = BKE_collection_master(scene); + sc = BKE_collection_master(&scene->id); } else { sc = CTX_data_scene_collection(C); } - BKE_collection_object_add(scene, sc, ob); + BKE_collection_object_add(&scene->id, sc, ob); for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { Base *base = BKE_view_layer_base_find(view_layer, ob); diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 23e1b766891..f69eb9af1bf 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -67,9 +67,8 @@ typedef enum TreeTraversalAction { /** * Callback type for reinserting elements at a different position, used to allow user customizable element order. - * Passing scene right now, may be better to allow some custom data. */ -typedef void (*TreeElementReinsertFunc)(struct Main *bmain, const struct Scene *scene, +typedef void (*TreeElementReinsertFunc)(struct Main *bmain, struct TreeElement *insert_element, struct TreeElement *insert_handle, TreeElementInsertType action); /** @@ -77,7 +76,7 @@ typedef void (*TreeElementReinsertFunc)(struct Main *bmain, const struct Scene * * if reinserting insert_element before/after/into insert_handle would be allowed. * It's allowed to change the reinsert info here for non const pointers. */ -typedef bool (*TreeElementReinsertPollFunc)(const struct Scene *scene, const struct TreeElement *insert_element, +typedef bool (*TreeElementReinsertPollFunc)(const struct TreeElement *insert_element, struct TreeElement **io_insert_handle, TreeElementInsertType *io_action); typedef TreeTraversalAction (*TreeTraversalFunc)(struct TreeElement *te, void *customdata); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index aa6a5dba6a7..856dd022c14 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -58,7 +58,7 @@ static int outliner_item_drag_drop_poll(bContext *C) SpaceOops *soops = CTX_wm_space_outliner(C); return ED_operator_outliner_active(C) && /* Only collection display modes supported for now. Others need more design work */ - ELEM(soops->outlinevis, SO_ACT_LAYER, SO_COLLECTIONS); + ELEM(soops->outlinevis, SO_ACT_LAYER, SO_COLLECTIONS, SO_GROUPS); } static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event) @@ -138,7 +138,7 @@ static void outliner_item_drag_get_insert_data( } static void outliner_item_drag_handle( - const Scene *scene, SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged) + SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged) { TreeElement *te_insert_handle; TreeElementInsertType insert_type; @@ -156,7 +156,7 @@ static void outliner_item_drag_handle( /* nothing will happen anyway, no need to do poll check */ } else if (!te_dragged->reinsert_poll || - !te_dragged->reinsert_poll(scene, te_dragged, &te_insert_handle, &insert_type)) + !te_dragged->reinsert_poll(te_dragged, &te_insert_handle, &insert_type)) { te_insert_handle = NULL; } @@ -164,7 +164,7 @@ static void outliner_item_drag_handle( te_dragged->drag_data->insert_handle = te_insert_handle; } -static bool outliner_item_drag_drop_apply(Main *bmain, const Scene *scene, TreeElement *dragged_te) +static bool outliner_item_drag_drop_apply(Main *bmain, TreeElement *dragged_te) { TreeElement *insert_handle = dragged_te->drag_data->insert_handle; TreeElementInsertType insert_type = dragged_te->drag_data->insert_type; @@ -173,12 +173,12 @@ static bool outliner_item_drag_drop_apply(Main *bmain, const Scene *scene, TreeE /* No need to do anything */ } else if (dragged_te->reinsert) { - BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(scene, dragged_te, &insert_handle, + BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(dragged_te, &insert_handle, &insert_type)); /* call of assert above should not have changed insert_handle and insert_type at this point */ BLI_assert(dragged_te->drag_data->insert_handle == insert_handle && dragged_te->drag_data->insert_type == insert_type); - dragged_te->reinsert(bmain, scene, dragged_te, insert_handle, insert_type); + dragged_te->reinsert(bmain, dragged_te, insert_handle, insert_type); return true; } @@ -188,7 +188,6 @@ static bool outliner_item_drag_drop_apply(Main *bmain, const Scene *scene, TreeE static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); TreeElement *te_dragged = op->customdata; @@ -199,7 +198,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv switch (event->type) { case EVT_MODAL_MAP: if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) { - if (outliner_item_drag_drop_apply(bmain, scene, te_dragged)) { + if (outliner_item_drag_drop_apply(bmain, te_dragged)) { skip_rebuild = false; } retval = OPERATOR_FINISHED; @@ -215,7 +214,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv redraw = true; break; case MOUSEMOVE: - outliner_item_drag_handle(scene, soops, ar, event, te_dragged); + outliner_item_drag_handle(soops, ar, event, te_dragged); redraw = true; break; } diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 5215efaa05c..08b5f337936 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -44,6 +44,7 @@ #include "BLI_listbase.h" #include "BKE_context.h" +#include "BKE_group.h" #include "BKE_object.h" #include "BKE_layer.h" #include "BKE_scene.h" @@ -780,12 +781,23 @@ static eOLDrawState tree_element_active_collection( /* don't allow selecting a scene collection, it can have multiple layer collection * instances (which one would the user want to be selected then?) */ else if (tselem->type == TSE_LAYER_COLLECTION) { - ViewLayer *view_layer = CTX_data_view_layer(C); - LayerCollection *lc = te->directdata; - const int collection_index = BKE_layer_collection_findindex(view_layer, lc); + LayerCollection *layer_collection = te->directdata; + + switch (layer_collection->scene_collection->type) { + case COLLECTION_TYPE_NONE: + case COLLECTION_TYPE_GROUP_INTERNAL: + { + ViewLayer *view_layer = BKE_view_layer_find_from_collection(tselem->id, layer_collection); + const int collection_index = BKE_layer_collection_findindex(view_layer, layer_collection); - BLI_assert(collection_index >= 0); - view_layer->active_collection = collection_index; + if (collection_index > -1) { + view_layer->active_collection = collection_index; + } + break; + } + default: + BLI_assert(!"Collection type not fully implemented"); + } WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); } @@ -906,26 +918,30 @@ static void do_outliner_item_activate_tree_element( } else if (te->idcode == ID_GR) { Group *gr = (Group *)tselem->id; - GroupObject *gob; if (extend) { int sel = BA_SELECT; - for (gob = gr->gobject.first; gob; gob = gob->next) { - if (gob->ob->flag & SELECT) { + FOREACH_GROUP_BASE(gr, base) + { + if (base->flag & BASE_SELECTED) { sel = BA_DESELECT; break; } } + FOREACH_GROUP_BASE_END - for (gob = gr->gobject.first; gob; gob = gob->next) { - ED_object_base_select(BKE_view_layer_base_find(view_layer, gob->ob), sel); + FOREACH_GROUP_OBJECT(gr, object) + { + ED_object_base_select(BKE_view_layer_base_find(view_layer, object), sel); } + FOREACH_GROUP_OBJECT_END } else { BKE_view_layer_base_deselect_all(view_layer); - for (gob = gr->gobject.first; gob; gob = gob->next) { - Base *base = BKE_view_layer_base_find(view_layer, gob->ob); + FOREACH_GROUP_OBJECT(gr, object) + { + Base *base = BKE_view_layer_base_find(view_layer, object); /* Object may not be in this scene */ if (base != NULL) { if ((base->flag & BASE_SELECTED) == 0) { @@ -933,6 +949,7 @@ static void do_outliner_item_activate_tree_element( } } } + FOREACH_GROUP_OBJECT_END } WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 63e1a527138..99fd539293f 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -525,20 +525,21 @@ static void group_linkobs2scene_cb( ViewLayer *view_layer = CTX_data_view_layer(C); SceneCollection *sc = CTX_data_scene_collection(C); Group *group = (Group *)tselem->id; - GroupObject *gob; Base *base; - for (gob = group->gobject.first; gob; gob = gob->next) { - base = BKE_view_layer_base_find(view_layer, gob->ob); + FOREACH_GROUP_OBJECT(group, object) + { + base = BKE_view_layer_base_find(view_layer, object); if (!base) { /* link to scene */ - BKE_collection_object_add(scene, sc, gob->ob); - base = BKE_view_layer_base_find(view_layer, gob->ob); - id_us_plus(&gob->ob->id); + BKE_collection_object_add(&scene->id, sc, object); + base = BKE_view_layer_base_find(view_layer, object); + id_us_plus(&object->id); } base->flag |= BASE_SELECTED; } + FOREACH_GROUP_OBJECT_END } static void group_instance_cb( @@ -663,6 +664,7 @@ typedef enum eOutliner_PropCollectionOps { OL_COLLECTION_OP_COLLECTION_NEW, OL_COLLECTION_OP_COLLECTION_DEL, OL_COLLECTION_OP_COLLECTION_UNLINK, + OL_COLLECTION_OP_GROUP_CREATE, } eOutliner_PropCollectionOps; static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) @@ -820,12 +822,13 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel bContext *C = (bContext *)Carg; Scene *scene = CTX_data_scene(C); LayerCollection *lc = te->directdata; + ID *id = te->store_elem->id; SceneCollection *sc = lc->scene_collection; if (event == OL_COLLECTION_OP_OBJECTS_ADD) { CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { - BKE_collection_object_add(scene, sc, ob); + BKE_collection_object_add(id, sc, ob); } CTX_DATA_END; @@ -836,7 +839,7 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { - BKE_collection_object_remove(bmain, scene, sc, ob, true); + BKE_collection_object_remove(bmain, id, sc, ob, true); } CTX_DATA_END; @@ -844,7 +847,13 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel te->store_elem->flag &= ~TSE_SELECTED; } else if (event == OL_COLLECTION_OP_COLLECTION_NEW) { - BKE_collection_add(scene, sc, NULL); + if (GS(id->name) == ID_GR) { + BKE_collection_add(id, sc, COLLECTION_TYPE_GROUP_INTERNAL, NULL); + } + else { + BLI_assert(GS(id->name) == ID_SCE); + BKE_collection_add(id, sc, COLLECTION_TYPE_NONE, NULL); + } WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); } else if (event == OL_COLLECTION_OP_COLLECTION_UNLINK) { @@ -861,7 +870,7 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel } } else if (event == OL_COLLECTION_OP_COLLECTION_DEL) { - if (BKE_collection_remove(scene, sc)) { + if (BKE_collection_remove(id, sc)) { DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); } @@ -870,6 +879,17 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */ } } + else if (event == OL_COLLECTION_OP_GROUP_CREATE) { + Main *bmain = CTX_data_main(C); + BKE_collection_group_create(bmain, scene, lc); + DEG_relations_tag_update(bmain); + /* TODO(sergey): Use proper flag for tagging here. */ + DEG_id_tag_update(&scene->id, 0); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + } + else { + BLI_assert(!"Collection operation not fully implemented!"); + } } static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, @@ -1794,15 +1814,39 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot) /* ******************** */ -static EnumPropertyItem prop_collection_op_types[] = { - {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"}, - {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"}, - {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"}, - {OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink collection"}, - {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"}, - {0, NULL, 0, NULL, NULL} +static EnumPropertyItem prop_collection_op_none_types[] = { + {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"}, + {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"}, + {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"}, + {OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink collection"}, + {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"}, + {OL_COLLECTION_OP_GROUP_CREATE, "GROUP_CREATE", ICON_GROUP, "Create Group", "Turn the collection into a group collection"}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem prop_collection_op_group_internal_types[] = { + {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"}, + {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"}, + {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"}, + {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"}, + {0, NULL, 0, NULL, NULL} }; +static const EnumPropertyItem *outliner_collection_operation_type_itemf( + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + *r_free = false; + SpaceOops *soops = CTX_wm_space_outliner(C); + + switch (soops->outlinevis) { + case SO_GROUPS: + return prop_collection_op_group_internal_types; + case SO_ACT_LAYER: + return prop_collection_op_none_types; + } + return NULL; +} + static int outliner_collection_operation_exec(bContext *C, wmOperator *op) { SpaceOops *soops = CTX_wm_space_outliner(C); @@ -1823,6 +1867,8 @@ static int outliner_collection_operation_exec(bContext *C, wmOperator *op) void OUTLINER_OT_collection_operation(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Outliner Collection Operation"; ot->idname = "OUTLINER_OT_collection_operation"; @@ -1835,7 +1881,10 @@ void OUTLINER_OT_collection_operation(wmOperatorType *ot) ot->flag = 0; - ot->prop = RNA_def_enum(ot->srna, "type", prop_collection_op_types, 0, "Collection Operation", ""); + prop = RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Collection Operation", ""); + RNA_def_enum_funcs(prop, outliner_collection_operation_type_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } /* ******************** */ diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 1ab715d0246..a9c9ab74970 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -88,6 +88,8 @@ #endif /* prototypes */ +static void outliner_add_layer_collections_recursive( + SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten); static void outliner_make_hierarchy(ListBase *lb); /* ********************************************************* */ @@ -386,13 +388,14 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s } static void outliner_object_reorder( - Main *UNUSED(bmain), const Scene *scene, + Main *UNUSED(bmain), TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) { TreeStoreElem *tselem_insert = TREESTORE(insert_element); Object *ob = (Object *)tselem_insert->id; SceneCollection *sc = outliner_scene_collection_from_tree_element(insert_handle); SceneCollection *sc_ob_parent = NULL; + ID *id = insert_handle->store_elem->id; BLI_assert(action == TE_INSERT_INTO); UNUSED_VARS_NDEBUG(action); @@ -407,13 +410,13 @@ static void outliner_object_reorder( } } else { - sc_ob_parent = BKE_collection_master(scene); + sc_ob_parent = BKE_collection_master(id); } - BKE_collection_object_move(scene, sc, sc_ob_parent, ob); + BKE_collection_object_move(id, sc, sc_ob_parent, ob); } static bool outliner_object_reorder_poll( - const Scene *UNUSED(scene), const TreeElement *insert_element, + const TreeElement *insert_element, TreeElement **io_insert_handle, TreeElementInsertType *io_action) { TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle); @@ -861,7 +864,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i } /* exceptions */ - if (ELEM(type, TSE_ID_BASE, TSE_LAYER_COLLECTION)) { + if (type == TSE_ID_BASE) { /* pass */ } else if (id == NULL) { @@ -1199,6 +1202,11 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i te->flag |= TE_LAZY_CLOSED; } + if ((type != TSE_LAYER_COLLECTION) && GS(id->name) == ID_GR) { + Group *group = (Group *)id; + outliner_add_layer_collections_recursive(soops, &te->subtree, id, &group->view_layer->layer_collections, NULL); + } + return te; } @@ -1349,20 +1357,21 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) } static void outliner_layer_collections_reorder( - Main *bmain, const Scene *scene, + Main *bmain, TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) { LayerCollection *lc_insert = insert_element->directdata; LayerCollection *lc_handle = insert_handle->directdata; + ID *id = insert_element->store_elem->id; if (action == TE_INSERT_BEFORE) { - BKE_layer_collection_move_above(scene, lc_handle, lc_insert); + BKE_layer_collection_move_above(id, lc_handle, lc_insert); } else if (action == TE_INSERT_AFTER) { - BKE_layer_collection_move_below(scene, lc_handle, lc_insert); + BKE_layer_collection_move_below(id, lc_handle, lc_insert); } else if (action == TE_INSERT_INTO) { - BKE_layer_collection_move_into(scene, lc_handle, lc_insert); + BKE_layer_collection_move_into(id, lc_handle, lc_insert); } else { BLI_assert(0); @@ -1371,25 +1380,30 @@ static void outliner_layer_collections_reorder( DEG_relations_tag_update(bmain); } static bool outliner_layer_collections_reorder_poll( - const Scene *UNUSED(scene), const TreeElement *UNUSED(insert_element), + const TreeElement *insert_element, TreeElement **io_insert_handle, TreeElementInsertType *UNUSED(io_action)) { const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle); + + if (tselem_handle->id != insert_element->store_elem->id) { + return false; + } + return ELEM(tselem_handle->type, TSE_LAYER_COLLECTION); } static void outliner_add_layer_collections_recursive( - SpaceOops *soops, ListBase *tree, ListBase *layer_collections, TreeElement *parent_ten) + SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten) { for (LayerCollection *collection = layer_collections->first; collection; collection = collection->next) { - TreeElement *ten = outliner_add_element(soops, tree, collection, parent_ten, TSE_LAYER_COLLECTION, 0); + TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0); ten->name = collection->scene_collection->name; ten->directdata = collection; ten->reinsert = outliner_layer_collections_reorder; ten->reinsert_poll = outliner_layer_collections_reorder_poll; - outliner_add_layer_collections_recursive(soops, &ten->subtree, &collection->layer_collections, ten); + outliner_add_layer_collections_recursive(soops, &ten->subtree, id, &collection->layer_collections, ten); for (LinkData *link = collection->object_bases.first; link; link = link->next) { Base *base = (Base *)link->data; TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0); @@ -1398,27 +1412,29 @@ static void outliner_add_layer_collections_recursive( outliner_make_hierarchy(&ten->subtree); } } -static void outliner_add_collections_act_layer(SpaceOops *soops, ViewLayer *layer) +static void outliner_add_collections_act_layer(SpaceOops *soops, Scene *scene, ViewLayer *layer) { - outliner_add_layer_collections_recursive(soops, &soops->tree, &layer->layer_collections, NULL); + outliner_add_layer_collections_recursive(soops, &soops->tree, &scene->id, &layer->layer_collections, NULL); } static void outliner_scene_collections_reorder( - Main *bmain, const Scene *scene, + Main *bmain, TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) { SceneCollection *sc_insert = insert_element->directdata; SceneCollection *sc_handle = insert_handle->directdata; + ID *id = insert_handle->store_elem->id; + BLI_assert(id == insert_element->store_elem->id); - BLI_assert((action == TE_INSERT_INTO) || (sc_handle != BKE_collection_master(scene))); + BLI_assert((action == TE_INSERT_INTO) || (sc_handle != BKE_collection_master(id))); if (action == TE_INSERT_BEFORE) { - BKE_collection_move_above(scene, sc_handle, sc_insert); + BKE_collection_move_above(id, sc_handle, sc_insert); } else if (action == TE_INSERT_AFTER) { - BKE_collection_move_below(scene, sc_handle, sc_insert); + BKE_collection_move_below(id, sc_handle, sc_insert); } else if (action == TE_INSERT_INTO) { - BKE_collection_move_into(scene, sc_handle, sc_insert); + BKE_collection_move_into(id, sc_handle, sc_insert); } else { BLI_assert(0); @@ -1427,17 +1443,23 @@ static void outliner_scene_collections_reorder( DEG_relations_tag_update(bmain); } static bool outliner_scene_collections_reorder_poll( - const Scene *scene, const TreeElement *UNUSED(insert_element), + const TreeElement *insert_element, TreeElement **io_insert_handle, TreeElementInsertType *io_action) { const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle); - SceneCollection *sc_master = BKE_collection_master(scene); - SceneCollection *sc_handle = (*io_insert_handle)->directdata; + ID *id = tselem_handle->id; + + if (id != insert_element->store_elem->id) { + return false; + } if (!ELEM(tselem_handle->type, TSE_SCENE_COLLECTION)) { return false; } + SceneCollection *sc_master = BKE_collection_master(id); + SceneCollection *sc_handle = (*io_insert_handle)->directdata; + if (sc_handle == sc_master) { /* exception: Can't insert before/after master selection, has to be one of its childs */ TreeElement *te_master = *io_insert_handle; @@ -1478,7 +1500,7 @@ static void outliner_add_scene_collections_recursive( } static void outliner_add_collections_master(SpaceOops *soops, Scene *scene) { - SceneCollection *master = BKE_collection_master(scene); + SceneCollection *master = BKE_collection_master(&scene->id); outliner_add_scene_collections_recursive(soops, &soops->tree, &master->scene_collections, NULL); outliner_add_scene_collection_objects(soops, &soops->tree, master, NULL); } @@ -1851,19 +1873,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa } else if (soops->outlinevis == SO_GROUPS) { Group *group; - GroupObject *go; - for (group = mainvar->group.first; group; group = group->id.next) { - if (group->gobject.first) { - te = outliner_add_element(soops, &soops->tree, group, NULL, 0, 0); - - for (go = group->gobject.first; go; go = go->next) { - outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0); - } - outliner_make_hierarchy(&te->subtree); - /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */ - for (go = group->gobject.first; go; go = go->next) go->ob->id.newid = NULL; - } + te = outliner_add_element(soops, &soops->tree, group, NULL, 0, 0); + outliner_make_hierarchy(&te->subtree); } } else if (soops->outlinevis == SO_SAME_TYPE) { @@ -1940,7 +1952,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa outliner_add_orphaned_datablocks(mainvar, soops); } else if (soops->outlinevis == SO_ACT_LAYER) { - outliner_add_collections_act_layer(soops, view_layer); + outliner_add_collections_act_layer(soops, scene, view_layer); } else if (soops->outlinevis == SO_COLLECTIONS) { outliner_add_collections_master(soops, scene); diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index ffaa259ab6f..1bc1a227a03 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -125,7 +125,8 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e */ if (!scene) { return 1; - } else { + } + else { for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 399e76e71b8..04dbab0b853 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -157,6 +157,7 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3]) case SEQ_TYPE_MULTICAM: case SEQ_TYPE_ADJUSTMENT: case SEQ_TYPE_GAUSSIAN_BLUR: + case SEQ_TYPE_COLORMIX: UI_GetThemeColor3ubv(TH_SEQ_EFFECT, col); /* slightly offset hue to distinguish different effects */ @@ -171,6 +172,7 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3]) else if (seq->type == SEQ_TYPE_MULTICAM) rgb_byte_set_hue_float_offset(col, 0.32); else if (seq->type == SEQ_TYPE_ADJUSTMENT) rgb_byte_set_hue_float_offset(col, 0.40); else if (seq->type == SEQ_TYPE_GAUSSIAN_BLUR) rgb_byte_set_hue_float_offset(col, 0.42); + else if (seq->type == SEQ_TYPE_COLORMIX) rgb_byte_set_hue_float_offset(col, 0.46); break; case SEQ_TYPE_COLOR: diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index a8a5bc6e96b..8f6eb064b0d 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -95,6 +95,7 @@ EnumPropertyItem sequencer_prop_effect_types[] = { {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""}, {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""}, {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""}, + {SEQ_TYPE_COLORMIX, "COLORMIX", 0, "Color Mix", ""}, {0, NULL, 0, NULL, NULL} }; @@ -694,7 +695,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) BKE_sequence_calc(scene, seq); } - if ((seq->startstill) && (cutframe < seq->start)) { + if ((seq->startstill) && (cutframe <= seq->start)) { /* don't do funny things with METAs ... */ if (seq->type == SEQ_TYPE_META) { skip_dup = true; @@ -708,13 +709,15 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) } } /* normal strip */ - else if ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))) { + else if ((cutframe >= seq->start) && (cutframe < (seq->start + seq->len))) { seq->endofs = 0; seq->endstill = 0; seq->anim_endofs += (seq->start + seq->len) - cutframe; } /* strips with extended stillframes after */ - else if (((seq->start + seq->len) < cutframe) && (seq->endstill)) { + else if (((seq->start + seq->len) == cutframe) || + (((seq->start + seq->len) < cutframe) && (seq->endstill))) + { seq->endstill -= seq->enddisp - cutframe; /* don't do funny things with METAs ... */ if (seq->type == SEQ_TYPE_META) { @@ -743,7 +746,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) } /* normal strip */ - else if ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))) { + else if ((cutframe >= seqn->start) && (cutframe < (seqn->start + seqn->len))) { seqn->start = cutframe; seqn->startstill = 0; seqn->startofs = 0; @@ -754,7 +757,9 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) } /* strips with extended stillframes after */ - else if (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)) { + else if (((seqn->start + seqn->len) == cutframe) || + (((seqn->start + seqn->len) < cutframe) && (seqn->endstill))) + { seqn->start = cutframe; seqn->startofs = 0; seqn->anim_startofs += ts.len - 1; @@ -790,7 +795,7 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) /* First Strip! */ /* strips with extended stillfames before */ - if ((seq->startstill) && (cutframe < seq->start)) { + if ((seq->startstill) && (cutframe <= seq->start)) { /* don't do funny things with METAs ... */ if (seq->type == SEQ_TYPE_META) { skip_dup = true; @@ -804,11 +809,13 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) } } /* normal strip */ - else if ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))) { + else if ((cutframe >= seq->start) && (cutframe < (seq->start + seq->len))) { seq->endofs = (seq->start + seq->len) - cutframe; } /* strips with extended stillframes after */ - else if (((seq->start + seq->len) < cutframe) && (seq->endstill)) { + else if (((seq->start + seq->len) == cutframe) || + (((seq->start + seq->len) < cutframe) && (seq->endstill))) + { seq->endstill -= seq->enddisp - cutframe; /* don't do funny things with METAs ... */ if (seq->type == SEQ_TYPE_META) { @@ -834,9 +841,9 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) seqn->endofs = ts.endofs; seqn->endstill = ts.endstill; } - + /* normal strip */ - else if ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))) { + if ((cutframe >= seqn->start) && (cutframe < (seqn->start + seqn->len))) { seqn->startstill = 0; seqn->startofs = cutframe - ts.start; seqn->endofs = ts.endofs; @@ -844,7 +851,9 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) } /* strips with extended stillframes after */ - else if (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)) { + else if (((seqn->start + seqn->len) == cutframe) || + (((seqn->start + seqn->len) < cutframe) && (seqn->endstill))) + { seqn->start = cutframe - ts.len + 1; seqn->startofs = ts.len - 1; seqn->endstill = ts.enddisp - cutframe - 1; diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 99ac0d9024c..283dbf3b4e2 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -58,6 +58,9 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" + +#include "RNA_access.h" #include "BIF_gl.h" @@ -649,6 +652,47 @@ static void time_main_region_listener( } } +static void time_main_region_message_subscribe( + const struct bContext *UNUSED(C), + struct WorkSpace *UNUSED(workspace), struct Scene *scene, + struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus) +{ + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_SpaceTimeline, sa->spacedata.first, &ptr); + + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + /* Timeline depends on scene properties. */ + { + bool use_preview = (scene->r.flag & SCER_PRV_RANGE); + extern PropertyRNA rna_Scene_frame_start; + extern PropertyRNA rna_Scene_frame_end; + extern PropertyRNA rna_Scene_frame_preview_start; + extern PropertyRNA rna_Scene_frame_preview_end; + extern PropertyRNA rna_Scene_use_preview_range; + extern PropertyRNA rna_Scene_frame_current; + const PropertyRNA *props[] = { + use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start, + use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end, + &rna_Scene_use_preview_range, + &rna_Scene_frame_current, + }; + + PointerRNA idptr; + RNA_id_pointer_create(&scene->id, &idptr); + + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__); + } + } +} + + /* ************************ header time area region *********************** */ /* add handlers, stuff you only do once or on area/region changes */ @@ -797,6 +841,7 @@ void ED_spacetype_time(void) art->init = time_main_region_init; art->draw = time_main_region_draw; art->listener = time_main_region_listener; + art->message_subscribe = time_main_region_message_subscribe; art->keymap = time_keymap; art->lock = 1; /* Due to pointcache, see T4960. */ BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 3e7e617bd0e..08ef9cc21cb 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -9458,6 +9458,8 @@ static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset) #else static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *UNUSED(dm), int offset) { + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + Mesh *me = em->ob->data; Gwn_Batch *batch = DRW_mesh_batch_cache_get_verts_with_select_id(me, offset); GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); @@ -9497,7 +9499,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset) immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32); - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + glLineWidth(1.0f); immBeginAtMost(GWN_PRIM_LINES, imm_len); dm->foreachMappedEdge(dm, bbs_mesh_wire__mapFunc, &data); @@ -9508,7 +9510,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset) #else static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *UNUSED(dm), int offset) { - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + glLineWidth(1.0f); Mesh *me = em->ob->data; Gwn_Batch *batch = DRW_mesh_batch_cache_get_edges_with_select_id(me, offset); @@ -9772,9 +9774,11 @@ void draw_object_backbufsel( ED_view3d_polygon_offset(rv3d, 1.0); - /* we draw edges always, for loop (select) tools */ - bbs_mesh_wire(em, dm, bm_solidoffs); - bm_wireoffs = bm_solidoffs + em->bm->totedge; + /* we draw edges if edge select mode */ + if (ts->selectmode & SCE_SELECT_EDGE) { + bbs_mesh_wire(em, dm, bm_solidoffs); + bm_wireoffs = bm_solidoffs + em->bm->totedge; + } /* we draw verts if vert select mode. */ if (ts->selectmode & SCE_SELECT_VERTEX) { diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index f138b014d03..7cf1573de43 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -67,6 +67,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "RE_engine.h" #include "RE_pipeline.h" @@ -1038,6 +1039,75 @@ static void view3d_main_region_listener( } } +static void view3d_main_region_message_subscribe( + const struct bContext *UNUSED(C), + struct WorkSpace *workspace, struct Scene *scene, + struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar, + struct wmMsgBus *mbus) +{ + /* Developer note: there are many properties that impact 3D view drawing, + * so instead of subscribing to individual properties, just subscribe to types + * accepting some redundant redraws. + * + * For other space types we might try avoid this, keep the 3D view as an exceptional case! */ + ViewRender *view_render = BKE_viewrender_get(scene, workspace); + wmMsgParams_RNA msg_key_params = {0}; + + /* Only subscribe to types. */ + StructRNA *type_array[] = { + /* These object have properties that impact drawing. */ + &RNA_AreaLamp, + &RNA_Camera, + &RNA_Lamp, + &RNA_Speaker, + &RNA_SunLamp, + + /* General types the 3D view depends on. */ + &RNA_Object, + &RNA_UnitSettings, /* grid-floor */ + + &RNA_ViewRenderSettings, + &RNA_World, + }; + + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + for (int i = 0; i < ARRAY_SIZE(type_array); i++) { + msg_key_params.ptr.type = type_array[i]; + WM_msg_subscribe_rna_params( + mbus, + &msg_key_params, + &msg_sub_value_region_tag_redraw, + __func__); + } + + /* Subscribe to a handful of other properties. */ + RegionView3D *rv3d = ar->regiondata; + + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_region_tag_redraw); + if (rv3d->persp == RV3D_CAMOB) { + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, use_border, &msg_sub_value_region_tag_redraw); + } + + /* Each engine could be responsible for its own engine data types. + * For now this is simplest. */ + if (STREQ(view_render->engine_id, RE_engine_id_BLENDER_EEVEE)) { + extern StructRNA RNA_ViewLayerEngineSettingsEevee; + WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsEevee, &msg_sub_value_region_tag_redraw); + } + else if (STREQ(view_render->engine_id, RE_engine_id_BLENDER_CLAY)) { + extern StructRNA RNA_ViewLayerEngineSettingsClay; + WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsClay, &msg_sub_value_region_tag_redraw); + } +} + /* concept is to retrieve cursor type context-less */ static void view3d_main_region_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar)) { @@ -1379,6 +1449,7 @@ void ED_spacetype_view3d(void) art->free = view3d_main_region_free; art->duplicate = view3d_main_region_duplicate; art->listener = view3d_main_region_listener; + art->message_subscribe = view3d_main_region_message_subscribe; art->cursor = view3d_main_region_cursor; art->lock = 1; /* can become flag, see BKE_spacedata_draw_locks */ BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 8024a733f40..6ea2ff10af2 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -90,6 +90,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "RNA_access.h" + #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -1931,8 +1933,8 @@ static void view3d_stereo3d_setup_offscreen( void ED_view3d_draw_offscreen_init(const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, View3D *v3d) { - RenderEngineType *type = eval_ctx->engine; - if (type->flag & RE_USE_LEGACY_PIPELINE) { + RenderEngineType *engine_type = eval_ctx->engine_type; + if (engine_type->flag & RE_USE_LEGACY_PIPELINE) { /* shadow buffers, before we setup matrices */ if (draw_glsl_material(scene, view_layer, NULL, v3d, v3d->drawtype)) { VP_deprecated_gpu_update_lamps_shadows_world(eval_ctx, scene, v3d); @@ -2014,8 +2016,8 @@ void ED_view3d_draw_offscreen( view3d_main_region_setup_view(eval_ctx, scene, v3d, ar, viewmat, winmat, NULL); /* main drawing call */ - RenderEngineType *type = eval_ctx->engine; - if (type->flag & RE_USE_LEGACY_PIPELINE) { + RenderEngineType *engine_type = eval_ctx->engine_type; + if (engine_type->flag & RE_USE_LEGACY_PIPELINE) { /* framebuffer fx needed, we need to draw offscreen first */ if (v3d->fx_settings.fx_flag && fx) { @@ -2058,7 +2060,7 @@ void ED_view3d_draw_offscreen( /* XXX, should take depsgraph as arg */ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false); BLI_assert(depsgraph != NULL); - DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine, ar, v3d, ofs); + DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine_type, ar, v3d, ofs); } /* restore size */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_camera.c b/source/blender/editors/space_view3d/view3d_manipulator_camera.c index a4d408eedc6..d020571930a 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_camera.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_camera.c @@ -45,6 +45,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "view3d_intern.h" /* own include */ @@ -217,6 +218,55 @@ static void WIDGETGROUP_camera_refresh(const bContext *C, wmManipulatorGroup *mg } +static void WIDGETGROUP_camera_message_subscribe( + const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) +{ + ARegion *ar = CTX_wm_region(C); + Object *ob = CTX_data_active_object(C); + Camera *ca = ob->data; + + wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = { + .owner = ar, + .user_data = mgroup->parent_mmap, + .notify = WM_manipulator_do_msg_notify_tag_refresh, + }; + + { + extern PropertyRNA rna_Camera_dof_distance; + extern PropertyRNA rna_Camera_draw_size; + extern PropertyRNA rna_Camera_ortho_scale; + extern PropertyRNA rna_Camera_sensor_fit; + extern PropertyRNA rna_Camera_sensor_width; + extern PropertyRNA rna_Camera_shift_x; + extern PropertyRNA rna_Camera_shift_y; + extern PropertyRNA rna_Camera_type; + const PropertyRNA *props[] = { + &rna_Camera_dof_distance, + &rna_Camera_draw_size, + &rna_Camera_ortho_scale, + &rna_Camera_sensor_fit, + &rna_Camera_sensor_width, + &rna_Camera_shift_x, + &rna_Camera_shift_y, + &rna_Camera_type, + }; + + PointerRNA idptr; + RNA_id_pointer_create(&ca->id, &idptr); + + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__); + } + } + + /* Subscribe to render settings */ + { + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_mpr_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_mpr_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_mpr_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_mpr_tag_refresh); + } +} void VIEW3D_WGT_camera(wmManipulatorGroupType *wgt) { @@ -230,6 +280,7 @@ void VIEW3D_WGT_camera(wmManipulatorGroupType *wgt) wgt->poll = WIDGETGROUP_camera_poll; wgt->setup = WIDGETGROUP_camera_setup; wgt->refresh = WIDGETGROUP_camera_refresh; + wgt->message_subscribe = WIDGETGROUP_camera_message_subscribe; } /** \} */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c index 0495d1d696c..230b4f44c16 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c @@ -272,7 +272,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) } else if (state == RULER_STATE_DRAG) { ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine(C), 0, + CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine_type(C), 0, ruler_info->ar, CTX_wm_view3d(C)); } else { diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 568343f8ec8..79fa9e14dc1 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -46,6 +46,7 @@ #include "BKE_appdir.h" #include "BKE_blender_copybuffer.h" #include "BKE_context.h" +#include "BKE_group.h" #include "BKE_main.h" #include "BKE_report.h" @@ -81,14 +82,16 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) CTX_DATA_END; for (Group *group = bmain->group.first; group; group = group->id.next) { - for (GroupObject *go = group->gobject.first; go; go = go->next) { - if (go->ob && (go->ob->id.tag & LIB_TAG_DOIT)) { + FOREACH_GROUP_OBJECT(group, object) + { + if (object && (object->id.tag & LIB_TAG_DOIT)) { BKE_copybuffer_tag_ID(&group->id); /* don't expand out to all other objects */ group->id.tag &= ~LIB_TAG_NEED_EXPAND; break; } } + FOREACH_GROUP_OBJECT_END } BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index 5d213962ae9..093425fc3bc 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -282,7 +282,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) } else if (state == RULER_STATE_DRAG) { ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine(C), 0, + CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine_type(C), 0, ruler_info->ar, CTX_wm_view3d(C)); } else { diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 4658ca566d2..28e15b3bfee 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -113,7 +113,7 @@ void view3d_set_viewcontext(bContext *C, ViewContext *vc) vc->depsgraph = CTX_data_depsgraph(C); vc->scene = CTX_data_scene(C); vc->view_layer = CTX_data_view_layer(C); - vc->engine = CTX_data_engine(C); + vc->engine_type = CTX_data_engine_type(C); vc->v3d = CTX_wm_view3d(C); vc->win = CTX_wm_window(C); vc->rv3d = CTX_wm_region_view3d(C); diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 2901588b040..76da1faf530 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -251,7 +251,7 @@ typedef struct WalkInfo { ARegion *ar; Scene *scene; ViewLayer *view_layer; - RenderEngineType *engine; + RenderEngineType *engine_type; wmTimer *timer; /* needed for redraws */ @@ -515,7 +515,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->ar = CTX_wm_region(C); walk->scene = CTX_data_scene(C); walk->view_layer = CTX_data_view_layer(C); - walk->engine = CTX_data_engine(C); + walk->engine_type = CTX_data_engine_type(C); #ifdef NDOF_WALK_DEBUG puts("\n-- walk begin --"); @@ -604,7 +604,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->rv3d->rflag |= RV3D_NAVIGATING; walk->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), walk->scene, walk->view_layer, walk->engine, 0, + CTX_data_main(C), walk->scene, walk->view_layer, walk->engine_type, 0, walk->ar, walk->v3d); walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index b6a9ba1079a..d9bfcd0c289 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -470,7 +470,7 @@ typedef struct TransInfo { struct ARegion *ar; struct Scene *scene; struct ViewLayer *view_layer; - struct RenderEngineType *engine; + struct RenderEngineType *engine_type; struct ToolSettings *settings; struct wmTimer *animtimer; struct wmKeyMap *keymap; /* so we can do lookups for header text */ diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 89c43187bd4..730ca70547b 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -119,6 +119,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "transform.h" #include "bmesh.h" @@ -1890,7 +1891,6 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) { TransData *td = NULL; TransDataExtension *tx; - Base *base = CTX_data_active_base(C); Object *ob = CTX_data_active_object(C); ParticleEditSettings *pset = PE_settings(t->scene); PTCacheEdit *edit = PE_get_current(t->scene, t->view_layer, ob); @@ -1910,8 +1910,6 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) if (psys) psmd = psys_get_modifier(ob, psys); - base->flag |= BA_HAS_RECALC_DATA; - for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) { point->flag &= ~PEP_TRANSFORM; transformparticle = 0; @@ -2485,7 +2483,7 @@ static void createTransEditVerts(TransInfo *t) int *island_vert_map = NULL; DEG_evaluation_context_init_from_scene(&eval_ctx, - t->scene, t->view_layer, t->engine, + t->scene, t->view_layer, t->engine_type, DAG_EVAL_VIEWPORT); /* Even for translation this is needed because of island-orientation, see: T51651. */ @@ -5531,6 +5529,37 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) } } +static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer) +{ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + base->object->id.tag &= ~LIB_TAG_DOIT; + } +} + +static void set_trans_object_base_deps_flag_cb(ID *id, void *UNUSED(user_data)) +{ + /* Here we only handle object IDs. */ + if (GS(id->name) != ID_OB) { + return; + } + id->tag |= LIB_TAG_DOIT; +} + +static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object) +{ + object->id.tag |= LIB_TAG_DOIT; + DEG_foreach_dependent_ID(depsgraph, &object->id, + set_trans_object_base_deps_flag_cb, NULL); +} + +static void trans_object_base_deps_flag_finish(ViewLayer *view_layer) +{ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (base->object->id.tag & LIB_TAG_DOIT) { + base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO; + } + } +} /* sets flags in Bases to define whether they take part in transform */ /* it deselects Bases, so we have to call the clear function always after */ @@ -5541,47 +5570,30 @@ static void set_trans_object_base_flags(TransInfo *t) ViewLayer *view_layer = t->view_layer; Scene *scene = t->scene; Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); - - /* - * if Base selected and has parent selected: - * base->flag_legacy = BA_WAS_SEL + /* NOTE: if Base selected and has parent selected: + * base->flag_legacy = BA_WAS_SEL */ - Base *base; - - /* don't do it if we're not actually going to recalculate anything */ - if (t->mode == TFM_DUMMY) + /* Don't do it if we're not actually going to recalculate anything. */ + if (t->mode == TFM_DUMMY) { return; - - /* makes sure base flags and object flags are identical */ + } + /* Makes sure base flags and object flags are identical. */ BKE_scene_base_flag_to_objects(t->view_layer); - /* Make sure depsgraph is here. */ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer); - - /* handle pending update events, otherwise they got copied below */ - EvaluationContext eval_ctx; - DEG_evaluation_context_init_from_scene(&eval_ctx, - t->scene, t->view_layer, t->engine, - DAG_EVAL_VIEWPORT); - for (base = view_layer->object_bases.first; base; base = base->next) { - if (base->object->recalc & OB_RECALC_ALL) { - /* TODO(sergey): Ideally, it's not needed. */ - BKE_object_handle_update(&eval_ctx, t->scene, base->object); - } - } - - for (base = view_layer->object_bases.first; base; base = base->next) { + /* Clear all flags we need. It will be used to detect dependencies. */ + trans_object_base_deps_flag_prepare(view_layer); + /* Traverse all bases and set all possible flags. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { base->flag_legacy &= ~BA_WAS_SEL; - if (TESTBASELIB_BGMODE(base)) { Object *ob = base->object; Object *parsel = ob->parent; - - /* if parent selected, deselect */ - while (parsel) { + /* If parent selected, deselect. */ + while (parsel != NULL) { if (parsel->base_flag & BASE_SELECTED) { Base *parbase = BKE_view_layer_base_find(view_layer, parsel); - if (parbase) { /* in rare cases this can fail */ + if (parbase != NULL) { /* in rare cases this can fail */ if (TESTBASELIB_BGMODE(parbase)) { break; } @@ -5589,9 +5601,8 @@ static void set_trans_object_base_flags(TransInfo *t) } parsel = parsel->parent; } - - if (parsel) { - /* rotation around local centers are allowed to propagate */ + if (parsel != NULL) { + /* Rotation around local centers are allowed to propagate. */ if ((t->around == V3D_AROUND_LOCAL_ORIGINS) && (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) { @@ -5602,21 +5613,13 @@ static void set_trans_object_base_flags(TransInfo *t) base->flag_legacy |= BA_WAS_SEL; } } - DEG_id_tag_update(&ob->id, OB_RECALC_OB); + flush_trans_object_base_deps_flag(depsgraph, ob); } } - - /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ - DEG_graph_flush_update(bmain, depsgraph); - - /* and we store them temporal in base (only used for transform code) */ - /* this because after doing updates, the object->recalc is cleared */ - for (base = view_layer->object_bases.first; base; base = base->next) { - if (base->object->recalc & OB_RECALC_OB) - base->flag_legacy |= BA_HAS_RECALC_OB; - if (base->object->recalc & OB_RECALC_DATA) - base->flag_legacy |= BA_HAS_RECALC_DATA; - } + /* Store temporary bits in base indicating that base is being modified + * (directly or indirectly) by transforming objects. + */ + trans_object_base_deps_flag_finish(view_layer); } static bool mark_children(Object *ob) @@ -5637,32 +5640,28 @@ static bool mark_children(Object *ob) static int count_proportional_objects(TransInfo *t) { int total = 0; - /* TODO(sergey): Get rid of global, use explicit main. */ - Main *bmain = G.main; ViewLayer *view_layer = t->view_layer; Scene *scene = t->scene; Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); - Base *base; - - /* rotations around local centers are allowed to propagate, so we take all objects */ + /* Clear all flags we need. It will be used to detect dependencies. */ + trans_object_base_deps_flag_prepare(view_layer); + /* Rotations around local centers are allowed to propagate, so we take all objects. */ if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) && (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) { - /* mark all parents */ - for (base = view_layer->object_bases.first; base; base = base->next) { + /* Mark all parents. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { if (TESTBASELIB_BGMODE(base)) { Object *parent = base->object->parent; - /* flag all parents */ - while (parent) { + while (parent != NULL) { parent->flag |= BA_TRANSFORM_PARENT; parent = parent->parent; } } } - - /* mark all children */ - for (base = view_layer->object_bases.first; base; base = base->next) { + /* Mark all children. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { /* all base not already selected or marked that is editable */ if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && (base->flag & BASE_SELECTED) == 0 && @@ -5672,36 +5671,24 @@ static int count_proportional_objects(TransInfo *t) } } } - - for (base = view_layer->object_bases.first; base; base = base->next) { + /* Flush changed flags to all dependencies. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { Object *ob = base->object; - - /* if base is not selected, not a parent of selection or not a child of selection and it is editable */ + /* If base is not selected, not a parent of selection or not a child of + * selection and it is editable. + */ if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && (base->flag & BASE_SELECTED) == 0 && (BASE_EDITABLE_BGMODE(base))) { - - DEG_id_tag_update(&ob->id, OB_RECALC_OB); - + flush_trans_object_base_deps_flag(depsgraph, ob); total += 1; } } - - - /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ - DEG_graph_relations_update(depsgraph, bmain, scene, view_layer); - DEG_graph_flush_update(bmain, depsgraph); - - /* and we store them temporal in base (only used for transform code) */ - /* this because after doing updates, the object->recalc is cleared */ - for (base = view_layer->object_bases.first; base; base = base->next) { - if (base->object->recalc & OB_RECALC_OB) - base->flag_legacy |= BA_HAS_RECALC_OB; - if (base->object->recalc & OB_RECALC_DATA) - base->flag_legacy |= BA_HAS_RECALC_DATA; - } - + /* Store temporary bits in base indicating that base is being modified + * (directly or indirectly) by transforming objects. + */ + trans_object_base_deps_flag_finish(view_layer); return total; } @@ -5715,7 +5702,7 @@ static void clear_trans_object_base_flags(TransInfo *t) base->flag |= BASE_SELECTED; } - base->flag_legacy &= ~(BA_WAS_SEL | BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT); + base->flag_legacy &= ~(BA_WAS_SEL | BA_SNAP_FIX_DEPS_FIASCO | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT); } } @@ -6489,12 +6476,16 @@ void special_aftertrans_update(bContext *C, TransInfo *t) DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } else if (arm->flag & ARM_DELAYDEFORM) { - /* old optimize trick... this enforces to bypass the depgraph */ + /* TODO(sergey): Armature is already updated by recalcData(), so we + * might save some time by skipping re-evaluating it. But this isn't + * possible yet within new dependency graph, and also other contexts + * might need to update their CoW copies. + */ DEG_id_tag_update(&ob->id, OB_RECALC_DATA); - ob->recalc = 0; // is set on OK position already by recalcData() } - else + else { DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + } } else if (t->options & CTX_PAINT_CURVE) { @@ -8291,7 +8282,7 @@ void createTransData(bContext *C, TransInfo *t) RegionView3D *rv3d = t->ar->regiondata; if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) { /* we could have a flag to easily check an object is being transformed */ - if (v3d->camera->recalc) { + if (v3d->camera->id.tag & LIB_TAG_DOIT) { t->flag |= T_CAMERA; } } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index f6ec93d8ff9..10a7677f42b 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1123,12 +1123,12 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve Object *obedit = CTX_data_edit_object(C); Object *ob = CTX_data_active_object(C); bGPdata *gpd = CTX_data_gpencil_data(C); - RenderEngineType *engine = CTX_data_engine(C); + RenderEngineType *engine_type = CTX_data_engine_type(C); PropertyRNA *prop; t->scene = sce; t->view_layer = view_layer; - t->engine = engine; + t->engine_type = engine_type; t->sa = sa; t->ar = ar; t->obedit = obedit; diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index ee722397f91..0e0c2f3ae25 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -65,6 +65,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "ED_armature.h" #include "ED_curve.h" @@ -1115,6 +1116,47 @@ static void manipulator_line_range(const View3D *v3d, const short axis_type, flo *r_len -= *r_start; } +static void manipulator_xform_message_subscribe( + wmManipulatorGroup *mgroup, struct wmMsgBus *mbus, + bScreen *screen, ScrArea *sa, ARegion *ar, const void *type_fn) +{ + /* Subscribe to view properties */ + wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = { + .owner = ar, + .user_data = mgroup->parent_mmap, + .notify = WM_manipulator_do_msg_notify_tag_refresh, + }; + + PointerRNA space_ptr; + RNA_pointer_create(&screen->id, &RNA_SpaceView3D, sa->spacedata.first, &space_ptr); + + { + extern PropertyRNA rna_SpaceView3D_transform_orientation; + const PropertyRNA *props[] = { + &rna_SpaceView3D_transform_orientation, + }; + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &space_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__); + } + } + + if (type_fn == TRANSFORM_WGT_manipulator) { + extern PropertyRNA rna_SpaceView3D_pivot_point; + const PropertyRNA *props[] = { + &rna_SpaceView3D_pivot_point + }; + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &space_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__); + } + } + else if (type_fn == VIEW3D_WGT_xform_cage) { + /* pass */ + } + else { + BLI_assert(0); + } +} + /** \} */ @@ -1383,6 +1425,15 @@ static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGrou MAN_ITER_AXES_END; } +static void WIDGETGROUP_manipulator_message_subscribe( + const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) +{ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + manipulator_xform_message_subscribe(mgroup, mbus, screen, sa, ar, TRANSFORM_WGT_manipulator); +} + static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) { ManipulatorGroup *man = mgroup->customdata; @@ -1464,6 +1515,7 @@ void TRANSFORM_WGT_manipulator(wmManipulatorGroupType *wgt) wgt->poll = WIDGETGROUP_manipulator_poll; wgt->setup = WIDGETGROUP_manipulator_setup; wgt->refresh = WIDGETGROUP_manipulator_refresh; + wgt->message_subscribe = WIDGETGROUP_manipulator_message_subscribe; wgt->draw_prepare = WIDGETGROUP_manipulator_draw_prepare; } @@ -1500,7 +1552,7 @@ static void WIDGETGROUP_xform_cage_setup(const bContext *UNUSED(C), wmManipulato ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE); mpr->color[0] = 1; - mpr->color_hi[0]=1; + mpr->color_hi[0] =1; mgroup->customdata = xmgroup; @@ -1585,6 +1637,15 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmManipulatorGroup } } +static void WIDGETGROUP_xform_cage_message_subscribe( + const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) +{ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + manipulator_xform_message_subscribe(mgroup, mbus, screen, sa, ar, VIEW3D_WGT_xform_cage); +} + static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) { struct XFormCageWidgetGroup *xmgroup = mgroup->customdata; @@ -1613,6 +1674,7 @@ void VIEW3D_WGT_xform_cage(wmManipulatorGroupType *wgt) wgt->poll = WIDGETGROUP_xform_cage_poll; wgt->setup = WIDGETGROUP_xform_cage_setup; wgt->refresh = WIDGETGROUP_xform_cage_refresh; + wgt->message_subscribe = WIDGETGROUP_xform_cage_message_subscribe; wgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare; } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 6b3167a0392..30aad46843d 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -300,9 +300,7 @@ void applyProject(TransInfo *t) mul_m4_v3(ob->obmat, iloc); } else if (t->flag & T_OBJECT) { - /* TODO(sergey): Ideally force update is not needed here. */ - td->ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME; - BKE_object_handle_update(G.main->eval_ctx, t->scene, td->ob); + BKE_object_eval_transform_all(G.main->eval_ctx, t->scene, td->ob); copy_v3_v3(iloc, td->ob->obmat[3]); } @@ -391,8 +389,7 @@ void applyGridAbsolute(TransInfo *t) mul_m4_v3(obmat, iloc); } else if (t->flag & T_OBJECT) { - td->ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME; - BKE_object_handle_update(G.main->eval_ctx, t->scene, td->ob); + BKE_object_eval_transform_all(G.main->eval_ctx, t->scene, td->ob); copy_v3_v3(iloc, td->ob->obmat[3]); } @@ -585,7 +582,7 @@ static void initSnappingMode(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { if (t->tsnap.object_context == NULL) { t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( - G.main, t->scene, t->view_layer, t->engine, 0, + G.main, t->scene, t->view_layer, t->engine_type, 0, t->ar, t->view); ED_transform_snap_object_context_set_editmesh_callbacks( diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 61705ba2868..ce8de2ef4d3 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -161,17 +161,8 @@ static void iter_snap_objects( void *data) { Base *base_act = sctx->eval_ctx.view_layer->basact; - /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA - * which makes the loop skip it, even the derived mesh will never change - * - * To solve that problem, we do it first as an exception. - * */ - if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) { - sob_callback(sctx, false, base_act->object, base_act->object->obmat, data); - } - for (Base *base = sctx->eval_ctx.view_layer->object_bases.first; base != NULL; base = base->next) { - if ((BASE_VISIBLE(base)) && (base->flag_legacy & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && + if ((BASE_VISIBLE(base)) && (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) == 0 && !((snap_select == SNAP_NOT_SELECTED && ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) || (snap_select == SNAP_NOT_ACTIVE && base == base_act))) { @@ -2096,7 +2087,7 @@ static bool snapObjectsRay( * \{ */ SnapObjectContext *ED_transform_snap_object_context_create( - Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine, int flag) + Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine_type, int flag) { SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__); @@ -2105,7 +2096,7 @@ SnapObjectContext *ED_transform_snap_object_context_create( sctx->bmain = bmain; sctx->scene = scene; - DEG_evaluation_context_init_from_scene(&sctx->eval_ctx, scene, view_layer, engine, DAG_EVAL_VIEWPORT); + DEG_evaluation_context_init_from_scene(&sctx->eval_ctx, scene, view_layer, engine_type, DAG_EVAL_VIEWPORT); sctx->cache.object_map = BLI_ghash_ptr_new(__func__); sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); @@ -2114,11 +2105,11 @@ SnapObjectContext *ED_transform_snap_object_context_create( } SnapObjectContext *ED_transform_snap_object_context_create_view3d( - Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine, int flag, + Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine_type, int flag, /* extra args for view3d */ const ARegion *ar, const View3D *v3d) { - SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, view_layer, engine, flag); + SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, view_layer, engine_type, flag); sctx->use_v3d = true; sctx->v3d_data.ar = ar; diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c index 61142fdc887..0f3240946fd 100644 --- a/source/blender/editors/util/numinput.c +++ b/source/blender/editors/util/numinput.c @@ -488,8 +488,9 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event) const float fac = (float)BKE_scene_unit_scale(&sce->unit, n->unit_type[idx], 1.0); /* Make radian default unit when needed. */ - if (n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) + if (n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) { default_unit = "r"; + } BLI_strncpy(str_unit_convert, n->str, sizeof(str_unit_convert)); @@ -513,7 +514,16 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event) n->val[idx] = -n->val[idx]; } if (n->val_flag[idx] & NUM_INVERSE) { - n->val[idx] = 1.0f / n->val[idx]; + val = n->val[idx]; + /* If we invert on radians when user is in degrees, you get unexpected results... See T53463. */ + if (!n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) { + val = RAD2DEG(val); + } + val = 1.0 / val; + if (!n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) { + val = DEG2RAD(val); + } + n->val[idx] = (float)val; } if (UNLIKELY(!isfinite(n->val[idx]))) { diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index c24e4994f7f..dbf1cf46c61 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -45,6 +45,7 @@ #include "BKE_blender_undo.h" #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_library_override.h" #include "BKE_main.h" #include "BKE_screen.h" @@ -82,6 +83,9 @@ void ED_undo_push(bContext *C, const char *str) if (G.debug & G_DEBUG) printf("%s: %s\n", __func__, str); + /* Always do it for now, this might need to be refined... */ + BKE_main_override_static_operations_create(CTX_data_main(C)); + if (obedit) { if (U.undosteps == 0) return; diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 6122ef99964..79f17756ca6 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -945,8 +945,8 @@ Object *BlenderStrokeRenderer::NewMesh() const ob->data = BKE_mesh_add(freestyle_bmain, name); ob->lay = 1; - SceneCollection *sc_master = BKE_collection_master(freestyle_scene); - BKE_collection_object_add(freestyle_scene, sc_master, ob); + SceneCollection *sc_master = BKE_collection_master(&freestyle_scene->id); + BKE_collection_object_add(&freestyle_scene->id, sc_master, ob); DEG_graph_tag_relations_update(freestyle_depsgraph); DEG_graph_id_tag_update(freestyle_bmain, diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h index 0e08af1bac8..79ba9421cda 100644 --- a/source/blender/freestyle/intern/system/PythonInterpreter.h +++ b/source/blender/freestyle/intern/system/PythonInterpreter.h @@ -52,7 +52,7 @@ extern "C" { #include "BPY_extern.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" } namespace Freestyle { diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index bc91df895c8..9e4daa2a036 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -1589,6 +1589,15 @@ static GPUNodeLink *gpu_uniformbuffer_link( GPUMaterial *mat, bNode *node, GPUNodeStack *stack, const int index, const eNodeSocketInOut in_out) { bNodeSocket *socket; + + /* Some nodes can have been create on the fly and does + * not have an original to point to. (i.e. the bump from + * ntree_shader_relink_displacement). In this case just + * revert to static constant folding. */ + if (node->original == NULL) { + return NULL; + } + if (in_out == SOCK_IN) { socket = BLI_findlink(&node->original->inputs, index); } diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 231f1d8f7b1..57df877bf18 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -181,7 +181,8 @@ void gpu_extensions_init(void) /* XXX : TODO : Remove this once this sampling mipmap problem is gone. * https://github.com/dfelinto/opengl-sandbox/blob/downsample/README.md */ else if (strstr(renderer, "AMD VEGA") && - strstr(vendor, "X.Org")) { + strstr(vendor, "X.Org")) + { GG.device = GPU_DEVICE_AMD_VEGA; GG.driver = GPU_DRIVER_OPENSOURCE; } diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 0a8ef9dffc5..e2883b53047 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -516,9 +516,9 @@ static float gaussian_profile(float r, float radius) const float v = radius * radius * (0.25f * 0.25f); const float Rm = sqrtf(v * GAUSS_TRUNCATE); - if(r >= Rm) + if (r >= Rm) { return 0.0f; - + } return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v); } @@ -535,20 +535,20 @@ static float cubic_profile(float r, float radius, float sharpness) { float Rm = radius * (1.0f + sharpness); - if(r >= Rm) + if (r >= Rm) { return 0.0f; - + } /* custom variation with extra sharpness, to match the previous code */ - const float y = 1.0f/(1.0f + sharpness); + const float y = 1.0f / (1.0f + sharpness); float Rmy, ry, ryinv; Rmy = powf(Rm, y); ry = powf(r, y); - ryinv = (r > 0.0f)? powf(r, y - 1.0f): 0.0f; + ryinv = (r > 0.0f) ? powf(r, y - 1.0f) : 0.0f; - const float Rmy5 = (Rmy*Rmy) * (Rmy*Rmy) * Rmy; + const float Rmy5 = (Rmy * Rmy) * (Rmy * Rmy) * Rmy; const float f = Rmy - ry; - const float num = f*(f*f)*(y*ryinv); + const float num = f * (f * f) * (y * ryinv); return (10.0f * num) / (Rmy5 * M_PI); } @@ -576,7 +576,7 @@ static float eval_integral(float x0, float x1, short falloff_type, float sharpne const float step = range / INTEGRAL_RESOLUTION; float integral = 0.0f; - for(int i = 0; i < INTEGRAL_RESOLUTION; ++i) { + for (int i = 0; i < INTEGRAL_RESOLUTION; ++i) { float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION; float y = eval_profile(x, falloff_type, sharpness, param); integral += y * step; diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 030b0808b54..4e1161148ea 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -115,6 +115,76 @@ enum { /* add any future new id property types here.*/ + +/* Static ID override structs. */ + +typedef struct IDOverrideStaticPropertyOperation { + struct IDOverrideStaticPropertyOperation *next, *prev; + + /* Type of override. */ + short operation; + short flag; + short pad_s1[2]; + + /* Sub-item references, if needed (for arrays or collections only). + * We need both reference and local values to allow e.g. insertion into collections (constraints, modifiers...). + * In collection case, if names are defined, they are used in priority. + * Names are pointers (instead of char[64]) to save some space, NULL when unset. + * Indices are -1 when unset. */ + char *subitem_reference_name; + char *subitem_local_name; + int subitem_reference_index; + int subitem_local_index; +} IDOverrideStaticPropertyOperation; + +/* IDOverridePropertyOperation->operation. */ +enum { + /* Basic operations. */ + IDOVERRIDESTATIC_OP_NOOP = 0, /* Special value, forbids any overriding. */ + + IDOVERRIDESTATIC_OP_REPLACE = 1, /* Fully replace local value by reference one. */ + + /* Numeric-only operations. */ + IDOVERRIDESTATIC_OP_ADD = 101, /* Add local value to reference one. */ + /* Subtract local value from reference one (needed due to unsigned values etc.). */ + IDOVERRIDESTATIC_OP_SUBTRACT = 102, + /* Multiply reference value by local one (more useful than diff for scales and the like). */ + IDOVERRIDESTATIC_OP_MULTIPLY = 103, + + /* Collection-only operations. */ + IDOVERRIDESTATIC_OP_INSERT_AFTER = 201, /* Insert after given reference's subitem. */ + IDOVERRIDESTATIC_OP_INSERT_BEFORE = 202, /* Insert before given reference's subitem. */ + /* We can add more if needed (move, delete, ...). */ +}; + +/* IDOverridePropertyOperation->flag. */ +enum { + IDOVERRIDESTATIC_FLAG_MANDATORY = 1 << 0, /* User cannot remove that override operation. */ + IDOVERRIDESTATIC_FLAG_LOCKED = 1 << 1, /* User cannot change that override operation. */ +}; + +/* A single overriden property, contain all operations on this one. */ +typedef struct IDOverrideStaticProperty { + struct IDOverrideStaticProperty *next, *prev; + + /* Path from ID to overridden property. *Does not* include indices/names for final arrays/collections items. */ + char *rna_path; + + ListBase operations; /* List of overriding operations (IDOverridePropertyOperation) applied to this property. */ +} IDOverrideStaticProperty; + +/* Main container for all overriding data info of a data-block. */ +typedef struct IDOverrideStatic { + struct ID *reference; /* Reference linked ID which this one overrides. */ + ListBase properties; /* List of IDOverrideProperty structs. */ + + /* Read/write data. */ + /* Temp ID storing extra override data (used for differential operations only currently). + * Always NULL outside of read/write context. */ + struct ID *storage; +} IDOverrideStatic; + + /* watch it: Sequence has identical beginning. */ /** * ID is the first thing included in all serializable types. It @@ -142,7 +212,12 @@ typedef struct ID { int us; int icon_id; IDProperty *properties; + + IDOverrideStatic *override_static; /* Reference linked ID which this one overrides. */ + void *py_instance; + + void *pad1; } ID; /** @@ -309,7 +384,8 @@ typedef enum ID_Type { /* id->flag (persitent). */ enum { - LIB_FAKEUSER = 1 << 9, + LIB_OVERRIDE_STATIC_AUTO = 1 << 0, /* Allow automatic generation of overriding rules. */ + LIB_FAKEUSER = 1 << 9, }; /** @@ -344,6 +420,9 @@ enum { /* RESET_NEVER tag datablock as a place-holder (because the real one could not be linked from its library e.g.). */ LIB_TAG_MISSING = 1 << 6, + /* RESET_NEVER tag datablock as being up-to-date regarding its reference. */ + LIB_TAG_OVERRIDESTATIC_OK = 1 << 9, + /* tag datablock has having an extra user. */ LIB_TAG_EXTRAUSER = 1 << 2, /* tag datablock has having actually increased usercount for the extra virtual user. */ @@ -353,7 +432,7 @@ enum { * Also used internally in readfile.c to mark datablocks needing do_versions. */ LIB_TAG_NEW = 1 << 8, /* RESET_BEFORE_USE free test flag. - * TODO make it a RESET_AFTER_USE too. */ + * TODO make it a RESET_AFTER_USE too. */ LIB_TAG_DOIT = 1 << 10, /* RESET_AFTER_USE tag existing data before linking so we know what is new. */ LIB_TAG_PRE_EXISTING = 1 << 11, diff --git a/source/blender/makesdna/DNA_group_types.h b/source/blender/makesdna/DNA_group_types.h index 45dd0cb9ff2..8f15aa85e97 100644 --- a/source/blender/makesdna/DNA_group_types.h +++ b/source/blender/makesdna/DNA_group_types.h @@ -60,6 +60,13 @@ typedef struct Group { * on the last used scene */ unsigned int layer; float dupli_ofs[3]; + + struct SceneCollection *collection; + struct ViewLayer *view_layer; } Group; + +#define GROUP_MASTER_COLLECTION(_group) \ + (((LayerCollection *)(_group)->view_layer->layer_collections.first)->scene_collection) + #endif /* __DNA_GROUP_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 3eac7f0aab3..c677383cb6e 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -104,7 +104,8 @@ typedef struct SceneCollection { char name[64]; /* MAX_NAME */ char filter[64]; /* MAX_NAME */ int active_object_index; /* for UI */ - int pad; + char type; + char pad[3]; ListBase objects; /* (Object *)LinkData->data */ ListBase filter_objects; /* (Object *)LinkData->data */ ListBase scene_collections; /* nested collections */ @@ -134,6 +135,11 @@ enum { VIEW_LAYER_FREESTYLE = (1 << 2), }; +/* SceneCollection->type */ +enum { + COLLECTION_TYPE_NONE = 0, + COLLECTION_TYPE_GROUP_INTERNAL = 1, +}; /* *************************************************************** */ /* Engine Settings */ diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index e65c36672b5..75705f7dd37 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -54,6 +54,9 @@ typedef struct LightProbe { float clipsta, clipend; + float vis_bias, vis_bleedbias; /* VSM visibility biases */ + float vis_blur, pad2; + int grid_resolution_x; /* Irradiance grid resolution */ int grid_resolution_y; int grid_resolution_z; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 6187a46dcd7..78c623f6408 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -279,7 +279,7 @@ typedef struct Object { struct BulletSoftBody *bsoft; /* settings for game engine bullet soft body */ char restrictflag; /* for restricting view, select, render etc. accessible in outliner */ - char recalc; /* dependency flag */ + char pad3; short softflag; /* softbody settings */ float anisotropicFriction[3]; @@ -326,7 +326,7 @@ typedef struct Object { struct IDProperty *base_collection_properties; /* used by depsgraph, flushed from base */ ListBase drawdata; /* runtime, ObjectEngineData */ - int deg_update_flag; /* what has been updated in this object */ + int pad1; int select_color; /* Mesh structure createrd during object evaluaiton. @@ -371,6 +371,7 @@ typedef struct DupliObject { struct ParticleSystem *particle_system; unsigned int random_id; unsigned int pad; + struct IDProperty *collection_properties; } DupliObject; /* **************** OBJECT ********************* */ @@ -531,9 +532,13 @@ enum { /* also needed for base!!!!! or rather, they interfere....*/ /* base->flag and ob->flag */ -#define BA_WAS_SEL (1 << 1) -#define BA_HAS_RECALC_OB (1 << 2) -#define BA_HAS_RECALC_DATA (1 << 3) +enum { + BA_WAS_SEL = (1 << 1), + /* NOTE: BA_HAS_RECALC_DATA can be re-used later if freed in readfile.c. */ + // BA_HAS_RECALC_OB = (1 << 2), /* DEPRECATED */ + // BA_HAS_RECALC_DATA = (1 << 3), /* DEPRECATED */ + BA_SNAP_FIX_DEPS_FIASCO = (1 << 2), /* Yes, re-use deprecated bit, all fine since it's runtime only. */ +}; /* NOTE: this was used as a proper setting in past, so nullify before using */ #define BA_TEMP_TAG (1 << 5) diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 74a1a13c2eb..b7e118d2053 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -301,6 +301,11 @@ enum { SEQ_TEXT_ALIGN_Y_BOTTOM = 2, }; +typedef struct ColorMixVars { + int blend_effect; /* value from SEQ_TYPE_XXX enumeration */ + float factor; /* blend factor [0.0f, 1.0f] */ +} ColorMixVars; + /* ***************** Sequence modifiers ****************** */ typedef struct SequenceModifierData { @@ -516,8 +521,29 @@ enum { SEQ_TYPE_ADJUSTMENT = 31, SEQ_TYPE_GAUSSIAN_BLUR = 40, SEQ_TYPE_TEXT = 41, - - SEQ_TYPE_MAX = 41 + SEQ_TYPE_COLORMIX = 42, + + /* Blend modes */ + SEQ_TYPE_SCREEN = 43, + SEQ_TYPE_LIGHTEN = 44, + SEQ_TYPE_DODGE = 45, + SEQ_TYPE_DARKEN = 46, + SEQ_TYPE_BURN = 47, + SEQ_TYPE_LINEAR_BURN = 48, + SEQ_TYPE_OVERLAY = 49, + SEQ_TYPE_HARD_LIGHT = 50, + SEQ_TYPE_SOFT_LIGHT = 51, + SEQ_TYPE_PIN_LIGHT = 52, + SEQ_TYPE_LIN_LIGHT = 53, + SEQ_TYPE_VIVID_LIGHT = 54, + SEQ_TYPE_HUE = 55, + SEQ_TYPE_SATURATION = 56, + SEQ_TYPE_VALUE = 57, + SEQ_TYPE_BLEND_COLOR = 58, + SEQ_TYPE_DIFFERENCE = 59, + SEQ_TYPE_EXCLUSION = 60, + + SEQ_TYPE_MAX = 60 }; #define SEQ_MOVIECLIP_RENDER_UNDISTORTED (1 << 0) diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 69086def4b9..27e108b82ab 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -126,7 +126,9 @@ typedef struct SpaceButs { short preview; /* preview is signal to refresh */ /* texture context selector (material, lamp, particles, world, other) */ short texture_context, texture_context_prev; - char flag, pad[7]; + char flag; + char collection_context; + char pad[6]; void *path; /* runtime */ int pathflag, dataicon; /* runtime */ @@ -208,6 +210,12 @@ typedef enum eSpaceButtons_Texture_Context { SB_TEXC_LINESTYLE = 5, } eSpaceButtons_Texture_Context; +/* sbuts->collection_context */ +typedef enum eSpaceButtons_Collection_Context { + SB_COLLECTION_CTX_VIEW_LAYER = 0, + SB_COLLECTION_CTX_GROUP = 1, +} eSpaceButtons_Collection_Context; + /* sbuts->align */ typedef enum eSpaceButtons_Align { BUT_FREE = 0, @@ -711,6 +719,8 @@ typedef enum eFileSel_Action { } eFileSel_Action; /* sfile->params->flag and simasel->flag */ +/* Note: short flag, also used as 16 lower bits of flags in link/append code + * (WM and BLO code area, see BLO_LibLinkFlags in BLO_readfile.h). */ typedef enum eFileSel_Params_Flag { FILE_SHOWSHORT = (1 << 0), FILE_RELPATH = (1 << 1), /* was FILE_STRINGCODE */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 3cdb379040c..81f605b093a 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -140,6 +140,8 @@ typedef struct uiWidgetStateColors { char inner_key_sel[4]; char inner_driven[4]; char inner_driven_sel[4]; + char inner_overridden[4]; + char inner_overridden_sel[4]; float blend, pad; } uiWidgetStateColors; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 8a313d8eda9..3792873db31 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -41,6 +41,7 @@ struct wmWindowManager; struct wmWindow; +struct wmMsgBus; struct wmEvent; struct wmGesture; struct wmOperatorType; @@ -156,6 +157,9 @@ typedef struct wmWindowManager { char is_interface_locked; /* indicates whether interface is locked for user interaction */ char par[7]; + + struct wmMsgBus *message_bus; + } wmWindowManager; /* wmWindowManager.initialized */ diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h index 1fc6acb8c2c..adc3c1fef2b 100644 --- a/source/blender/makesdna/DNA_workspace_types.h +++ b/source/blender/makesdna/DNA_workspace_types.h @@ -84,6 +84,7 @@ typedef struct WorkSpace { /* Store for each hook (so for each window) which layout has * been activated the last time this workspace was visible. */ ListBase hook_layout_relations DNA_PRIVATE_WORKSPACE_READ_WRITE; /* WorkSpaceDataRelation */ + ListBase scene_viewlayer_relations DNA_PRIVATE_WORKSPACE_READ_WRITE; /* WorkSpaceDataRelation */ /* Custom transform orientations */ ListBase transform_orientations DNA_PRIVATE_WORKSPACE; @@ -94,7 +95,7 @@ typedef struct WorkSpace { /* should be: '#ifdef USE_WORKSPACE_TOOL'. */ bToolDef tool; - struct ViewLayer *view_layer DNA_PRIVATE_WORKSPACE; + struct ViewLayer *view_layer DNA_DEPRECATED; struct ViewRender view_render; } WorkSpace; diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 182a026df94..593d93b5615 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -993,7 +993,7 @@ static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offs char str[SDNA_MAX_FILENAME_LENGTH], *cp; int firststruct; - if (debugSDNA > -1) { + if (debugSDNA > 0) { fflush(stdout); printf("Running makesdna at debug level %d\n", debugSDNA); } @@ -1089,7 +1089,7 @@ static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offs /* file writing */ - if (debugSDNA > -1) printf("Writing file ... "); + if (debugSDNA > 0) printf("Writing file ... "); if (nr_names == 0 || nr_structs == 0) { /* pass */ @@ -1199,7 +1199,7 @@ static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offs MEM_freeN(typelens_64); MEM_freeN(structs); - if (debugSDNA > -1) printf("done.\n"); + if (debugSDNA > 0) printf("done.\n"); return(0); } diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index aedc53512b7..a99541385d0 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -39,6 +39,9 @@ extern "C" { struct bContext; struct ID; +struct IDOverrideStatic; +struct IDOverrideStaticProperty; +struct IDOverrideStaticPropertyOperation; struct ListBase; struct Main; struct ReportList; @@ -118,6 +121,7 @@ extern StructRNA RNA_ColorManagedViewSettings; extern StructRNA RNA_ColorRamp; extern StructRNA RNA_ColorRampElement; extern StructRNA RNA_ColorSequence; +extern StructRNA RNA_ColorMixSequence; extern StructRNA RNA_CompositorNode; extern StructRNA RNA_CompositorNodeAlphaOver; extern StructRNA RNA_CompositorNodeBilateralblur; @@ -737,6 +741,7 @@ extern StructRNA RNA_XorController; void RNA_main_pointer_create(struct Main *main, PointerRNA *r_ptr); void RNA_id_pointer_create(struct ID *id, PointerRNA *r_ptr); void RNA_pointer_create(struct ID *id, StructRNA *type, void *data, PointerRNA *r_ptr); +bool RNA_pointer_is_null(const PointerRNA *ptr); bool RNA_path_resolved_create( PointerRNA *ptr, struct PropertyRNA *prop, @@ -1042,7 +1047,7 @@ char *RNA_path_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int * call RNA_struct_find_property. The names have to exist as RNA properties * for the type in the pointer, if they do not exist an error will be printed. * - * There is no support for pointers and collections here yet, these can be + * There is no support for pointers and collections here yet, these can be * added when ID properties support them. */ int RNA_boolean_get(PointerRNA *ptr, const char *name); @@ -1140,7 +1145,7 @@ bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop); void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop); bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost); bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier); -bool RNA_property_is_idprop(PropertyRNA *prop); +bool RNA_property_is_idprop(const PropertyRNA *prop); bool RNA_property_is_unlink(PropertyRNA *prop); void RNA_struct_property_unset(PointerRNA *ptr, const char *identifier); @@ -1209,9 +1214,8 @@ int RNA_function_call_direct_va(struct bContext *C, struct ReportList *reports, int RNA_function_call_direct_va_lookup(struct bContext *C, struct ReportList *reports, PointerRNA *ptr, const char *identifier, const char *format, va_list args); -const char *RNA_translate_ui_text(const char *text, const char *text_ctxt, - struct StructRNA *type, struct PropertyRNA *prop, - int translate); +const char *RNA_translate_ui_text( + const char *text, const char *text_ctxt, struct StructRNA *type, struct PropertyRNA *prop, int translate); /* ID */ @@ -1235,17 +1239,51 @@ StructRNA *ID_code_to_RNA_type(short idcode); void _RNA_warning(const char *format, ...) ATTR_PRINTF_FORMAT(1, 2); -/* Equals test (skips pointers and collections) - * is_strict false assumes uninitialized properties are equal */ +/* Equals test. */ -typedef enum eRNAEqualsMode { - RNA_EQ_STRICT, /* set/unset ignored */ - RNA_EQ_UNSET_MATCH_ANY, /* unset property matches anything */ - RNA_EQ_UNSET_MATCH_NONE /* unset property never matches set property */ -} eRNAEqualsMode; +/* Note: In practice, EQ_STRICT and EQ_COMPARE have same behavior currently, and will yield same result. */ +typedef enum eRNACompareMode { + /* Only care about equality, not full comparison. */ + RNA_EQ_STRICT, /* set/unset ignored */ + RNA_EQ_UNSET_MATCH_ANY, /* unset property matches anything */ + RNA_EQ_UNSET_MATCH_NONE, /* unset property never matches set property */ + /* Full comparison. */ + RNA_EQ_COMPARE, +} eRNACompareMode; -bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, eRNAEqualsMode mode); -bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, eRNAEqualsMode mode); +bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, eRNACompareMode mode); +bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, eRNACompareMode mode); + +/* Override. */ + +bool RNA_struct_override_matches(struct PointerRNA *local, struct PointerRNA *reference, + struct IDOverrideStatic *override, const bool ignore_non_overridable, const bool ignore_overridden); + +bool RNA_struct_override_store( + struct PointerRNA *local, struct PointerRNA *reference, PointerRNA *storage, struct IDOverrideStatic *override); + +void RNA_property_override_apply( + struct PointerRNA *dst, struct PointerRNA *src, struct PointerRNA *storage, struct PropertyRNA *prop, + struct IDOverrideStaticProperty *op); +void RNA_struct_override_apply( + struct PointerRNA *dst, struct PointerRNA *src, struct PointerRNA *storage, + struct IDOverrideStatic *override); + +bool RNA_struct_auto_override( + struct PointerRNA *local, struct PointerRNA *reference, struct IDOverrideStatic *override, const char *root_path); + +struct IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop); +struct IDOverrideStaticProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created); + +struct IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_find( + PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict); +struct IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_get( + PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index, + const bool strict, bool *r_strict, bool *r_created); + +void RNA_property_override_status( + PointerRNA *ptr, PropertyRNA *prop, const int index, + bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked); #ifdef __cplusplus } diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index e9e4276b235..4e32651d356 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -177,6 +177,8 @@ void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *update void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable); void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable); +void RNA_def_property_override_funcs(PropertyRNA *prop, const char *diff, const char *store, const char *apply); + void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func); void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func); diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 155c82bbbc3..345c47ae1bf 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -61,6 +61,8 @@ extern const EnumPropertyItem rna_enum_object_modifier_type_items[]; extern const EnumPropertyItem rna_enum_constraint_type_items[]; extern const EnumPropertyItem rna_enum_boidrule_type_items[]; extern const EnumPropertyItem rna_enum_sequence_modifier_type_items[]; + +extern const EnumPropertyItem rna_enum_collection_type_items[]; extern const EnumPropertyItem rna_enum_layer_collection_mode_settings_type_items[]; extern const EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[]; diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 657eeeeaeab..47aebbc13e7 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -108,6 +108,8 @@ typedef enum PropertyUnit { #define RNA_TRANSLATION_PREC_DEFAULT 5 +#define RNA_STACK_ARRAY 32 + /* also update enums in bpy_props.c when adding items here * watch it: these values are written to files as part of * node socket button subtypes! @@ -156,7 +158,7 @@ typedef enum PropertySubType { /* Make sure enums are updated with these */ /* HIGHEST FLAG IN USE: 1 << 31 - * FREE FLAGS: 2, 3, 7, 9, 11, 13, 14, 15, 30 */ + * FREE FLAGS: 3, 7, 9, 11, 13, 14, 15, 30 */ typedef enum PropertyFlag { /* editable means the property is editable in the user * interface, properties are editable by default except @@ -174,6 +176,9 @@ typedef enum PropertyFlag { * and collections */ PROP_ANIMATABLE = (1 << 1), + /* Means the property can be overriden by a local 'proxy' of some linked datablock. */ + PROP_OVERRIDABLE_STATIC = (1 << 2), + /* This flag means when the property's widget is in 'textedit' mode, it will be updated * after every typed char, instead of waiting final validation. Used e.g. for text searchbox. * It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 293cef52b90..19f66109665 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -46,6 +46,14 @@ # endif #endif +/** + * Variable to control debug output of makesrna. + * debugSRNA: + * - 0 = no output, except errors + * - 1 = detail actions + */ +static int debugSRNA = 0; + /* stub for BLI_abort() */ #ifndef NDEBUG void BLI_system_backtrace(FILE *fp) @@ -62,7 +70,9 @@ void BLI_system_backtrace(FILE *fp) static int file_older(const char *file1, const char *file2) { struct stat st1, st2; - /* printf("compare: %s %s\n", file1, file2); */ + if (debugSRNA > 0) { + printf("compare: %s %s\n", file1, file2); + } if (stat(file1, &st1)) return 0; if (stat(file2, &st2)) return 0; @@ -3015,12 +3025,15 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr prop->arraylength[1], prop->arraylength[2], prop->totarraylength); - fprintf(f, "\t%s%s, %d, %s, %s,\n", + fprintf(f, "\t%s%s, %d, %s, %s, %s, %s, %s,\n", (prop->flag & PROP_CONTEXT_UPDATE) ? "(UpdateFunc)" : "", rna_function_string(prop->update), prop->noteflag, rna_function_string(prop->editable), - rna_function_string(prop->itemeditable)); + rna_function_string(prop->itemeditable), + rna_function_string(prop->override_diff), + rna_function_string(prop->override_store), + rna_function_string(prop->override_apply)); if (prop->flag_internal & PROP_INTERN_RAW_ACCESS) rna_set_raw_offset(f, srna, prop); else fprintf(f, "\t0, -1"); @@ -4141,7 +4154,9 @@ int main(int argc, char **argv) return_status = 1; } else { - fprintf(stderr, "Running makesrna\n"); + if (debugSRNA > 0) { + fprintf(stderr, "Running makesrna\n"); + } makesrna_path = argv[0]; return_status = rna_preprocess(argv[1]); } diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index c519c61e9e9..44df8916796 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -97,6 +97,7 @@ const EnumPropertyItem rna_enum_id_type_items[] = { #include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_library_override.h" #include "BKE_library_remap.h" #include "BKE_animsys.h" #include "BKE_material.h" @@ -311,6 +312,15 @@ static ID *rna_ID_copy(ID *id, Main *bmain) return NULL; } +static ID *rna_ID_override_create(ID *id, Main *bmain) +{ + if (id->lib == NULL) { + return NULL; + } + + return BKE_override_static_create_from(bmain, id); +} + static void rna_ID_update_tag(ID *id, ReportList *reports, int flag) { /* XXX, new function for this! */ @@ -762,6 +772,14 @@ static PointerRNA rna_IDPreview_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_ImagePreview, prv_img); } +static PointerRNA rna_ID_override_reference_get(PointerRNA *ptr) +{ + ID *id = (ID *)ptr->data; + ID *reference = (id && id->override_static) ? id->override_static->reference : NULL; + + return reference ? rna_pointer_inherit_refine(ptr, ID_code_to_RNA_type(GS(reference->name)), reference) : PointerRNA_NULL; +} + #else static void rna_def_ID_properties(BlenderRNA *brna) @@ -1024,6 +1042,12 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Library", "Library file the data-block is linked from"); + prop = RNA_def_pointer(srna, "override_static_reference", "ID", + "Override Reference", "Reference linked data-block overridden by this one"); + RNA_def_property_pointer_sdna(prop, NULL, "override_static->reference"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_pointer_funcs(prop, "rna_ID_override_reference_get", NULL, NULL, NULL); + prop = RNA_def_pointer(srna, "preview", "ImagePreview", "Preview", "Preview image and icon of this data-block (None if not supported for this type of data)"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1036,6 +1060,12 @@ static void rna_def_ID(BlenderRNA *brna) parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID"); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "override_create", "rna_ID_override_create"); + RNA_def_function_ui_description(func, "Create an overridden local copy of this linked data-block (not supported for all data-blocks)"); + RNA_def_function_flag(func, FUNC_USE_MAIN); + parm = RNA_def_pointer(func, "id", "ID", "", "New overridden local copy of the ID"); + RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "user_clear", "rna_ID_user_clear"); RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, " "on reload the data will be removed"); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 9c510176bb2..345c3d23dbe 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -51,6 +51,7 @@ #include "BKE_idprop.h" #include "BKE_fcurve.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_main.h" #include "BKE_report.h" @@ -61,6 +62,7 @@ #include "RNA_enum_types.h" #include "WM_api.h" +#include "WM_message.h" /* flush updates */ #include "DNA_object_types.h" @@ -173,6 +175,11 @@ void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr) } } +bool RNA_pointer_is_null(const PointerRNA *ptr) +{ + return !((ptr->data != NULL) && (ptr->id.data != NULL) && (ptr->type != NULL)); +} + static void rna_pointer_inherit_id(StructRNA *type, PointerRNA *parent, PointerRNA *ptr) { if (type && type->flag & STRUCT_ID) { @@ -1817,7 +1824,8 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop) return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0 && - (!id || !ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION))); + (!id || ((!ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)) && + (!id->override_static || (prop->flag & PROP_OVERRIDABLE_STATIC))))); } /** @@ -1843,11 +1851,19 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char * } /* property from linked data-block */ - if (id && ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) { - if (!(*r_info)[0]) { - *r_info = "Can't edit this property from a linked data-block."; + if (id) { + if (ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) { + if (!(*r_info)[0]) { + *r_info = "Can't edit this property from a linked data-block."; + } + return false; + } + if (id->override_static != NULL && (prop->flag & PROP_OVERRIDABLE_STATIC) == 0) { + if (!(*r_info)[0]) { + *r_info = "Can't edit this property from an override data-block."; + } + return false; } - return false; } return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0); @@ -1966,8 +1982,18 @@ static void rna_property_update(bContext *C, Main *bmain, Scene *scene, PointerR else prop->update(bmain, scene, ptr); } +#if 0 if (prop->noteflag) WM_main_add_notifier(prop->noteflag, ptr->id.data); +#else + /* if C is NULL, we're updating from animation. + * avoid slow-down from f-curves by not publishing (for now). */ + if (C != NULL) { + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + /* we could add NULL check, for now don't */ + WM_msg_publish_rna(mbus, ptr, prop); + } +#endif } if (!is_rna || (prop->flag & PROP_IDPROPERTY)) { @@ -2921,9 +2947,6 @@ char *RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, int length; BLI_assert(RNA_property_type(prop) == PROP_STRING); - if (!ptr->data) { - return NULL; - } length = RNA_property_string_length(ptr, prop); @@ -5687,7 +5710,7 @@ void RNA_struct_property_unset(PointerRNA *ptr, const char *identifier) } } -bool RNA_property_is_idprop(PropertyRNA *prop) +bool RNA_property_is_idprop(const PropertyRNA *prop) { return (prop->magic != RNA_MAGIC); } @@ -6860,8 +6883,7 @@ int RNA_function_call_direct_va_lookup(bContext *C, ReportList *reports, Pointer } const char *RNA_translate_ui_text( - const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop, - int translate) + const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop, int translate) { return rna_translate_ui_text(text, text_ctxt, type, prop, translate); } @@ -6963,120 +6985,22 @@ bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index) } } +static bool rna_property_override_operation_apply( + PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local, + IDOverrideStaticPropertyOperation *opop); + bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index) { - int len, fromlen; - PropertyRNA *fromprop = prop; - - if (prop->magic != RNA_MAGIC) { - /* In case of IDProperty, we have to find the *real* idprop of ptr, - * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */ - prop = (PropertyRNA *)rna_idproperty_find(ptr, ((IDProperty *)fromprop)->name); - - /* its possible the custom-prop doesn't exist on this data-block */ - if (prop == NULL) { - return false; - } - - /* Even though currently we now prop will always be the 'fromprop', this might not be the case in the future. */ - if (prop == fromprop) { - fromprop = (PropertyRNA *)rna_idproperty_find(fromptr, ((IDProperty *)prop)->name); - } - } - - /* get the length of the array to work with */ - len = RNA_property_array_length(ptr, prop); - fromlen = RNA_property_array_length(fromptr, fromprop); - - if (len != fromlen) + if (!RNA_property_editable(ptr, prop)) { return false; - - /* get and set the default values as appropriate for the various types */ - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - if (len) { - if (index == -1) { - int *tmparray = MEM_callocN(sizeof(int) * len, "copy - boolean"); - - RNA_property_boolean_get_array(fromptr, fromprop, tmparray); - RNA_property_boolean_set_array(ptr, prop, tmparray); - - MEM_freeN(tmparray); - } - else { - int value = RNA_property_boolean_get_index(fromptr, fromprop, index); - RNA_property_boolean_set_index(ptr, prop, index, value); - } - } - else { - int value = RNA_property_boolean_get(fromptr, fromprop); - RNA_property_boolean_set(ptr, prop, value); - } - return true; - case PROP_INT: - if (len) { - if (index == -1) { - int *tmparray = MEM_callocN(sizeof(int) * len, "copy - int"); - - RNA_property_int_get_array(fromptr, fromprop, tmparray); - RNA_property_int_set_array(ptr, prop, tmparray); - - MEM_freeN(tmparray); - } - else { - int value = RNA_property_int_get_index(fromptr, fromprop, index); - RNA_property_int_set_index(ptr, prop, index, value); - } - } - else { - int value = RNA_property_int_get(fromptr, fromprop); - RNA_property_int_set(ptr, prop, value); - } - return true; - case PROP_FLOAT: - if (len) { - if (index == -1) { - float *tmparray = MEM_callocN(sizeof(float) * len, "copy - float"); - - RNA_property_float_get_array(fromptr, fromprop, tmparray); - RNA_property_float_set_array(ptr, prop, tmparray); - - MEM_freeN(tmparray); - } - else { - float value = RNA_property_float_get_index(fromptr, fromprop, index); - RNA_property_float_set_index(ptr, prop, index, value); - } - } - else { - float value = RNA_property_float_get(fromptr, fromprop); - RNA_property_float_set(ptr, prop, value); - } - return true; - case PROP_ENUM: - { - int value = RNA_property_enum_get(fromptr, fromprop); - RNA_property_enum_set(ptr, prop, value); - return true; - } - case PROP_POINTER: - { - PointerRNA value = RNA_property_pointer_get(fromptr, fromprop); - RNA_property_pointer_set(ptr, prop, value); - return true; - } - case PROP_STRING: - { - char *value = RNA_property_string_get_alloc(fromptr, fromprop, NULL, 0, NULL); - RNA_property_string_set(ptr, prop, value); - MEM_freeN(value); - return true; - } - default: - return false; } - return false; + IDOverrideStaticPropertyOperation opop = { + .operation = IDOVERRIDESTATIC_OP_REPLACE, + .subitem_reference_index = index, + .subitem_local_index = index + }; + return rna_property_override_operation_apply(ptr, fromptr, NULL, prop, &opop); } /* use RNA_warning macro which includes __func__ suffix */ @@ -7101,176 +7025,513 @@ void _RNA_warning(const char *format, ...) #endif } -bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNAEqualsMode mode) +static int rna_property_override_diff( + PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNACompareMode mode, + IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags); + +bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNACompareMode mode) +{ + BLI_assert(ELEM(mode, RNA_EQ_STRICT, RNA_EQ_UNSET_MATCH_ANY, RNA_EQ_UNSET_MATCH_NONE)); + + return (rna_property_override_diff(a, b, prop, mode, NULL, NULL, NULL, 0) != 0); +} + +bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNACompareMode mode) +{ + CollectionPropertyIterator iter; + PropertyRNA *iterprop; + bool equals = true; + + if (a == NULL && b == NULL) + return true; + else if (a == NULL || b == NULL) + return false; + else if (a->type != b->type) + return false; + + iterprop = RNA_struct_iterator_property(a->type); + + RNA_property_collection_begin(a, iterprop, &iter); + for (; iter.valid; RNA_property_collection_next(&iter)) { + PropertyRNA *prop = iter.ptr.data; + + if (!RNA_property_equals(a, b, prop, mode)) { + equals = false; + break; + } + } + RNA_property_collection_end(&iter); + + return equals; +} + +/* Low-level functions, also used by non-override RNA API like copy or equality check. */ +#include "PIL_time_utildefines.h" +static int rna_property_override_diff( + PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop_a, eRNACompareMode mode, + IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags) { - int len, fromlen; + int len_a, len_b; + + PropertyRNA *prop_b = prop_a; + + if (prop_a->magic != RNA_MAGIC) { + /* In case of IDProperty, we have to find the *real* idprop of ptr, + * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */ + /* XXX TODO this is ugly, we already get correct prop in upcalling code, whould just pass them to this func! */ + prop_a = (PropertyRNA *)rna_idproperty_find(ptr_a, ((IDProperty *)prop_a)->name); + prop_b = (PropertyRNA *)rna_idproperty_find(ptr_b, ((IDProperty *)prop_b)->name); + + if (ELEM(NULL, prop_a, prop_b)) { + return 1; + } + } + + BLI_assert(prop_a->override_diff == prop_b->override_diff && prop_a->override_diff != NULL); if (mode == RNA_EQ_UNSET_MATCH_ANY) { /* uninitialized properties are assumed to match anything */ - if (!RNA_property_is_set(a, prop) || !RNA_property_is_set(b, prop)) - return true; + if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b)) + return 0; } else if (mode == RNA_EQ_UNSET_MATCH_NONE) { /* unset properties never match set properties */ - if (RNA_property_is_set(a, prop) != RNA_property_is_set(b, prop)) - return false; + if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b)) + return 1; } /* get the length of the array to work with */ - len = RNA_property_array_length(a, prop); - fromlen = RNA_property_array_length(b, prop); + len_a = RNA_property_array_length(ptr_a, prop_a); + len_b = RNA_property_array_length(ptr_b, prop_b); - if (len != fromlen) - return false; + if (len_a != len_b) { + /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */ + return len_a > len_b ? 1 : -1; + } - /* get and set the default values as appropriate for the various types */ - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - { - if (len) { - int fixed_a[16], fixed_b[16]; - int *array_a, *array_b; - bool equals; + return prop_a->override_diff( + ptr_a, ptr_b, prop_a, prop_b, len_a, len_b, mode, override, rna_path, flags, r_override_changed); +} - array_a = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_a; - array_b = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_b; +/* Modify local data-block to make it ready for override application (only needed for diff operations, where we use + * the local data-block's data as second operand). */ +static bool rna_property_override_operation_store( + PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local, + IDOverrideStaticProperty *op) +{ + int len_local, len_reference, len_storage = 0; + PropertyRNA *prop_reference = prop_local; + PropertyRNA *prop_storage = prop_local; + bool changed = false; - RNA_property_boolean_get_array(a, prop, array_a); - RNA_property_boolean_get_array(b, prop, array_b); + if (!ptr_storage) { + return changed; + } - equals = memcmp(array_a, array_b, sizeof(int) * len) == 0; + if (prop_local->magic != RNA_MAGIC) { + /* In case of IDProperty, we have to find the *real* idprop of ptr, + * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */ + /* XXX TODO this is ugly, we already get correct prop in upcalling code, should just pass them to this func! */ + prop_local = (PropertyRNA *)rna_idproperty_find(ptr_local, ((IDProperty *)prop_local)->name); + prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, ((IDProperty *)prop_reference)->name); + if (ptr_storage) { + prop_storage = (PropertyRNA *)rna_idproperty_find(ptr_storage, ((IDProperty *)prop_storage)->name); + } - if (array_a != fixed_a) MEM_freeN(array_a); - if (array_b != fixed_b) MEM_freeN(array_b); + /* its possible the custom-prop doesn't exist on this data-block */ + if (prop_local == NULL) { + return changed; + } + } - return equals; - } - else { - int value = RNA_property_boolean_get(a, prop); - return value == RNA_property_boolean_get(b, prop); - } + /* get the length of the array to work with */ + len_local = RNA_property_array_length(ptr_local, prop_local); + len_reference = RNA_property_array_length(ptr_reference, prop_reference); + if (prop_storage) { + len_storage = RNA_property_array_length(ptr_storage, prop_storage); + } + + if (len_local != len_reference || len_local != len_storage) { + /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */ + return changed; + } + + BLI_assert(prop_local->override_store == prop_reference->override_store && + (!ptr_storage || prop_local->override_store == prop_storage->override_store) && + prop_local->override_store != NULL); + + for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) { + /* Only needed for diff operations. */ + if (!ELEM(opop->operation, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY)) { + continue; } - case PROP_INT: + if (prop_local->override_store( + ptr_local, ptr_reference, ptr_storage, prop_local, prop_reference, prop_storage, + len_local, len_reference, len_storage, opop)) { - if (len) { - int fixed_a[16], fixed_b[16]; - int *array_a, *array_b; - bool equals; + changed = true; + } + } - array_a = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_a; - array_b = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_b; + return changed; +} - RNA_property_int_get_array(a, prop, array_a); - RNA_property_int_get_array(b, prop, array_b); +static bool rna_property_override_operation_apply( + PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local, + IDOverrideStaticPropertyOperation *opop) +{ + int len_local, len_reference, len_storage = 0; + PropertyRNA *prop_reference = prop_local; + PropertyRNA *prop_storage = prop_local; - equals = memcmp(array_a, array_b, sizeof(int) * len) == 0; + const short override_op = opop->operation; - if (array_a != fixed_a) MEM_freeN(array_a); - if (array_b != fixed_b) MEM_freeN(array_b); + if (override_op == IDOVERRIDESTATIC_OP_NOOP) { + return true; + } - return equals; - } - else { - int value = RNA_property_int_get(a, prop); - return value == RNA_property_int_get(b, prop); - } + if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !ptr_storage) { + /* We cannot apply 'diff' override operations without some refference storage. + * This should typically only happen at read time of .blend file... */ + return false; + } + + if (prop_local->magic != RNA_MAGIC) { + /* In case of IDProperty, we have to find the *real* idprop of ptr, + * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */ + /* XXX TODO this is ugly, we already get correct prop in upcalling code, whould just pass them to this func! */ + prop_local = (PropertyRNA *)rna_idproperty_find(ptr_local, ((IDProperty *)prop_local)->name); + prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, ((IDProperty *)prop_reference)->name); + if (ptr_storage) { + prop_storage = (PropertyRNA *)rna_idproperty_find(ptr_storage, ((IDProperty *)prop_storage)->name); } - case PROP_FLOAT: - { - if (len) { - float fixed_a[16], fixed_b[16]; - float *array_a, *array_b; - bool equals; + /* its possible the custom-prop doesn't exist on this data-block */ + if (prop_local == NULL) { + return false; + } + } - array_a = (len > 16) ? MEM_mallocN(sizeof(float) * len, "RNA equals") : fixed_a; - array_b = (len > 16) ? MEM_mallocN(sizeof(float) * len, "RNA equals") : fixed_b; + if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !prop_storage) { + /* We cannot apply 'diff' override operations without some refference storage. + * This should typically only happen at read time of .blend file... */ + return false; + } - RNA_property_float_get_array(a, prop, array_a); - RNA_property_float_get_array(b, prop, array_b); + /* get the length of the array to work with */ + len_local = RNA_property_array_length(ptr_local, prop_local); + len_reference = RNA_property_array_length(ptr_reference, prop_reference); + if (ptr_storage) { + len_storage = RNA_property_array_length(ptr_storage, prop_storage); + } - equals = memcmp(array_a, array_b, sizeof(float) * len) == 0; + if (len_local != len_reference || (ptr_storage && len_local != len_storage)) { + /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */ + return false; + } - if (array_a != fixed_a) MEM_freeN(array_a); - if (array_b != fixed_b) MEM_freeN(array_b); + BLI_assert(prop_local->override_apply == prop_reference->override_apply && + (!ptr_storage || prop_local->override_apply == prop_storage->override_apply) && + prop_local->override_apply != NULL); - return equals; - } - else { - float value = RNA_property_float_get(a, prop); - return value == RNA_property_float_get(b, prop); + /* get and set the default values as appropriate for the various types */ + return prop_local->override_apply( + ptr_local, ptr_reference, ptr_storage, + prop_local, prop_reference, prop_storage, + len_local, len_reference, len_storage, + opop); +} + + +/** + * Check whether reference and local overriden data match (are the same), + * with respect to given restrictive sets of properties. */ +bool RNA_struct_override_matches( + PointerRNA *local, PointerRNA *reference, + IDOverrideStatic *override, const bool ignore_non_overridable, const bool ignore_overridden) +{ + CollectionPropertyIterator iter; + PropertyRNA *iterprop; + bool equals = true; + + BLI_assert(local->type == reference->type); + + iterprop = RNA_struct_iterator_property(local->type); + + RNA_property_collection_begin(local, iterprop, &iter); + for (; iter.valid; RNA_property_collection_next(&iter)) { + PropertyRNA *prop = iter.ptr.data; + + if (ignore_non_overridable && !(prop->flag & PROP_OVERRIDABLE_STATIC)) { + continue; + } + + if (ignore_overridden) { + /* XXX TODO this will have to be refined to handle collections insertions, and array items */ + char *rna_path = RNA_path_from_ID_to_property(local, prop); + if (BKE_override_static_property_find(override, rna_path) != NULL) { + MEM_SAFE_FREE(rna_path); + continue; } + MEM_SAFE_FREE(rna_path); } - case PROP_ENUM: - { - int value = RNA_property_enum_get(a, prop); - return value == RNA_property_enum_get(b, prop); + int flag = 0; + if (ignore_non_overridable) { + flag |= RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE; + } + if (ignore_overridden) { + flag |= RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN; + } + if (rna_property_override_diff(local, reference, prop, RNA_EQ_STRICT, override, NULL, NULL, flag) != 0) { + equals = false; + break; } + } + RNA_property_collection_end(&iter); - case PROP_STRING: - { - char fixed_a[128], fixed_b[128]; - int len_a, len_b; - char *value_a = RNA_property_string_get_alloc(a, prop, fixed_a, sizeof(fixed_a), &len_a); - char *value_b = RNA_property_string_get_alloc(b, prop, fixed_b, sizeof(fixed_b), &len_b); - bool equals = STREQ(value_a, value_b); + return equals; +} - if (value_a != fixed_a) MEM_freeN(value_a); - if (value_b != fixed_b) MEM_freeN(value_b); +/** Store needed second operands into \a storage data-block for differential override operations. */ +bool RNA_struct_override_store(PointerRNA *local, PointerRNA *reference, PointerRNA *storage, IDOverrideStatic *override) +{ + bool changed = false; - return equals; - } +#ifdef DEBUG_OVERRIDE_TIMEIT + TIMEIT_START_AVERAGED(RNA_struct_override_store); +#endif + for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) { + /* Simplified for now! */ + PointerRNA src_data, dst_data; + PropertyRNA *src_prop, *dst_prop; - case PROP_POINTER: + if (RNA_path_resolve_property(reference, op->rna_path, &src_data, &src_prop) && + RNA_path_resolve_property(local, op->rna_path, &dst_data, &dst_prop)) { - if (!STREQ(RNA_property_identifier(prop), "rna_type")) { - PointerRNA propptr_a = RNA_property_pointer_get(a, prop); - PointerRNA propptr_b = RNA_property_pointer_get(b, prop); - return RNA_struct_equals(&propptr_a, &propptr_b, mode); + PointerRNA storage_data; + PropertyRNA *storage_prop = NULL; + + /* It is totally OK if this does not success, only a subset of override operations actually need storage. */ + if (storage && (storage->id.data != NULL)) { + RNA_path_resolve_property(storage, op->rna_path, &storage_data, &storage_prop); + } + + if (rna_property_override_operation_store(&dst_data, &src_data, &storage_data, src_prop, op)) { + changed = true; } - break; } + } +#ifdef DEBUG_OVERRIDE_TIMEIT + TIMEIT_END_AVERAGED(RNA_struct_override_store); +#endif - default: - break; + return changed; +} + +/** Apply given \a op override property operations on \a dst, using \a src as source. */ +void RNA_property_override_apply( + PointerRNA *dst, PointerRNA *src, PointerRNA *storage, PropertyRNA *prop, IDOverrideStaticProperty *op) +{ + for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) { + if (!rna_property_override_operation_apply(dst, src, storage, prop, opop)) { + BLI_assert(0); + } } +} - return true; +/** Apply given \a override operations on \a dst, using \a src as source. */ +void RNA_struct_override_apply(PointerRNA *dst, PointerRNA *src, PointerRNA *storage, IDOverrideStatic *override) +{ +#ifdef DEBUG_OVERRIDE_TIMEIT + TIMEIT_START_AVERAGED(RNA_struct_override_apply); +#endif + for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) { + /* Simplified for now! */ + PointerRNA src_data, dst_data; + PropertyRNA *src_prop, *dst_prop; + + if (RNA_path_resolve_property(src, op->rna_path, &src_data, &src_prop) && + RNA_path_resolve_property(dst, op->rna_path, &dst_data, &dst_prop)) + { + PointerRNA storage_data; + PropertyRNA *storage_prop = NULL; + + /* It is totally OK if this does not success, only a subset of override operations actually need storage. */ + if (storage && (storage->id.data != NULL)) { + RNA_path_resolve_property(storage, op->rna_path, &storage_data, &storage_prop); + } + + /* Note that src and dst props are the same, unless they are IDProperties... */ + RNA_property_override_apply(&dst_data, &src_data, storage_prop ? &storage_data : NULL, src_prop, op); + } +#ifndef NDEBUG + else { + printf("Failed to apply static override operation to '%s.%s' (could not resolve some properties)\n", + ((ID *)src->id.data)->name, op->rna_path); + } +#endif + } +#ifdef DEBUG_OVERRIDE_TIMEIT + TIMEIT_END_AVERAGED(RNA_struct_override_apply); +#endif } -bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNAEqualsMode mode) +/** Automatically define override rules by comparing \a local and \a reference RNA structs. */ +bool RNA_struct_auto_override(PointerRNA *local, PointerRNA *reference, IDOverrideStatic *override, const char *root_path) { CollectionPropertyIterator iter; -// CollectionPropertyRNA *citerprop; /* UNUSED */ PropertyRNA *iterprop; - bool equals = true; + bool changed = false; - if (a == NULL && b == NULL) - return true; - else if (a == NULL || b == NULL) - return false; - else if (a->type != b->type) - return false; + BLI_assert(local->type == reference->type); + BLI_assert(local->id.data && reference->id.data); - iterprop = RNA_struct_iterator_property(a->type); -// citerprop = (CollectionPropertyRNA *)rna_ensure_property(iterprop); /* UNUSED */ + if ((((ID *)local->id.data)->flag & LIB_OVERRIDE_STATIC_AUTO) == 0) { + return changed; + } - RNA_property_collection_begin(a, iterprop, &iter); - for (; iter.valid; RNA_property_collection_next(&iter)) { +#ifdef DEBUG_OVERRIDE_TIMEIT + static float _sum_time = 0.0f; + static float _num_time = 0.0f; + double _timeit_time; + if (!root_path) { + _timeit_time = PIL_check_seconds_timer(); + } +#endif + + iterprop = RNA_struct_iterator_property(local->type); + + for (RNA_property_collection_begin(local, iterprop, &iter); iter.valid; RNA_property_collection_next(&iter)) { PropertyRNA *prop = iter.ptr.data; - if (!RNA_property_equals(a, b, prop, mode)) { - equals = false; - break; + if (!(prop->flag & PROP_OVERRIDABLE_STATIC)) { + continue; + } + if (RNA_property_animated(local, prop)) { + continue; + } + + /* XXX TODO this will have to be refined to handle collections insertions, and array items */ + char *rna_path; + if (root_path) { + /* Inlined building, much much more efficient. */ + rna_path = BLI_sprintfN("%s.%s", root_path, RNA_property_identifier(prop)); + } + else { + rna_path = RNA_path_from_ID_to_property(local, prop); } + if (rna_path == NULL) { + continue; + } + + rna_property_override_diff(local, reference, prop, RNA_EQ_STRICT, override, rna_path, &changed, + RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN); + + MEM_SAFE_FREE(rna_path); } RNA_property_collection_end(&iter); - return equals; +#ifdef DEBUG_OVERRIDE_TIMEIT + if (!root_path) { + const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time); + _sum_time += _delta_time; + _num_time++; + printf("ID: %s\n", ((ID *)local->id.data)->name); + printf("time end (%s): %.6f\n", __func__, _delta_time); + printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n", __func__, (_sum_time / _num_time), _sum_time, (int)_num_time); + } +#endif + + return changed; +} + +IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop) +{ + ID *id = ptr->id.data; + + if (!id || !id->override_static) { + return NULL; + } + + char *rna_path = RNA_path_from_ID_to_property(ptr, prop); + if (rna_path) { + IDOverrideStaticProperty *op = BKE_override_static_property_find(id->override_static, rna_path); + MEM_freeN(rna_path); + return op; + } + return NULL; +} + +IDOverrideStaticProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created) +{ + ID *id = ptr->id.data; + + if (!id || !id->override_static) { + return NULL; + } + + char *rna_path = RNA_path_from_ID_to_property(ptr, prop); + if (rna_path) { + IDOverrideStaticProperty *op = BKE_override_static_property_get(id->override_static, rna_path, r_created); + MEM_freeN(rna_path); + return op; + } + return NULL; } +IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_find( + PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict) +{ + IDOverrideStaticProperty *op = RNA_property_override_property_find(ptr, prop); + + if (!op) { + return NULL; + } + + return BKE_override_static_property_operation_find(op, NULL, NULL, index, index, strict, r_strict); +} + +IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_get( + PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index, + const bool strict, bool *r_strict, bool *r_created) +{ + IDOverrideStaticProperty *op = RNA_property_override_property_get(ptr, prop, NULL); + + if (!op) { + return NULL; + } + + return BKE_override_static_property_operation_get(op, operation, NULL, NULL, index, index, strict, r_strict, r_created); +} + +void RNA_property_override_status( + PointerRNA *ptr, PropertyRNA *prop, const int index, + bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked) +{ +#define SET_RET(_name, _val) if (_name != NULL) *_name = (_val) + + SET_RET(r_overridable, false); + SET_RET(r_overridden, false); + SET_RET(r_mandatory, false); + SET_RET(r_locked, false); + + if (!ptr || !prop || !ptr->id.data || !((ID *)ptr->id.data)->override_static) { + return; + } + + SET_RET(r_overridable, (prop->flag & PROP_OVERRIDABLE_STATIC) && (prop->flag & PROP_EDITABLE)); + + if (r_overridden || r_mandatory || r_locked) { + IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_find(ptr, prop, index, false, NULL); + SET_RET(r_overridden, opop != NULL); + SET_RET(r_mandatory, (opop->flag & IDOVERRIDESTATIC_FLAG_MANDATORY) != 0); + SET_RET(r_locked, (opop->flag & IDOVERRIDESTATIC_FLAG_LOCKED) != 0); + } +} + + bool RNA_path_resolved_create( PointerRNA *ptr, struct PropertyRNA *prop, diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index e53533df782..3d11e7bb723 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -585,6 +585,34 @@ static FCurve *rna_Driver_find(AnimData *adt, ReportList *reports, const char *d return list_find_fcurve(&adt->drivers, data_path, index); } +bool rna_AnimaData_override_apply( + PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_storage, + PropertyRNA *prop_dst, PropertyRNA *prop_src, PropertyRNA *UNUSED(prop_storage), + const int len_dst, const int len_src, const int len_storage, + IDOverrideStaticPropertyOperation *opop) +{ + BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage) && len_dst == 0); + BLI_assert(opop->operation == IDOVERRIDESTATIC_OP_REPLACE && "Unsupported RNA override operation on animdata pointer"); + UNUSED_VARS_NDEBUG(ptr_storage, len_dst, len_src, len_storage, opop); + + /* AnimData is a special case, since you cannot edit/replace it, it's either existent or not. */ + AnimData *adt_dst = RNA_property_pointer_get(ptr_dst, prop_dst).data; + AnimData *adt_src = RNA_property_pointer_get(ptr_src, prop_src).data; + + if (adt_dst == NULL && adt_src != NULL) { + /* Copy anim data from reference into final local ID. */ + BKE_animdata_copy_id(NULL, ptr_dst->id.data, ptr_src->id.data, false); + return true; + } + else if (adt_dst != NULL && adt_src == NULL) { + /* Override has cleared/removed anim data from its reference. */ + BKE_animdata_free(ptr_dst->id.data, true); + return true; + } + + return false; +} + #else /* helper function for Keying Set -> keying settings */ @@ -999,6 +1027,8 @@ void rna_def_animdata_common(StructRNA *srna) prop = RNA_def_property(srna, "animation_data", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "adt"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_funcs(prop, NULL, NULL, "rna_AnimaData_override_apply"); RNA_def_property_ui_text(prop, "Animation Data", "Animation data for this data-block"); } @@ -1022,7 +1052,7 @@ static void rna_def_animdata(BlenderRNA *brna) /* Active Action */ prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE); /* this flag as well as the dynamic test must be defined for this to be editable... */ - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_OVERRIDABLE_STATIC); RNA_def_property_pointer_funcs(prop, NULL, "rna_AnimData_action_set", NULL, "rna_Action_id_poll"); RNA_def_property_editable_func(prop, "rna_AnimData_action_editable"); RNA_def_property_ui_text(prop, "Action", "Active Action for this data-block"); diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index f8a492c3cee..1ec0fd92a67 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -549,14 +549,14 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone) RNA_def_property_float_sdna(prop, NULL, "ease1"); RNA_def_property_range(prop, -5.0f, 5.0f); RNA_def_property_float_default(prop, 1.0f); - RNA_def_property_ui_text(prop, "B-Bone Ease In", "Length of first Bezier Handle (for B-Bones only)"); + RNA_def_property_ui_text(prop, "Ease In", "Length of first Bezier Handle (for B-Bones only)"); RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone); prop = RNA_def_property(srna, "bbone_easeout", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "ease2"); RNA_def_property_range(prop, -5.0f, 5.0f); RNA_def_property_float_default(prop, 1.0f); - RNA_def_property_ui_text(prop, "B-Bone Ease Out", "Length of second Bezier Handle (for B-Bones only)"); + RNA_def_property_ui_text(prop, "Ease Out", "Length of second Bezier Handle (for B-Bones only)"); RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone); /* Scale In/Out */ diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c index 911f2cca2f6..3df114282fd 100644 --- a/source/blender/makesrna/intern/rna_context.c +++ b/source/blender/makesrna/intern/rna_context.c @@ -144,15 +144,15 @@ static PointerRNA rna_Context_view_render_get(PointerRNA *ptr) static void rna_Context_engine_get(PointerRNA *ptr, char *value) { bContext *C = (bContext *)ptr->data; - RenderEngineType *engine = CTX_data_engine(C); - strcpy(value, engine->idname); + RenderEngineType *engine_type = CTX_data_engine_type(C); + strcpy(value, engine_type->idname); } static int rna_Context_engine_length(PointerRNA *ptr) { bContext *C = (bContext *)ptr->data; - RenderEngineType *engine = CTX_data_engine(C); - return strlen(engine->idname); + RenderEngineType *engine_type = CTX_data_engine_type(C); + return strlen(engine_type->idname); } static PointerRNA rna_Context_scene_collection_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index c8a6a503fd9..03e58f8f78e 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -1270,6 +1270,14 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier #endif } + /* Override handling. */ + if (DefRNA.preprocess) { + prop->override_diff = (RNAPropOverrideDiff)"rna_property_override_diff_default"; + prop->override_store = (RNAPropOverrideStore)"rna_property_override_store_default"; + prop->override_apply = (RNAPropOverrideApply)"rna_property_override_apply_default"; + } + /* TODO: do we want that for runtime-defined stuff too? I’d say no, but... maybe yes :/ */ + rna_addtail(&cont->properties, prop); return prop; @@ -2222,6 +2230,29 @@ void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editabl if (editable) prop->itemeditable = (ItemEditableFunc)editable; } +/** + * Set custom callbacks for override operations handling. + * + * \note \a diff callback will also be used by RNA comparison/equality functions. + */ +void RNA_def_property_override_funcs(PropertyRNA *prop, const char *diff, const char *store, const char *apply) +{ + if (!DefRNA.preprocess) { + fprintf(stderr, "%s: only during preprocessing.\n", __func__); + return; + } + + if (diff) { + prop->override_diff = (RNAPropOverrideDiff)diff; + } + if (store) { + prop->override_store = (RNAPropOverrideStore)store; + } + if (apply) { + prop->override_apply = (RNAPropOverrideApply)apply; + } +} + void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *func) { if (!DefRNA.preprocess) { diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index 04c8352833e..7d520ec6abd 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -61,7 +61,7 @@ static PointerRNA rna_DepsgraphIter_object_get(PointerRNA *ptr) static PointerRNA rna_DepsgraphIter_instance_object_get(PointerRNA *ptr) { BLI_Iterator *iterator = ptr->data; - DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data; + DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; Object *instance_object = NULL; if (deg_iter->dupli_object_current != NULL) { instance_object = deg_iter->dupli_object_current->ob; @@ -72,7 +72,7 @@ static PointerRNA rna_DepsgraphIter_instance_object_get(PointerRNA *ptr) static PointerRNA rna_DepsgraphIter_parent_get(PointerRNA *ptr) { BLI_Iterator *iterator = ptr->data; - DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data; + DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; Object *dupli_parent = NULL; if (deg_iter->dupli_object_current != NULL) { dupli_parent = deg_iter->dupli_parent; @@ -83,7 +83,7 @@ static PointerRNA rna_DepsgraphIter_parent_get(PointerRNA *ptr) static void rna_DepsgraphIter_persistent_id_get(PointerRNA *ptr, int *persistent_id) { BLI_Iterator *iterator = ptr->data; - DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data; + DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; memcpy(persistent_id, deg_iter->dupli_object_current->persistent_id, sizeof(deg_iter->dupli_object_current->persistent_id)); } @@ -91,7 +91,7 @@ static void rna_DepsgraphIter_persistent_id_get(PointerRNA *ptr, int *persistent static void rna_DepsgraphIter_orco_get(PointerRNA *ptr, float *orco) { BLI_Iterator *iterator = ptr->data; - DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data; + DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; memcpy(orco, deg_iter->dupli_object_current->orco, sizeof(deg_iter->dupli_object_current->orco)); } @@ -99,14 +99,14 @@ static void rna_DepsgraphIter_orco_get(PointerRNA *ptr, float *orco) static unsigned int rna_DepsgraphIter_random_id_get(PointerRNA *ptr) { BLI_Iterator *iterator = ptr->data; - DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data; + DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; return deg_iter->dupli_object_current->random_id; } static void rna_DepsgraphIter_uv_get(PointerRNA *ptr, float *uv) { BLI_Iterator *iterator = ptr->data; - DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data; + DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; memcpy(uv, deg_iter->dupli_object_current->uv, sizeof(deg_iter->dupli_object_current->uv)); } @@ -114,7 +114,7 @@ static void rna_DepsgraphIter_uv_get(PointerRNA *ptr, float *uv) static int rna_DepsgraphIter_is_instance_get(PointerRNA *ptr) { BLI_Iterator *iterator = ptr->data; - DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data; + DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; return (deg_iter->dupli_object_current != NULL); } @@ -149,25 +149,25 @@ static void rna_Depsgraph_debug_stats(Depsgraph *graph, char *result) static void rna_Depsgraph_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__); - DEGObjectsIteratorData *data = MEM_callocN(sizeof(DEGObjectsIteratorData), __func__); + DEGOIterObjectData *data = MEM_callocN(sizeof(DEGOIterObjectData), __func__); data->graph = (Depsgraph *)ptr->data; - data->flag = DEG_OBJECT_ITER_FLAG_SET; + data->flag = DEG_ITER_OBJECT_FLAG_SET; ((BLI_Iterator *)iter->internal.custom)->valid = true; - DEG_objects_iterator_begin(iter->internal.custom, data); + DEG_iterator_objects_begin(iter->internal.custom, data); iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid; } static void rna_Depsgraph_objects_next(CollectionPropertyIterator *iter) { - DEG_objects_iterator_next(iter->internal.custom); + DEG_iterator_objects_next(iter->internal.custom); iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid; } static void rna_Depsgraph_objects_end(CollectionPropertyIterator *iter) { - DEG_objects_iterator_end(iter->internal.custom); + DEG_iterator_objects_end(iter->internal.custom); MEM_freeN(((BLI_Iterator *)iter->internal.custom)->data); MEM_freeN(iter->internal.custom); } @@ -186,25 +186,25 @@ static PointerRNA rna_Depsgraph_objects_get(CollectionPropertyIterator *iter) static void rna_Depsgraph_duplis_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__); - DEGObjectsIteratorData *data = MEM_callocN(sizeof(DEGObjectsIteratorData), __func__); + DEGOIterObjectData *data = MEM_callocN(sizeof(DEGOIterObjectData), __func__); data->graph = (Depsgraph *)ptr->data; - data->flag = DEG_OBJECT_ITER_FLAG_ALL; + data->flag = DEG_ITER_OBJECT_FLAG_ALL; ((BLI_Iterator *)iter->internal.custom)->valid = true; - DEG_objects_iterator_begin(iter->internal.custom, data); + DEG_iterator_objects_begin(iter->internal.custom, data); iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid; } static void rna_Depsgraph_duplis_next(CollectionPropertyIterator *iter) { - DEG_objects_iterator_next(iter->internal.custom); + DEG_iterator_objects_next(iter->internal.custom); iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid; } static void rna_Depsgraph_duplis_end(CollectionPropertyIterator *iter) { - DEG_objects_iterator_end(iter->internal.custom); + DEG_iterator_objects_end(iter->internal.custom); MEM_freeN(((BLI_Iterator *)iter->internal.custom)->data); MEM_freeN(iter->internal.custom); } diff --git a/source/blender/makesrna/intern/rna_group.c b/source/blender/makesrna/intern/rna_group.c index 2a5a0011279..bf64bb1181f 100644 --- a/source/blender/makesrna/intern/rna_group.c +++ b/source/blender/makesrna/intern/rna_group.c @@ -49,8 +49,9 @@ static PointerRNA rna_Group_objects_get(CollectionPropertyIterator *iter) { ListBaseIterator *internal = &iter->internal.listbase; - /* we are actually iterating a GroupObject list, so override get */ - return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ((GroupObject *)internal->link)->ob); + /* we are actually iterating a ObjectBase list, so override get */ + Base *base = (Base *)internal->link; + return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, base->object); } static void rna_Group_objects_link(Group *group, ReportList *reports, Object *object) @@ -124,20 +125,18 @@ void RNA_def_group(BlenderRNA *brna) RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - prop = RNA_def_property(srna, "layers", PROP_BOOLEAN, PROP_LAYER); - RNA_def_property_boolean_sdna(prop, NULL, "layer", 1); - RNA_def_property_array(prop, 20); - RNA_def_property_ui_text(prop, "Dupli Layers", "Layers visible when this group is instanced as a dupli"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "gobject", NULL); + RNA_def_property_collection_sdna(prop, NULL, "view_layer->object_bases", NULL); RNA_def_property_struct_type(prop, "Object"); RNA_def_property_ui_text(prop, "Objects", "A collection of this groups objects"); RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_Group_objects_get", NULL, NULL, NULL, NULL); - rna_def_group_objects(brna, prop); + prop = RNA_def_property(srna, "view_layer", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "ViewLayer"); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "View Layer", "Group internal view layer"); } #endif diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index d516692ec28..212a8bb8e20 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -669,6 +669,7 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_struct_ui_icon(srna, ICON_IMAGE_DATA); prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_string_sdna(prop, NULL, "name"); RNA_def_property_ui_text(prop, "File Name", "Image/Movie file name"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update"); @@ -708,6 +709,7 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Packed Files", "Collection of packed images"); prop = RNA_def_property(srna, "field_order", PROP_ENUM, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, prop_field_order_items); RNA_def_property_ui_text(prop, "Field Order", "Order of video fields (select which lines are displayed first)"); @@ -715,6 +717,7 @@ static void rna_def_image(BlenderRNA *brna) /* booleans */ prop = RNA_def_property(srna, "use_fields", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_FIELDS); RNA_def_property_ui_text(prop, "Fields", "Use fields of the image"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_fields_update"); @@ -722,36 +725,43 @@ static void rna_def_image(BlenderRNA *brna) prop = RNA_def_property(srna, "use_view_as_render", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_VIEW_AS_RENDER); RNA_def_property_ui_text(prop, "View as Render", "Apply render part of display transformation when displaying this image on the screen"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", IMA_IGNORE_ALPHA); RNA_def_property_ui_text(prop, "Use Alpha", "Use the alpha channel information from the image or make image fully opaque"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update"); prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_DEINTERLACE); RNA_def_property_ui_text(prop, "Deinterlace", "Deinterlace movie file on load"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update"); prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_USE_VIEWS); RNA_def_property_ui_text(prop, "Use Multi-View", "Use Multiple Views (when available)"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update"); prop = RNA_def_property(srna, "is_stereo_3d", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_boolean_funcs(prop, "rna_Image_is_stereo_3d_get", NULL); RNA_def_property_ui_text(prop, "Stereo 3D", "Image has left and right views"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_property(srna, "is_multiview", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_boolean_funcs(prop, "rna_Image_is_multiview_get", NULL); RNA_def_property_ui_text(prop, "Multiple Views", "Image has more than one view"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_boolean_funcs(prop, "rna_Image_dirty_get", NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Dirty", "Image has changed and is not saved"); @@ -795,12 +805,14 @@ static void rna_def_image(BlenderRNA *brna) /* realtime properties */ prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, prop_mapping_items); RNA_def_property_ui_text(prop, "Mapping", "Mapping type to use for this image in the game engine"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "display_aspect", PROP_FLOAT, PROP_XYZ); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_float_sdna(prop, NULL, "aspx"); RNA_def_property_array(prop, 2); RNA_def_property_range(prop, 0.1f, FLT_MAX); @@ -809,52 +821,61 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "use_animation", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_TWINANIM); RNA_def_property_ui_text(prop, "Animated", "Use as animated texture in the game engine"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_animated_update"); prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_int_sdna(prop, NULL, "twsta"); RNA_def_property_range(prop, 0, 255); RNA_def_property_ui_text(prop, "Animation Start", "Start frame of an animated texture"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_animated_update"); prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_int_sdna(prop, NULL, "twend"); RNA_def_property_range(prop, 0, 255); RNA_def_property_ui_text(prop, "Animation End", "End frame of an animated texture"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_animated_update"); prop = RNA_def_property(srna, "fps", PROP_INT, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_int_sdna(prop, NULL, "animspeed"); RNA_def_property_range(prop, 1, 100); RNA_def_property_ui_text(prop, "Animation Speed", "Speed of the animation in frames per second"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "use_tiles", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_TILES); RNA_def_property_ui_text(prop, "Tiles", "Use of tilemode for faces (default shift-LMB to pick the tile for selected faces)"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "tiles_x", PROP_INT, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_int_sdna(prop, NULL, "xrep"); RNA_def_property_range(prop, 1, 16); RNA_def_property_ui_text(prop, "Tiles X", "Degree of repetition in the X direction"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "tiles_y", PROP_INT, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_int_sdna(prop, NULL, "yrep"); RNA_def_property_range(prop, 1, 16); RNA_def_property_ui_text(prop, "Tiles Y", "Degree of repetition in the Y direction"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "use_clamp_x", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_CLAMP_U); RNA_def_property_ui_text(prop, "Clamp X", "Disable texture repeating horizontally"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "use_clamp_y", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_CLAMP_V); RNA_def_property_ui_text(prop, "Clamp Y", "Disable texture repeating vertically"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); @@ -893,6 +914,7 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_float_vector(srna, "resolution", 2, NULL, 0, 0, "Resolution", "X/Y pixels per meter", 0, 0); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_float_funcs(prop, "rna_Image_resolution_get", "rna_Image_resolution_set", NULL); prop = RNA_def_property(srna, "frame_duration", PROP_INT, PROP_UNSIGNED); @@ -927,12 +949,14 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings"); prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_enum_items(prop, alpha_mode_items); RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update"); /* multiview */ prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_enum_sdna(prop, NULL, "views_format"); RNA_def_property_enum_items(prop, rna_enum_views_format_items); RNA_def_property_ui_text(prop, "Views Format", "Mode to load image views"); diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 23a34918d33..7dffab4eefb 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -37,6 +37,9 @@ struct FreestyleSettings; struct ID; +struct IDOverrideStatic; +struct IDOverrideStaticProperty; +struct IDOverrideStaticPropertyOperation; struct IDProperty; struct Main; struct Mesh; @@ -201,6 +204,12 @@ void RNA_def_mask(struct BlenderRNA *brna); void rna_def_animdata_common(struct StructRNA *srna); +bool rna_AnimaData_override_apply( + struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage, + struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage, + const int len_local, const int len_reference, const int len_storage, + struct IDOverrideStaticPropertyOperation *opop); + void rna_def_animviz_common(struct StructRNA *srna); void rna_def_motionpath_common(struct StructRNA *srna); @@ -391,6 +400,33 @@ extern StructRNA RNA_PropertyGroup; struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop, struct PointerRNA *ptr); +/* Override default callbacks. */ +/* Default override callbacks for all types. */ +/* TODO: Maybe at some point we'll want to write that in direct RNA-generated code instead + * (like we do for default get/set/etc.)? + * Not obvious though, those are fairly more complicated than basic SDNA access. + */ +int rna_property_override_diff_default( + struct PointerRNA *ptr_a, struct PointerRNA *ptr_b, + struct PropertyRNA *prop_a, struct PropertyRNA *prop_b, + const int len_a, const int len_b, + const int mode, + struct IDOverrideStatic *override, const char *rna_path, + const int flags, bool *r_override_changed); + +bool rna_property_override_store_default( + struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage, + struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage, + const int len_local, const int len_reference, const int len_storage, + struct IDOverrideStaticPropertyOperation *opop); + +bool rna_property_override_apply_default( + struct PointerRNA *ptr_dst, struct PointerRNA *ptr_src, struct PointerRNA *ptr_storage, + struct PropertyRNA *prop_dst, struct PropertyRNA *prop_src, struct PropertyRNA *prop_storage, + const int len_dst, const int len_src, const int len_storage, + struct IDOverrideStaticPropertyOperation *opop); + + /* Builtin Property Callbacks */ void rna_builtin_properties_begin(struct CollectionPropertyIterator *iter, struct PointerRNA *ptr); diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index b43423464e9..fd0b655e41e 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -40,6 +40,9 @@ struct PointerRNA; struct FunctionRNA; struct CollectionPropertyIterator; struct bContext; +struct IDOverrideStatic; +struct IDOverrideStaticProperty; +struct IDOverrideStaticPropertyOperation; struct IDProperty; struct GHash; struct Main; @@ -117,6 +120,60 @@ typedef void (*PropStringSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA * typedef int (*PropEnumGetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *prop); typedef void (*PropEnumSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *prop, int value); +/* Handling override operations, and also comparison. */ +enum { + /* Do not compare properties that are not overridable. */ + RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE = 1 << 0, + /* Do not compare properties that are already overridden. */ + RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN = 1 << 1, +}; + +/** + * If \a override is NULL, merely do comparison between prop_a from ptr_a and prop_b from ptr_b, + * following comparison mode given. + * If \a override and \a rna_path are not NULL, it will add a new override operation for overridable properties + * that differ and have not yet been overridden (and set accordingly \a r_override_changed if given). + * + * \note Given PropertyRNA are final (in case of IDProps...). + * \note In non-array cases, \a len values are 0. + * \note \a override, \a rna_path and \a r_override_changed may be NULL pointers. + */ +typedef int (*RNAPropOverrideDiff)( + struct PointerRNA *ptr_a, struct PointerRNA *ptr_b, + struct PropertyRNA *prop_a, struct PropertyRNA *prop_b, + const int len_a, const int len_b, + const int mode, + struct IDOverrideStatic *override, const char *rna_path, + const int flags, bool *r_override_changed); + +/** + * Only used for differential override (add, sub, etc.). + * Store into storage the value needed to transform reference's value into local's value. + * + * \note Given PropertyRNA are final (in case of IDProps...). + * \note In non-array cases, \a len values are 0. + * \note Might change given override operation (e.g. change 'add' one into 'sub'), in case computed storage value + * is out of range (or even change it to basic 'set' operation if nothing else works). + */ +typedef bool (*RNAPropOverrideStore)( + struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage, + struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage, + const int len_local, const int len_reference, const int len_storage, + struct IDOverrideStaticPropertyOperation *opop); + +/** + * Apply given override operation from src to dst (using value from storage as second operand + * for differential operations). + * + * \note Given PropertyRNA are final (in case of IDProps...). + * \note In non-array cases, \a len values are 0. + */ +typedef bool (*RNAPropOverrideApply)( + struct PointerRNA *ptr_dst, struct PointerRNA *ptr_src, struct PointerRNA *ptr_storage, + struct PropertyRNA *prop_dst, struct PropertyRNA *prop_src, struct PropertyRNA *prop_storage, + const int len_dst, const int len_src, const int len_storage, + struct IDOverrideStaticPropertyOperation *opop); + /* Container - generic abstracted container of RNA properties */ typedef struct ContainerRNA { void *next, *prev; @@ -194,6 +251,11 @@ struct PropertyRNA { /* callback for testing if array-item editable (if applicable) */ ItemEditableFunc itemeditable; + /* Override handling callbacks (diff is also used for comparison). */ + RNAPropOverrideDiff override_diff; + RNAPropOverrideStore override_store; + RNAPropOverrideApply override_apply; + /* raw access */ int rawoffset; RawPropertyType rawtype; diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index 4583774318b..877d6b250c0 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -54,8 +54,15 @@ const EnumPropertyItem rna_enum_layer_collection_mode_settings_type_items[] = { {0, NULL, 0, NULL, NULL} }; +const EnumPropertyItem rna_enum_collection_type_items[] = { + {COLLECTION_TYPE_NONE, "NONE", 0, "Normal", ""}, + {COLLECTION_TYPE_GROUP_INTERNAL, "GROUP_INTERNAL", 0, "Group Internal", ""}, + {0, NULL, 0, NULL, NULL} +}; + #ifdef RNA_RUNTIME +#include "DNA_group_types.h" #include "DNA_object_types.h" #include "RNA_access.h" @@ -69,6 +76,20 @@ const EnumPropertyItem rna_enum_layer_collection_mode_settings_type_items[] = { #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" +static StructRNA *rna_SceneCollection_refine(PointerRNA *ptr) +{ + SceneCollection *scene_collection = (SceneCollection *)ptr->data; + switch (scene_collection->type) { + case COLLECTION_TYPE_GROUP_INTERNAL: + case COLLECTION_TYPE_NONE: + return &RNA_SceneCollection; + default: + BLI_assert(!"Collection type not fully implemented"); + break; + } + return &RNA_SceneCollection; +} + static void rna_SceneCollection_name_set(PointerRNA *ptr, const char *value) { Scene *scene = (Scene *)ptr->id.data; @@ -96,9 +117,7 @@ static PointerRNA rna_SceneCollection_objects_get(CollectionPropertyIterator *it static int rna_SceneCollection_move_above(ID *id, SceneCollection *sc_src, Main *bmain, SceneCollection *sc_dst) { - Scene *scene = (Scene *)id; - - if (!BKE_collection_move_above(scene, sc_dst, sc_src)) { + if (!BKE_collection_move_above(id, sc_dst, sc_src)) { return 0; } @@ -110,9 +129,7 @@ static int rna_SceneCollection_move_above(ID *id, SceneCollection *sc_src, Main static int rna_SceneCollection_move_below(ID *id, SceneCollection *sc_src, Main *bmain, SceneCollection *sc_dst) { - Scene *scene = (Scene *)id; - - if (!BKE_collection_move_below(scene, sc_dst, sc_src)) { + if (!BKE_collection_move_below(id, sc_dst, sc_src)) { return 0; } @@ -124,9 +141,7 @@ static int rna_SceneCollection_move_below(ID *id, SceneCollection *sc_src, Main static int rna_SceneCollection_move_into(ID *id, SceneCollection *sc_src, Main *bmain, SceneCollection *sc_dst) { - Scene *scene = (Scene *)id; - - if (!BKE_collection_move_into(scene, sc_dst, sc_src)) { + if (!BKE_collection_move_into(id, sc_dst, sc_src)) { return 0; } @@ -139,8 +154,7 @@ static int rna_SceneCollection_move_into(ID *id, SceneCollection *sc_src, Main * static SceneCollection *rna_SceneCollection_new( ID *id, SceneCollection *sc_parent, Main *bmain, const char *name) { - Scene *scene = (Scene *)id; - SceneCollection *sc = BKE_collection_add(scene, sc_parent, name); + SceneCollection *sc = BKE_collection_add(id, sc_parent, COLLECTION_TYPE_NONE, name); DEG_relations_tag_update(bmain); WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); @@ -151,7 +165,6 @@ static SceneCollection *rna_SceneCollection_new( static void rna_SceneCollection_remove( ID *id, SceneCollection *sc_parent, Main *bmain, ReportList *reports, PointerRNA *sc_ptr) { - Scene *scene = (Scene *)id; SceneCollection *sc = sc_ptr->data; const int index = BLI_findindex(&sc_parent->scene_collections, sc); @@ -161,7 +174,7 @@ static void rna_SceneCollection_remove( return; } - if (!BKE_collection_remove(scene, sc)) { + if (!BKE_collection_remove(id, sc)) { BKE_reportf(reports, RPT_ERROR, "Collection '%s' could not be removed from collection '%s'", sc->name, sc_parent->name); return; @@ -203,7 +216,7 @@ void rna_SceneCollection_object_link( return; } - BKE_collection_object_add(scene, sc, ob); + BKE_collection_object_add(&scene->id, sc, ob); /* TODO(sergey): Only update relations for the current scene. */ DEG_relations_tag_update(bmain); @@ -226,7 +239,7 @@ static void rna_SceneCollection_object_unlink( return; } - BKE_collection_object_remove(bmain, scene, sc, ob, false); + BKE_collection_object_remove(bmain, &scene->id, sc, ob, false); /* needed otherwise the depgraph will contain freed objects which can crash, see [#20958] */ DEG_relations_tag_update(bmain); @@ -386,6 +399,7 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(shadow_high_bitdepth) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(taa_samples) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gi_diffuse_bounces) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gi_cubemap_resolution) +RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gi_visibility_resolution) /* object engine */ RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(show_wire) @@ -417,11 +431,17 @@ static void rna_ViewLayerEngineSettings_update(bContext *C, PointerRNA *UNUSED(p DEG_id_tag_update(&scene->id, 0); } -static void rna_LayerCollectionEngineSettings_update(bContext *C, PointerRNA *UNUSED(ptr)) +static void rna_LayerCollectionEngineSettings_update(bContext *UNUSED(C), PointerRNA *ptr) { - Scene *scene = CTX_data_scene(C); + ID *id = ptr->id.data; /* TODO(sergey): Use proper flag for tagging here. */ - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(id, 0); + + /* Instead of passing 'noteflag' to the rna update function, we handle the notifier ourselves. + * We need to do this because the LayerCollection may be coming from different ID types (Scene or Group) + * and when using NC_SCENE the id most match the active scene for the listener to receive the notification.*/ + + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); } static void rna_LayerCollectionEngineSettings_wire_update(bContext *C, PointerRNA *UNUSED(ptr)) @@ -641,9 +661,7 @@ static PointerRNA rna_LayerCollection_objects_get(CollectionPropertyIterator *it static int rna_LayerCollection_move_above(ID *id, LayerCollection *lc_src, Main *bmain, LayerCollection *lc_dst) { - Scene *scene = (Scene *)id; - - if (!BKE_layer_collection_move_above(scene, lc_dst, lc_src)) { + if (!BKE_layer_collection_move_above(id, lc_dst, lc_src)) { return 0; } @@ -655,9 +673,7 @@ static int rna_LayerCollection_move_above(ID *id, LayerCollection *lc_src, Main static int rna_LayerCollection_move_below(ID *id, LayerCollection *lc_src, Main *bmain, LayerCollection *lc_dst) { - Scene *scene = (Scene *)id; - - if (!BKE_layer_collection_move_below(scene, lc_dst, lc_src)) { + if (!BKE_layer_collection_move_below(id, lc_dst, lc_src)) { return 0; } @@ -669,9 +685,7 @@ static int rna_LayerCollection_move_below(ID *id, LayerCollection *lc_src, Main static int rna_LayerCollection_move_into(ID *id, LayerCollection *lc_src, Main *bmain, LayerCollection *lc_dst) { - Scene *scene = (Scene *)id; - - if (!BKE_layer_collection_move_into(scene, lc_dst, lc_src)) { + if (!BKE_layer_collection_move_into(id, lc_dst, lc_src)) { return 0; } @@ -681,19 +695,27 @@ static int rna_LayerCollection_move_into(ID *id, LayerCollection *lc_src, Main * return 1; } -static void rna_LayerCollection_flag_update(bContext *C, PointerRNA *UNUSED(ptr)) +static void rna_LayerCollection_flag_update(bContext *C, PointerRNA *ptr) { - Scene *scene = CTX_data_scene(C); + ID *id = ptr->id.data; /* TODO(sergey): Use proper flag for tagging here. */ - DEG_id_tag_update(&scene->id, 0); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + DEG_id_tag_update(id, 0); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); } static void rna_LayerCollection_enable_set( ID *id, LayerCollection *layer_collection, Main *bmain, bContext *C, ReportList *reports, int value) { - Scene *scene = (Scene *)id; - ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection); + ViewLayer *view_layer; + if (GS(id->name) == ID_SCE) { + Scene *scene = (Scene *)id; + view_layer = BKE_view_layer_find_from_collection(&scene->id, layer_collection); + } + else { + BLI_assert(GS(id->name) == ID_GR); + Group *group = (Group *)id; + view_layer = group->view_layer; + } if (layer_collection->flag & COLLECTION_DISABLED) { if (value == 1) { @@ -715,6 +737,7 @@ static void rna_LayerCollection_enable_set( } } + Scene *scene = CTX_data_scene(C); DEG_relations_tag_update(bmain); /* TODO(sergey): Use proper flag for tagging here. */ DEG_id_tag_update(&scene->id, 0); @@ -722,6 +745,32 @@ static void rna_LayerCollection_enable_set( WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); } +static Group *rna_LayerCollection_create_group( + ID *id, LayerCollection *layer_collection, Main *bmain, bContext *C, ReportList *reports) +{ + Group *group; + Scene *scene = (Scene *)id; + SceneCollection *scene_collection = layer_collection->scene_collection; + + /* The master collection can't be converted. */ + if (scene_collection == BKE_collection_master(&scene->id)) { + BKE_report(reports, RPT_ERROR, "The master collection can't be converted to group"); + return NULL; + } + + group = BKE_collection_group_create(bmain, scene, layer_collection); + if (group == NULL) { + BKE_reportf(reports, RPT_ERROR, "Failed to convert collection %s", scene_collection->name); + return NULL; + } + + DEG_relations_tag_update(bmain); + /* TODO(sergey): Use proper flag for tagging here. */ + DEG_id_tag_update(&scene->id, 0); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + return group; +} + static int rna_LayerCollections_active_collection_index_get(PointerRNA *ptr) { ViewLayer *view_layer = (ViewLayer *)ptr->data; @@ -863,7 +912,7 @@ static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, Po static void rna_ViewLayer_update_tagged(ViewLayer *UNUSED(view_layer), bContext *C) { Depsgraph *graph = CTX_data_depsgraph(C); - DEG_OBJECT_ITER(graph, ob, DEG_OBJECT_ITER_FLAG_ALL) + DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_ALL) { /* Don't do anything, we just need to run the iterator to flush * the base info to the objects. */ @@ -1034,6 +1083,7 @@ static void rna_def_scene_collection(BlenderRNA *brna) srna = RNA_def_struct(brna, "SceneCollection", NULL); RNA_def_struct_ui_text(srna, "Scene Collection", "Collection"); + RNA_def_struct_refine_func(srna, "rna_SceneCollection_refine"); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneCollection_name_set"); @@ -1041,6 +1091,11 @@ static void rna_def_scene_collection(BlenderRNA *brna) RNA_def_struct_name_property(srna, prop); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL); + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_collection_type_items); + RNA_def_property_ui_text(prop, "Type", "Type of collection"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + prop = RNA_def_property(srna, "filter", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneCollection_filter_set"); RNA_def_property_ui_text(prop, "Filter", "Filter to dynamically include objects based on their names (e.g., CHAR_*)"); @@ -1152,6 +1207,14 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static const EnumPropertyItem eevee_gi_visibility_size_items[] = { + {8, "8", 0, "8px", ""}, + {16, "16", 0, "16px", ""}, + {32, "32", 0, "32px", ""}, + {64, "64", 0, "64px", ""}, + {0, NULL, 0, NULL, NULL} + }; + static const EnumPropertyItem eevee_volumetric_tile_size_items[] = { {2, "2", 0, "2px", ""}, {4, "4", 0, "4px", ""}, @@ -1178,12 +1241,22 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update"); prop = RNA_def_property(srna, "gi_cubemap_resolution", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_funcs(prop, "rna_LayerEngineSettings_Eevee_gi_cubemap_resolution_get", "rna_LayerEngineSettings_Eevee_gi_cubemap_resolution_set", NULL); + RNA_def_property_enum_funcs(prop, "rna_LayerEngineSettings_Eevee_gi_cubemap_resolution_get", + "rna_LayerEngineSettings_Eevee_gi_cubemap_resolution_set", NULL); RNA_def_property_enum_items(prop, eevee_shadow_size_items); RNA_def_property_ui_text(prop, "Cubemap Size", "Size of every cubemaps"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update"); + prop = RNA_def_property(srna, "gi_visibility_resolution", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_funcs(prop, "rna_LayerEngineSettings_Eevee_gi_visibility_resolution_get", + "rna_LayerEngineSettings_Eevee_gi_visibility_resolution_set", NULL); + RNA_def_property_enum_items(prop, eevee_gi_visibility_size_items); + RNA_def_property_ui_text(prop, "Irradiance Visibility Size", + "Size of the shadow map applied to each irradiance sample"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update"); + /* Temporal Anti-Aliasing (super sampling) */ prop = RNA_def_property(srna, "taa_samples", PROP_INT, PROP_NONE); RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_taa_samples_get", @@ -1420,14 +1493,14 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 2); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "gtao_quality", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_quality_get", "rna_LayerEngineSettings_Eevee_gtao_quality_set", NULL); RNA_def_property_ui_text(prop, "Trace Quality", "Quality of the horizon search"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "gtao_distance", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_distance_get", "rna_LayerEngineSettings_Eevee_gtao_distance_set", NULL); @@ -1435,7 +1508,7 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, 100000.0f); RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "gtao_samples", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_samples_get", @@ -1624,49 +1697,49 @@ static void rna_def_layer_collection_engine_settings_clay(BlenderRNA *brna) RNA_def_property_enum_items(prop, clay_matcap_items); RNA_def_property_ui_text(prop, "Matcap", "Image to use for Material Capture by this material"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "matcap_rotation", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_rotation_get", "rna_LayerEngineSettings_Clay_matcap_rotation_set", NULL); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Matcap Rotation", "Orientation of the matcap on the model"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "matcap_hue", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_hue_get", "rna_LayerEngineSettings_Clay_matcap_hue_set", NULL); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Matcap Hue Shift", "Hue correction of the matcap"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "matcap_saturation", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_saturation_get", "rna_LayerEngineSettings_Clay_matcap_saturation_set", NULL); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Matcap Saturation", "Saturation correction of the matcap"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "matcap_value", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_value_get", "rna_LayerEngineSettings_Clay_matcap_value_set", NULL); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Matcap Value", "Value correction of the matcap"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "ssao_factor_cavity", PROP_FLOAT, PROP_NONE); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_factor_cavity_get", "rna_LayerEngineSettings_Clay_ssao_factor_cavity_set", NULL); RNA_def_property_ui_text(prop, "Cavity Strength", "Strength of the Cavity effect"); RNA_def_property_range(prop, 0.0f, 250.0f); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "ssao_factor_edge", PROP_FLOAT, PROP_NONE); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_factor_edge_get", "rna_LayerEngineSettings_Clay_ssao_factor_edge_set", NULL); RNA_def_property_ui_text(prop, "Edge Strength", "Strength of the Edge effect"); RNA_def_property_range(prop, 0.0f, 250.0f); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "ssao_distance", PROP_FLOAT, PROP_NONE); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_distance_get", "rna_LayerEngineSettings_Clay_ssao_distance_set", NULL); @@ -1674,7 +1747,7 @@ static void rna_def_layer_collection_engine_settings_clay(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, 100000.0f); RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "ssao_attenuation", PROP_FLOAT, PROP_NONE); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_attenuation_get", "rna_LayerEngineSettings_Clay_ssao_attenuation_set", NULL); @@ -1682,14 +1755,14 @@ static void rna_def_layer_collection_engine_settings_clay(BlenderRNA *brna) RNA_def_property_range(prop, 1.0f, 100000.0f); RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "hair_brightness_randomness", PROP_FLOAT, PROP_NONE); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_hair_brightness_randomness_get", "rna_LayerEngineSettings_Clay_hair_brightness_randomness_set", NULL); RNA_def_property_ui_text(prop, "Hair Brightness Randomness", "Brightness randomness for hair"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); RNA_define_verify_sdna(1); /* not in sdna */ } @@ -1710,13 +1783,13 @@ static void rna_def_layer_collection_mode_settings_object(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Wire", "Add the object's wireframe over solid drawing"); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_ObjectMode_show_wire_get", "rna_LayerEngineSettings_ObjectMode_show_wire_set"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "show_backface_culling", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text(prop, "Backface Culling", ""); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_ObjectMode_show_backface_culling_get", "rna_LayerEngineSettings_ObjectMode_show_backface_culling_set"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); RNA_define_verify_sdna(1); /* not in sdna */ } @@ -1736,31 +1809,31 @@ static void rna_def_layer_collection_mode_settings_edit(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Hidden Wire", "Use hidden wireframe display"); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_show_occlude_wire_get", "rna_LayerEngineSettings_EditMode_show_occlude_wire_set"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "show_weight", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text(prop, "Show Weights", "Draw weights in editmode"); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_show_weight_get", "rna_LayerEngineSettings_EditMode_show_weight_set"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "face_normals_show", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text(prop, "Draw Normals", "Display face normals as lines"); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_face_normals_show_get", "rna_LayerEngineSettings_EditMode_face_normals_show_set"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "vert_normals_show", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text(prop, "Draw Vertex Normals", "Display vertex normals as lines"); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_vert_normals_show_get", "rna_LayerEngineSettings_EditMode_vert_normals_show_set"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "loop_normals_show", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text(prop, "Draw Split Normals", "Display vertex-per-face normals as lines"); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_loop_normals_show_get", "rna_LayerEngineSettings_EditMode_loop_normals_show_set"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "normals_length", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Normal Size", "Display size for normals in the 3D view"); @@ -1768,14 +1841,14 @@ static void rna_def_layer_collection_mode_settings_edit(BlenderRNA *brna) RNA_def_property_range(prop, 0.00001, 1000.0); RNA_def_property_ui_range(prop, 0.01, 10.0, 10.0, 2); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "backwire_opacity", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Backwire Opacity", "Opacity when rendering transparent wires"); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_EditMode_backwire_opacity_get", "rna_LayerEngineSettings_EditMode_backwire_opacity_set", NULL); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); RNA_define_verify_sdna(1); /* not in sdna */ } @@ -1795,7 +1868,7 @@ static void rna_def_layer_collection_mode_settings_paint_weight(BlenderRNA *brna RNA_def_property_ui_text(prop, "Use Shading", "Whether to use shaded or shadeless drawing"); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_PaintWeightMode_use_shading_get", "rna_LayerEngineSettings_PaintWeightMode_use_shading_set"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "use_wire", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text(prop, "Show Wire", "Whether to overlay wireframe onto the mesh"); @@ -1821,7 +1894,7 @@ static void rna_def_layer_collection_mode_settings_paint_vertex(BlenderRNA *brna RNA_def_property_ui_text(prop, "Use Shading", "Whether to use shaded or shadeless drawing"); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_PaintVertexMode_use_shading_get", "rna_LayerEngineSettings_PaintVertexMode_use_shading_set"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update"); + RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); prop = RNA_def_property(srna, "use_wire", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text(prop, "Show Wire", "Whether to overlay wireframe onto the mesh"); @@ -1997,6 +2070,12 @@ static void rna_def_layer_collection(BlenderRNA *brna) parm = RNA_def_boolean(func, "value", 1, "Enable", ""); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + func = RNA_def_function(srna, "create_group", "rna_LayerCollection_create_group"); + RNA_def_function_ui_description(func, "Enable or disable a collection"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "result", "Group", "", "Newly created Group"); + RNA_def_function_return(func, parm); + /* Flags */ prop = RNA_def_property(srna, "is_enabled", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_DISABLED); diff --git a/source/blender/makesrna/intern/rna_lightprobe.c b/source/blender/makesrna/intern/rna_lightprobe.c index 448d847a959..61dc835022b 100644 --- a/source/blender/makesrna/intern/rna_lightprobe.c +++ b/source/blender/makesrna/intern/rna_lightprobe.c @@ -160,6 +160,25 @@ static void rna_def_lightprobe(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Resolution Z", "Number of sample along the z axis of the volume"); RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc"); + prop = RNA_def_property(srna, "visibility_buffer_bias", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "vis_bias"); + RNA_def_property_range(prop, 0.001f, 9999.0f); + RNA_def_property_ui_range(prop, 0.001f, 5.0f, 1.0, 3); + RNA_def_property_ui_text(prop, "Visibility Bias", "Bias for reducing self shadowing"); + RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL); + + prop = RNA_def_property(srna, "visibility_bleed_bias", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "vis_bleedbias"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Visibility Bleed Bias", "Bias for reducing light-bleed on variance shadow maps"); + RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL); + + prop = RNA_def_property(srna, "visibility_blur", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "vis_blur"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Visibility Blur", "Filter size of the visibilty blur"); + RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc"); + /* Data preview */ prop = RNA_def_property(srna, "show_data", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LIGHTPROBE_FLAG_SHOW_DATA); diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index d1b28bffc7e..f15006fa0ed 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -249,7 +249,6 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char } ob = BKE_object_add_only_object(bmain, type, safe_name); - id_us_min(&ob->id); ob->data = data; test_object_materials(ob, ob->data); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index d482f7e1b94..c443b68b209 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1817,7 +1817,7 @@ static void rna_def_modifier_armature(BlenderRNA *brna) prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Object", "Armature object to deform with"); RNA_def_property_pointer_funcs(prop, NULL, "rna_ArmatureModifier_object_set", NULL, "rna_Armature_object_poll"); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_OVERRIDABLE_STATIC); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "use_bone_envelopes", PROP_BOOLEAN, PROP_NONE); @@ -2997,7 +2997,7 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) prop = RNA_def_property(srna, "profile", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_range(prop, 0.15f, 1.0f, 0.05, 2); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.05, 2); RNA_def_property_ui_text(prop, "Profile", "The profile shape (0.5 = round)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 37957f55f5c..a153590f4ac 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -57,7 +57,6 @@ #include "BLI_sys_types.h" /* needed for intptr_t used in ED_mesh.h */ #include "ED_mesh.h" -#include "ED_object.h" #include "WM_api.h" #include "WM_types.h" @@ -2423,7 +2422,7 @@ static void rna_def_object(BlenderRNA *brna) /* parent */ prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_parent_set", NULL, NULL); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Parent", "Parent Object"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update"); @@ -2501,6 +2500,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_float_sdna(prop, NULL, "loc"); RNA_def_property_editable_array_func(prop, "rna_Object_location_editable"); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Location", "Location of the object"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); @@ -2508,6 +2508,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION); RNA_def_property_float_sdna(prop, NULL, "quat"); RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable"); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_float_array_default(prop, default_quat); RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); @@ -2521,12 +2522,14 @@ static void rna_def_object(BlenderRNA *brna) "rna_Object_rotation_axis_angle_set", NULL); RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable"); RNA_def_property_float_array_default(prop, default_axisAngle); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Axis-Angle Rotation", "Angle of Rotation for Axis-Angle rotation representation"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); prop = RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER); RNA_def_property_float_sdna(prop, NULL, "rot"); RNA_def_property_editable_array_func(prop, "rna_Object_rotation_euler_editable"); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); @@ -2539,7 +2542,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "size"); - RNA_def_property_flag(prop, PROP_PROPORTIONAL); + RNA_def_property_flag(prop, PROP_PROPORTIONAL | PROP_OVERRIDABLE_STATIC); RNA_def_property_editable_array_func(prop, "rna_Object_scale_editable"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3); RNA_def_property_float_array_default(prop, default_scale); @@ -2666,6 +2669,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "Modifier"); RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting the geometric data of the object"); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); rna_def_object_modifiers(brna, prop); /* constraints */ @@ -2978,6 +2982,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "pose", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "pose"); RNA_def_property_struct_type(prop, "Pose"); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Pose", "Current pose for armatures"); /* shape keys */ diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index b4c721a88b3..baf7f5e6aa3 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -839,6 +839,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) /* Transformation settings */ prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_float_sdna(prop, NULL, "loc"); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_editable_array_func(prop, "rna_PoseChannel_location_editable"); RNA_def_property_ui_text(prop, "Location", ""); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); @@ -846,7 +847,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "size"); - RNA_def_property_flag(prop, PROP_PROPORTIONAL); + RNA_def_property_flag(prop, PROP_PROPORTIONAL | PROP_OVERRIDABLE_STATIC); RNA_def_property_editable_array_func(prop, "rna_PoseChannel_scale_editable"); RNA_def_property_float_array_default(prop, default_scale); RNA_def_property_ui_text(prop, "Scale", ""); @@ -854,6 +855,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION); RNA_def_property_float_sdna(prop, NULL, "quat"); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_editable_array_func(prop, "rna_PoseChannel_rotation_4d_editable"); RNA_def_property_float_array_default(prop, default_quat); RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions"); @@ -863,6 +865,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) * having a single one is better for Keyframing and other property-management situations... */ prop = RNA_def_property(srna, "rotation_axis_angle", PROP_FLOAT, PROP_AXISANGLE); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_array(prop, 4); RNA_def_property_float_funcs(prop, "rna_PoseChannel_rotation_axis_angle_get", "rna_PoseChannel_rotation_axis_angle_set", NULL); @@ -873,6 +876,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop = RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER); RNA_def_property_float_sdna(prop, NULL, "eul"); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_editable_array_func(prop, "rna_PoseChannel_rotation_euler_editable"); RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); @@ -1399,6 +1403,7 @@ static void rna_def_pose(BlenderRNA *brna) prop = RNA_def_property(srna, "bones", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "chanbase", NULL); RNA_def_property_struct_type(prop, "PoseBone"); + RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Pose Bones", "Individual pose bones for the armature"); /* can be removed, only for fast lookup */ RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, "rna_PoseBones_lookup_string", NULL); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 507262675b3..24d56ef2a19 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -107,6 +107,8 @@ const EnumPropertyItem rna_enum_property_unit_items[] = { #include "MEM_guardedalloc.h" #include "BLI_ghash.h" +#include "BKE_library_override.h" + /* Struct */ static void rna_Struct_identifier_get(PointerRNA *ptr, char *value) @@ -564,6 +566,13 @@ static int rna_Property_animatable_get(PointerRNA *ptr) return (prop->flag & PROP_ANIMATABLE) != 0; } +static int rna_Property_overridable_get(PointerRNA *ptr) +{ + PropertyRNA *prop = (PropertyRNA *)ptr->data; + + return (prop->flag & PROP_OVERRIDABLE_STATIC) != 0; +} + static int rna_Property_use_output_get(PointerRNA *ptr) { PropertyRNA *prop = (PropertyRNA *)ptr->data; @@ -1082,6 +1091,1003 @@ static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key return false; } +/* Default override (and compare) callbacks. */ + +/* Used for both Pointer and Collection properties. */ +static int rna_property_override_equals_propptr( + PointerRNA *propptr_a, PointerRNA *propptr_b, eRNACompareMode mode, + IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags) +{ + bool is_id = false; + bool is_type_null = false; + + /* Beware, PointerRNA_NULL has no type and is considered a 'blank page'! */ + if (propptr_a->type == NULL) { + if (propptr_b->type == NULL) { + if (r_override_changed) { + *r_override_changed = false; + } + return 0; + } + is_id = RNA_struct_is_ID(propptr_b->type); + is_type_null = true; + } + else { + is_id = RNA_struct_is_ID(propptr_a->type); + is_type_null = (propptr_b->type == NULL); + } + + if (is_id) { + BLI_assert(propptr_a->data == propptr_a->id.data && propptr_b->data == propptr_b->id.data); + } + + if (override) { + if (rna_path) { + if (is_type_null || is_id) { + /* In case this is an ID (or one of the pointers is NULL), do not compare structs! + * This is a quite safe path to infinite loop. + * Instead, just compare pointers themselves (we assume sub-ID structs cannot loop). */ + const int comp = (propptr_a->data != propptr_b->data); + + if (comp != 0 && rna_path) { + bool created = false; + IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); + + if (op != NULL && created) { /* If not yet overridden... */ + BKE_override_static_property_operation_get( + op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL); + if (r_override_changed) { + *r_override_changed = created; + } + } + } + + return comp; + } + else { + const bool changed = RNA_struct_auto_override(propptr_a, propptr_b, override, rna_path); + if (r_override_changed) { + *r_override_changed = *r_override_changed || changed; + } + /* XXX Simplification here, if no override was added we assume they are equal, + * this may not be good behavior, time will say. */ + return !changed; + } + } + else { + return !RNA_struct_override_matches( + propptr_a, propptr_b, override, + flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE, + flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN); + } + } + else { + return !RNA_struct_equals(propptr_a, propptr_b, mode); + } +} + +static char *rna_path_collection_prop_item_extend(const char *rna_path_prop, const char *item_name) +{ + const size_t esc_item_name_len = strlen(item_name) * 2; + char *esc_item_name = alloca(sizeof(*esc_item_name) * esc_item_name_len); + BLI_strescape(esc_item_name, item_name, esc_item_name_len); + return BLI_sprintfN("%s[\"%s\"]", rna_path_prop, esc_item_name); +} + +int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, + PropertyRNA *prop_a, PropertyRNA *prop_b, + const int len_a, const int len_b, + const int mode, + IDOverrideStatic *override, const char *rna_path, + const int flags, bool *r_override_changed) +{ + BLI_assert(len_a == len_b); + + switch (RNA_property_type(prop_a)) { + case PROP_BOOLEAN: + { + if (len_a) { + int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY]; + int *array_a, *array_b; + + array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_a, "RNA equals") : array_stack_a; + array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_b, "RNA equals") : array_stack_b; + + RNA_property_boolean_get_array(ptr_a, prop_a, array_a); + RNA_property_boolean_get_array(ptr_b, prop_b, array_b); + + const int comp = memcmp(array_a, array_b, sizeof(int) * len_a); + + if (comp != 0 && rna_path) { + /* XXX TODO this will have to be refined to handle array items */ + bool created = false; + IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); + + if (op != NULL && created) { + BKE_override_static_property_operation_get( + op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL); + if (r_override_changed) { + *r_override_changed = created; + } + } + else { + /* Already overriden prop, we'll have to check arrays items etc. */ + } + } + + if (array_a != array_stack_a) MEM_freeN(array_a); + if (array_b != array_stack_b) MEM_freeN(array_b); + + return comp; + } + else { + const int value_a = RNA_property_boolean_get(ptr_a, prop_a); + const int value_b = RNA_property_boolean_get(ptr_b, prop_b); + const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0; + + if (comp != 0 && rna_path) { + bool created = false; + IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); + + if (op != NULL && created) { /* If not yet overridden... */ + BKE_override_static_property_operation_get( + op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL); + if (r_override_changed) { + *r_override_changed = created; + } + } + } + + return comp; + } + } + + case PROP_INT: + { + if (len_a) { + int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY]; + int *array_a, *array_b; + + array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_a, "RNA equals") : array_stack_a; + array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_b, "RNA equals") : array_stack_b; + + RNA_property_int_get_array(ptr_a, prop_a, array_a); + RNA_property_int_get_array(ptr_b, prop_b, array_b); + + const int comp = memcmp(array_a, array_b, sizeof(int) * len_a); + + if (comp != 0 && rna_path) { + /* XXX TODO this will have to be refined to handle array items */ + bool created = false; + IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); + + if (op != NULL && created) { + BKE_override_static_property_operation_get( + op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL); + if (r_override_changed) { + *r_override_changed = created; + } + } + else { + /* Already overriden prop, we'll have to check arrays items etc. */ + } + } + + if (array_a != array_stack_a) MEM_freeN(array_a); + if (array_b != array_stack_b) MEM_freeN(array_b); + + return comp; + } + else { + const int value_a = RNA_property_int_get(ptr_a, prop_a); + const int value_b = RNA_property_int_get(ptr_b, prop_b); + const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0; + + if (comp != 0 && rna_path) { + bool created = false; + IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); + + if (op != NULL && created) { /* If not yet overridden... */ + BKE_override_static_property_operation_get( + op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL); + if (r_override_changed) { + *r_override_changed = created; + } + } + } + + return comp; + } + } + + case PROP_FLOAT: + { + const bool is_proportional = (prop_a->flag & PROP_PROPORTIONAL) != 0; + if (len_a) { + float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY]; + float *array_a, *array_b; + + array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(float) * len_a, "RNA equals") : array_stack_a; + array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(float) * len_b, "RNA equals") : array_stack_b; + + RNA_property_float_get_array(ptr_a, prop_a, array_a); + RNA_property_float_get_array(ptr_b, prop_b, array_b); + + const int comp = memcmp(array_a, array_b, sizeof(float) * len_a); + + if (comp != 0 && rna_path) { + /* XXX TODO this will have to be refined to handle array items */ + bool created = false; + IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); + + if (op != NULL && created) { + BKE_override_static_property_operation_get( + op, is_proportional ? IDOVERRIDESTATIC_OP_MULTIPLY : IDOVERRIDESTATIC_OP_REPLACE, + NULL, NULL, -1, -1, true, NULL, NULL); + if (r_override_changed) { + *r_override_changed = created; + } + } + else { + /* Already overriden prop, we'll have to check arrays items etc. */ + } + } + + if (array_a != array_stack_a) MEM_freeN(array_a); + if (array_b != array_stack_b) MEM_freeN(array_b); + + return comp; + } + else { + const float value_a = RNA_property_float_get(ptr_a, prop_a); + const float value_b = RNA_property_float_get(ptr_b, prop_b); + const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0; + + if (comp != 0 && rna_path) { + bool created = false; + IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); + + if (op != NULL && created) { /* If not yet overridden... */ + BKE_override_static_property_operation_get( + op, is_proportional ? IDOVERRIDESTATIC_OP_MULTIPLY : IDOVERRIDESTATIC_OP_REPLACE, + NULL, NULL, -1, -1, true, NULL, NULL); + if (r_override_changed) { + *r_override_changed = created; + } + } + } + + return comp ; + } + } + + case PROP_ENUM: + { + const int value_a = RNA_property_enum_get(ptr_a, prop_a); + const int value_b = RNA_property_enum_get(ptr_b, prop_b); + const int comp = value_a != value_b; + + if (comp != 0 && rna_path) { + bool created = false; + IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); + + if (op != NULL && created) { /* If not yet overridden... */ + BKE_override_static_property_operation_get( + op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL); + if (r_override_changed) { + *r_override_changed = created; + } + } + } + + return comp; + } + + case PROP_STRING: + { + char fixed_a[128], fixed_b[128]; + int len_str_a, len_str_b; + char *value_a = RNA_property_string_get_alloc(ptr_a, prop_a, fixed_a, sizeof(fixed_a), &len_str_a); + char *value_b = RNA_property_string_get_alloc(ptr_b, prop_b, fixed_b, sizeof(fixed_b), &len_str_b); + const int comp = strcmp(value_a, value_b); + + if (comp != 0 && rna_path) { + bool created = false; + IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); + + if (op != NULL && created) { /* If not yet overridden... */ + BKE_override_static_property_operation_get( + op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL); + if (r_override_changed) { + *r_override_changed = created; + } + } + } + + if (value_a != fixed_a) MEM_freeN(value_a); + if (value_b != fixed_b) MEM_freeN(value_b); + + return comp; + } + + case PROP_POINTER: + { + if (STREQ(RNA_property_identifier(prop_a), "rna_type")) { + /* Dummy 'pass' answer, this is a meta-data and must be ignored... */ + return 0; + } + else { + PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, prop_a); + PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, prop_b); + return rna_property_override_equals_propptr( + &propptr_a, &propptr_b, mode, + override, rna_path, r_override_changed, flags); + } + break; + } + + case PROP_COLLECTION: + { + bool equals = true; + int idx = 0; + + CollectionPropertyIterator iter_a, iter_b; + RNA_property_collection_begin(ptr_a, prop_a, &iter_a); + RNA_property_collection_begin(ptr_b, prop_b, &iter_b); + + for (; iter_a.valid && iter_b.valid; + RNA_property_collection_next(&iter_a), RNA_property_collection_next(&iter_b), idx++) + { + char *extended_rna_path = NULL; + + if (iter_a.ptr.type != iter_b.ptr.type) { + /* nothing we can do (for until we support adding/removing from collections), skip it. */ + equals = false; + continue; + } + + PropertyRNA *propname = RNA_struct_name_property(iter_a.ptr.type); + char propname_buff_a[256], propname_buff_b[256]; + char *propname_a = NULL, *propname_b = NULL; + + if (propname != NULL) { + propname_a = RNA_property_string_get_alloc(&iter_a.ptr, propname, propname_buff_a, sizeof(propname_buff_a), NULL); + propname_b = RNA_property_string_get_alloc(&iter_b.ptr, propname, propname_buff_b, sizeof(propname_buff_b), NULL); + if (!STREQ(propname_a, propname_b)) { + /* Same as above, not same structs. */ + equals = false; + } + else if (rna_path) { + extended_rna_path = rna_path_collection_prop_item_extend(rna_path, propname_a); + } + } + else { /* Based on index... */ + if (rna_path) { + extended_rna_path = BLI_sprintfN("%s[%d]", rna_path, idx); + } + } + + if (equals) { + const int eq = rna_property_override_equals_propptr( + &iter_a.ptr, &iter_b.ptr, mode, + override, extended_rna_path, r_override_changed, flags); + equals = equals && eq; + } + + if (propname_a != propname_buff_a) { + MEM_freeN(propname_a); + } + if (propname_b != propname_buff_b) { + MEM_freeN(propname_b); + } + MEM_SAFE_FREE(extended_rna_path); + + if (!rna_path && !equals) { + break; /* Early out in case we do not want to loop over whole collection. */ + } + } + + equals = equals && !(iter_a.valid || iter_b.valid); /* Not same number of items in both collections... */ + RNA_property_collection_end(&iter_a); + RNA_property_collection_end(&iter_b); + + return (equals == false); + } + + default: + break; + } + + return 0; +} + +bool rna_property_override_store_default( + PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, + PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage, + const int len_local, const int len_reference, const int len_storage, + IDOverrideStaticPropertyOperation *opop) +{ + BLI_assert(len_local == len_reference && (!ptr_storage || len_local == len_storage)); + UNUSED_VARS_NDEBUG(len_reference, len_storage); + + bool changed = false; + const int index = opop->subitem_reference_index; + + if (!ELEM(opop->operation, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY)) { + return changed; + } + + /* XXX TODO About range limits. + * Ideally, it woudl be great to get rid of RNA range in that specific case. + * However, this won't be that easy and will add yet another layer of complexity in generated code, + * not to mention that we could most likely *not* bypass custom setters anyway. + * So for now, if needed second operand value is not in valid range, we simply fall back + * to a mere REPLACE operation. + * Time will say whether this is acceptable limitation or not. */ + switch (RNA_property_type(prop_local)) { + case PROP_BOOLEAN: + /* TODO support boolean ops? Really doubt this would ever be useful though... */ + BLI_assert(0 && "Boolean properties support no override diff operation"); + break; + case PROP_INT: + { + int prop_min, prop_max; + RNA_property_int_range(ptr_local, prop_local, &prop_min, &prop_max); + + if (len_local) { + if (index == -1) { + int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY]; + int *array_a, *array_b; + + array_a = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_local, __func__) : array_stack_a; + RNA_property_int_get_array(ptr_reference, prop_reference, array_a); + + switch (opop->operation) { + case IDOVERRIDESTATIC_OP_ADD: + case IDOVERRIDESTATIC_OP_SUBTRACT: + { + const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1; + const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD; + bool do_set = true; + array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b; + RNA_property_int_get_array(ptr_local, prop_local, array_b); + for (int i = len_local; i--;) { + array_b[i] = fac * (array_b[i] - array_a[i]); + if (array_b[i] < prop_min || array_b[i] > prop_max) { + opop->operation = other_op; + for (int j = len_local; j--;) { + array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]); + if (array_b[j] < prop_min || array_b[j] > prop_max) { + /* We failed to find a suitable diff op, + * fall back to plain REPLACE one. */ + opop->operation = IDOVERRIDESTATIC_OP_REPLACE; + do_set = false; + break; + } + } + break; + } + } + if (do_set) { + changed = true; + RNA_property_int_set_array(ptr_storage, prop_storage, array_b); + } + if (array_b != array_stack_b) MEM_freeN(array_b); + break; + } + default: + BLI_assert(0 && "Unsupported RNA override diff operation on integer"); + break; + } + + if (array_a != array_stack_a) MEM_freeN(array_a); + } + else { + const int value = RNA_property_int_get_index(ptr_reference, prop_reference, index); + + switch (opop->operation) { + case IDOVERRIDESTATIC_OP_ADD: + case IDOVERRIDESTATIC_OP_SUBTRACT: + { + const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1; + const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD; + int b = fac * (RNA_property_int_get_index(ptr_local, prop_local, index) - value); + if (b < prop_min || b > prop_max) { + opop->operation = other_op; + b = -b; + if (b < prop_min || b > prop_max) { + opop->operation = IDOVERRIDESTATIC_OP_REPLACE; + break; + } + } + changed = true; + RNA_property_int_set_index(ptr_storage, prop_storage, index, b); + break; + } + default: + BLI_assert(0 && "Unsupported RNA override diff operation on integer"); + break; + } + } + } + else { + const int value = RNA_property_int_get(ptr_reference, prop_reference); + + switch (opop->operation) { + case IDOVERRIDESTATIC_OP_ADD: + case IDOVERRIDESTATIC_OP_SUBTRACT: + { + const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1; + const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD; + int b = fac * (RNA_property_int_get(ptr_local, prop_local) - value); + if (b < prop_min || b > prop_max) { + opop->operation = other_op; + b = -b; + if (b < prop_min || b > prop_max) { + opop->operation = IDOVERRIDESTATIC_OP_REPLACE; + break; + } + } + changed = true; + RNA_property_int_set(ptr_storage, prop_storage, b); + break; + } + default: + BLI_assert(0 && "Unsupported RNA override diff operation on integer"); + break; + } + } + break; + } + case PROP_FLOAT: + { + float prop_min, prop_max; + RNA_property_float_range(ptr_local, prop_local, &prop_min, &prop_max); + + if (len_local) { + if (index == -1) { + float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY]; + float *array_a, *array_b; + + array_a = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_local, __func__) : array_stack_a; + + RNA_property_float_get_array(ptr_reference, prop_reference, array_a); + switch (opop->operation) { + case IDOVERRIDESTATIC_OP_ADD: + case IDOVERRIDESTATIC_OP_SUBTRACT: + { + const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0 : -1.0; + const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD; + bool do_set = true; + array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b; + RNA_property_float_get_array(ptr_local, prop_local, array_b); + for (int i = len_local; i--;) { + array_b[i] = fac * (array_b[i] - array_a[i]); + if (array_b[i] < prop_min || array_b[i] > prop_max) { + opop->operation = other_op; + for (int j = len_local; j--;) { + array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]); + if (array_b[j] < prop_min || array_b[j] > prop_max) { + /* We failed to find a suitable diff op, + * fall back to plain REPLACE one. */ + opop->operation = IDOVERRIDESTATIC_OP_REPLACE; + do_set = false; + break; + } + } + break; + } + } + if (do_set) { + changed = true; + RNA_property_float_set_array(ptr_storage, prop_storage, array_b); + } + if (array_b != array_stack_b) MEM_freeN(array_b); + break; + } + case IDOVERRIDESTATIC_OP_MULTIPLY: + { + bool do_set = true; + array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b; + RNA_property_float_get_array(ptr_local, prop_local, array_b); + for (int i = len_local; i--;) { + array_b[i] = array_a[i] == 0.0f ? array_b[i] : array_b[i] / array_a[i]; + if (array_b[i] < prop_min || array_b[i] > prop_max) { + opop->operation = IDOVERRIDESTATIC_OP_REPLACE; + do_set = false; + break; + } + } + if (do_set) { + changed = true; + RNA_property_float_set_array(ptr_storage, prop_storage, array_b); + } + if (array_b != array_stack_b) MEM_freeN(array_b); + break; + } + default: + BLI_assert(0 && "Unsupported RNA override diff operation on float"); + break; + } + + if (array_a != array_stack_a) MEM_freeN(array_a); + } + else { + const float value = RNA_property_float_get_index(ptr_reference, prop_reference, index); + + switch (opop->operation) { + case IDOVERRIDESTATIC_OP_ADD: + case IDOVERRIDESTATIC_OP_SUBTRACT: + { + const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0f : -1.0f; + const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD; + float b = fac * (RNA_property_float_get_index(ptr_local, prop_local, index) - value); + if (b < prop_min || b > prop_max) { + opop->operation = other_op; + b = -b; + if (b < prop_min || b > prop_max) { + opop->operation = IDOVERRIDESTATIC_OP_REPLACE; + break; + } + } + changed = true; + RNA_property_float_set_index(ptr_storage, prop_storage, index, b); + break; + } + case IDOVERRIDESTATIC_OP_MULTIPLY: + { + const float b = RNA_property_float_get_index(ptr_local, prop_local, index) / (value == 0.0f ? 1.0f : value); + if (b < prop_min || b > prop_max) { + opop->operation = IDOVERRIDESTATIC_OP_REPLACE; + break; + } + changed = true; + RNA_property_float_set_index(ptr_storage, prop_storage, index, b); + break; + } + default: + BLI_assert(0 && "Unsupported RNA override diff operation on float"); + break; + } + } + } + else { + const float value = RNA_property_float_get(ptr_reference, prop_reference); + + switch (opop->operation) { + case IDOVERRIDESTATIC_OP_ADD: + case IDOVERRIDESTATIC_OP_SUBTRACT: + { + const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0f : -1.0f; + const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD; + float b = fac * (RNA_property_float_get(ptr_local, prop_local) - value); + if (b < prop_min || b > prop_max) { + opop->operation = other_op; + b = -b; + if (b < prop_min || b > prop_max) { + opop->operation = IDOVERRIDESTATIC_OP_REPLACE; + break; + } + } + changed = true; + RNA_property_float_set(ptr_storage, prop_storage, b); + break; + } + case IDOVERRIDESTATIC_OP_MULTIPLY: + { + const float b = RNA_property_float_get(ptr_local, prop_local) / (value == 0.0f ? 1.0f : value); + if (b < prop_min || b > prop_max) { + opop->operation = IDOVERRIDESTATIC_OP_REPLACE; + break; + } + changed = true; + RNA_property_float_set(ptr_storage, prop_storage, b); + break; + } + default: + BLI_assert(0 && "Unsupported RNA override diff operation on float"); + break; + } + } + return true; + } + case PROP_ENUM: + /* TODO support add/sub, for bitflags? */ + BLI_assert(0 && "Enum properties support no override diff operation"); + break; + case PROP_POINTER: + BLI_assert(0 && "Pointer properties support no override diff operation"); + break; + case PROP_STRING: + BLI_assert(0 && "String properties support no override diff operation"); + break; + case PROP_COLLECTION: + /* XXX TODO support this of course... */ + BLI_assert(0 && "Collection properties support no override diff operation"); + break; + default: + break; + } + + return changed; +} + +bool rna_property_override_apply_default( + PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_storage, + PropertyRNA *prop_dst, PropertyRNA *prop_src, PropertyRNA *prop_storage, + const int len_dst, const int len_src, const int len_storage, + IDOverrideStaticPropertyOperation *opop) +{ + BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage)); + UNUSED_VARS_NDEBUG(len_src, len_storage); + + const int index = opop->subitem_reference_index; + const short override_op = opop->operation; + + switch (RNA_property_type(prop_dst)) { + case PROP_BOOLEAN: + if (len_dst) { + if (index == -1) { + int array_stack_a[RNA_STACK_ARRAY]; + int *array_a; + + array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a; + + RNA_property_boolean_get_array(ptr_src, prop_src, array_a); + + switch (override_op) { + case IDOVERRIDESTATIC_OP_REPLACE: + RNA_property_boolean_set_array(ptr_dst, prop_dst, array_a); + break; + default: + BLI_assert(0 && "Unsupported RNA override operation on boolean"); + return false; + } + + if (array_a != array_stack_a) MEM_freeN(array_a); + } + else { + const int value = RNA_property_boolean_get_index(ptr_src, prop_src, index); + + switch (override_op) { + case IDOVERRIDESTATIC_OP_REPLACE: + RNA_property_boolean_set_index(ptr_dst, prop_dst, index, value); + break; + default: + BLI_assert(0 && "Unsupported RNA override operation on boolean"); + return false; + } + } + } + else { + const int value = RNA_property_boolean_get(ptr_src, prop_src); + + switch (override_op) { + case IDOVERRIDESTATIC_OP_REPLACE: + RNA_property_boolean_set(ptr_dst, prop_dst, value); + break; + default: + BLI_assert(0 && "Unsupported RNA override operation on boolean"); + return false; + } + } + return true; + case PROP_INT: + if (len_dst) { + if (index == -1) { + int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY]; + int *array_a, *array_b; + + array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a; + + switch (override_op) { + case IDOVERRIDESTATIC_OP_REPLACE: + RNA_property_int_get_array(ptr_src, prop_src, array_a); + RNA_property_int_set_array(ptr_dst, prop_dst, array_a); + break; + case IDOVERRIDESTATIC_OP_ADD: + case IDOVERRIDESTATIC_OP_SUBTRACT: + RNA_property_int_get_array(ptr_dst, prop_dst, array_a); + array_b = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_dst, __func__) : array_stack_b; + RNA_property_int_get_array(ptr_storage, prop_storage, array_b); + if (override_op == IDOVERRIDESTATIC_OP_ADD) { + for (int i = len_dst; i--;) array_a[i] += array_b[i]; + } + else { + for (int i = len_dst; i--;) array_a[i] -= array_b[i]; + } + RNA_property_int_set_array(ptr_dst, prop_dst, array_a); + if (array_b != array_stack_b) MEM_freeN(array_b); + break; + default: + BLI_assert(0 && "Unsupported RNA override operation on integer"); + return false; + } + + if (array_a != array_stack_a) MEM_freeN(array_a); + } + else { + const int storage_value = ptr_storage ? RNA_property_int_get_index(ptr_storage, prop_storage, index) : 0; + + switch (override_op) { + case IDOVERRIDESTATIC_OP_REPLACE: + RNA_property_int_set_index(ptr_dst, prop_dst, index, + RNA_property_int_get_index(ptr_src, prop_src, index)); + break; + case IDOVERRIDESTATIC_OP_ADD: + RNA_property_int_set_index(ptr_dst, prop_dst, index, + RNA_property_int_get_index(ptr_dst, prop_dst, index) - storage_value); + break; + case IDOVERRIDESTATIC_OP_SUBTRACT: + RNA_property_int_set_index(ptr_dst, prop_dst, index, + RNA_property_int_get_index(ptr_dst, prop_dst, index) - storage_value); + break; + default: + BLI_assert(0 && "Unsupported RNA override operation on integer"); + return false; + } + } + } + else { + const int storage_value = ptr_storage ? RNA_property_int_get(ptr_storage, prop_storage) : 0; + + switch (override_op) { + case IDOVERRIDESTATIC_OP_REPLACE: + RNA_property_int_set(ptr_dst, prop_dst, RNA_property_int_get(ptr_src, prop_src)); + break; + case IDOVERRIDESTATIC_OP_ADD: + RNA_property_int_set(ptr_dst, prop_dst, RNA_property_int_get(ptr_dst, prop_dst) + storage_value); + break; + case IDOVERRIDESTATIC_OP_SUBTRACT: + RNA_property_int_set(ptr_dst, prop_dst, RNA_property_int_get(ptr_dst, prop_dst) - storage_value); + break; + default: + BLI_assert(0 && "Unsupported RNA override operation on integer"); + return false; + } + } + return true; + case PROP_FLOAT: + if (len_dst) { + if (index == -1) { + float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY]; + float *array_a, *array_b; + + array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a; + + switch (override_op) { + case IDOVERRIDESTATIC_OP_REPLACE: + RNA_property_float_get_array(ptr_src, prop_src, array_a); + RNA_property_float_set_array(ptr_dst, prop_dst, array_a); + break; + case IDOVERRIDESTATIC_OP_ADD: + case IDOVERRIDESTATIC_OP_SUBTRACT: + case IDOVERRIDESTATIC_OP_MULTIPLY: + RNA_property_float_get_array(ptr_dst, prop_dst, array_a); + array_b = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_dst, __func__) : array_stack_b; + RNA_property_float_get_array(ptr_storage, prop_storage, array_b); + if (override_op == IDOVERRIDESTATIC_OP_ADD) { + for (int i = len_dst; i--;) array_a[i] += array_b[i]; + } + else if (override_op == IDOVERRIDESTATIC_OP_SUBTRACT) { + for (int i = len_dst; i--;) array_a[i] -= array_b[i]; + } + else { + for (int i = len_dst; i--;) array_a[i] *= array_b[i]; + } + RNA_property_float_set_array(ptr_dst, prop_dst, array_a); + if (array_b != array_stack_b) MEM_freeN(array_b); + break; + default: + BLI_assert(0 && "Unsupported RNA override operation on float"); + return false; + } + + if (array_a != array_stack_a) MEM_freeN(array_a); + } + else { + const float storage_value = ptr_storage ? RNA_property_float_get_index(ptr_storage, prop_storage, index) : 0.0f; + + switch (override_op) { + case IDOVERRIDESTATIC_OP_REPLACE: + RNA_property_float_set_index(ptr_dst, prop_dst, index, + RNA_property_float_get_index(ptr_src, prop_src, index)); + break; + case IDOVERRIDESTATIC_OP_ADD: + RNA_property_float_set_index(ptr_dst, prop_dst, index, + RNA_property_float_get_index(ptr_dst, prop_dst, index) + storage_value); + break; + case IDOVERRIDESTATIC_OP_SUBTRACT: + RNA_property_float_set_index(ptr_dst, prop_dst, index, + RNA_property_float_get_index(ptr_dst, prop_dst, index) - storage_value); + break; + case IDOVERRIDESTATIC_OP_MULTIPLY: + RNA_property_float_set_index(ptr_dst, prop_dst, index, + RNA_property_float_get_index(ptr_dst, prop_dst, index) * storage_value); + break; + default: + BLI_assert(0 && "Unsupported RNA override operation on float"); + return false; + } + } + } + else { + const float storage_value = ptr_storage ? RNA_property_float_get(ptr_storage, prop_storage) : 0.0f; + + switch (override_op) { + case IDOVERRIDESTATIC_OP_REPLACE: + RNA_property_float_set(ptr_dst, prop_dst, RNA_property_float_get(ptr_src, prop_src)); + break; + case IDOVERRIDESTATIC_OP_ADD: + RNA_property_float_set(ptr_dst, prop_dst, RNA_property_float_get(ptr_dst, prop_dst) + storage_value); + break; + case IDOVERRIDESTATIC_OP_SUBTRACT: + RNA_property_float_set(ptr_dst, prop_dst, RNA_property_float_get(ptr_dst, prop_dst) - storage_value); + break; + case IDOVERRIDESTATIC_OP_MULTIPLY: + RNA_property_float_set(ptr_dst, prop_dst, RNA_property_float_get(ptr_dst, prop_dst) * storage_value); + break; + default: + BLI_assert(0 && "Unsupported RNA override operation on float"); + return false; + } + } + return true; + case PROP_ENUM: + { + const int value = RNA_property_enum_get(ptr_src, prop_src); + + switch (override_op) { + case IDOVERRIDESTATIC_OP_REPLACE: + RNA_property_enum_set(ptr_dst, prop_dst, value); + break; + /* TODO support add/sub, for bitflags? */ + default: + BLI_assert(0 && "Unsupported RNA override operation on enum"); + return false; + } + return true; + } + case PROP_POINTER: + { + PointerRNA value = RNA_property_pointer_get(ptr_src, prop_src); + + switch (override_op) { + case IDOVERRIDESTATIC_OP_REPLACE: + RNA_property_pointer_set(ptr_dst, prop_dst, value); + break; + default: + BLI_assert(0 && "Unsupported RNA override operation on pointer"); + return false; + } + return true; + } + case PROP_STRING: + { + char buff[256]; + char *value = RNA_property_string_get_alloc(ptr_src, prop_src, buff, sizeof(buff), NULL); + + switch (override_op) { + case IDOVERRIDESTATIC_OP_REPLACE: + RNA_property_string_set(ptr_dst, prop_dst, value); + break; + default: + BLI_assert(0 && "Unsupported RNA override operation on string"); + return false; + } + + if (value != buff) MEM_freeN(value); + return true; + } + default: + /* TODO PROP_COLLECTION of course! */ + return false; + } + + return false; +} + + #else @@ -1259,6 +2265,11 @@ static void rna_def_property(BlenderRNA *brna) RNA_def_property_boolean_funcs(prop, "rna_Property_animatable_get", NULL); RNA_def_property_ui_text(prop, "Animatable", "Property is animatable through RNA"); + prop = RNA_def_property(srna, "is_overridable", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_funcs(prop, "rna_Property_overridable_get", NULL); + RNA_def_property_ui_text(prop, "Overridable", "Property is overridable through RNA"); + prop = RNA_def_property(srna, "is_required", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_boolean_funcs(prop, "rna_Property_is_required_get", NULL); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 5600935c567..785f805a33e 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1496,7 +1496,7 @@ static void rna_Scene_editmesh_select_mode_set(PointerRNA *ptr, const int *value } } -static void rna_Scene_editmesh_select_mode_update(Main *UNUSED(bmain), bContext *C, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +static void rna_Scene_editmesh_select_mode_update(bContext *C, PointerRNA *UNUSED(ptr)) { ViewLayer *view_layer = CTX_data_view_layer(C); Mesh *me = NULL; @@ -1746,7 +1746,7 @@ static char *rna_CurvePaintSettings_path(PointerRNA *UNUSED(ptr)) } /* generic function to recalc geometry */ -static void rna_EditMesh_update(Main *UNUSED(bmain), bContext *C, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +static void rna_EditMesh_update(bContext *C, PointerRNA *UNUSED(ptr)) { ViewLayer *view_layer = CTX_data_view_layer(C); Mesh *me = NULL; diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index b245d12bbd5..7d8bf4949d5 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -176,19 +176,19 @@ static void rna_Scene_ray_cast( int *r_success, float r_location[3], float r_normal[3], int *r_index, Object **r_ob, float r_obmat[16]) { - RenderEngineType *engine; + RenderEngineType *engine_type; if (engine_id == NULL || engine_id[0] == '\0') { - engine = RE_engines_find(scene->view_render.engine_id); + engine_type = RE_engines_find(scene->view_render.engine_id); } else { - engine = RE_engines_find(engine_id); + engine_type = RE_engines_find(engine_id); } normalize_v3(direction); SnapObjectContext *sctx = ED_transform_snap_object_context_create( - G.main, scene, view_layer, engine, 0); + G.main, scene, view_layer, engine_type, 0); bool ret = ED_transform_snap_object_project_ray_ex( sctx, diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index a2edb072102..ddcf525c3c8 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -166,7 +166,7 @@ static void rna_ParticleEdit_redo(bContext *C, PointerRNA *UNUSED(ptr)) psys_free_path_cache(edit->psys, edit); } -static void rna_ParticleEdit_update(Main *UNUSED(bmain), Scene *UNUSED(scene), bContext *C, PointerRNA *UNUSED(ptr)) +static void rna_ParticleEdit_update(bContext *C, PointerRNA *UNUSED(ptr)) { ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = OBACT(view_layer); @@ -280,12 +280,13 @@ static void rna_Sculpt_update(bContext *C, PointerRNA *UNUSED(ptr)) } } -static void rna_Sculpt_ShowDiffuseColor_update(bContext *C, Scene *scene, PointerRNA *UNUSED(ptr)) +static void rna_Sculpt_ShowDiffuseColor_update(bContext *C, PointerRNA *UNUSED(ptr)) { ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = OBACT(view_layer); if (ob && ob->sculpt) { + Scene *scene = CTX_data_scene(C); Sculpt *sd = scene->toolsettings->sculpt; ob->sculpt->show_diffuse_color = ((sd->flags & SCULPT_SHOW_DIFFUSE) != 0); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index fbc29039539..61ac81a6d1c 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -550,6 +550,8 @@ static StructRNA *rna_Sequence_refine(struct PointerRNA *ptr) return &RNA_GaussianBlurSequence; case SEQ_TYPE_TEXT: return &RNA_TextSequence; + case SEQ_TYPE_COLORMIX: + return &RNA_ColorMixSequence; default: return &RNA_Sequence; } @@ -1338,6 +1340,24 @@ static const EnumPropertyItem blend_mode_items[] = { {SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", ""}, {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""}, {SEQ_TYPE_OVERDROP, "OVER_DROP", 0, "Over Drop", ""}, + {SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""}, + {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""}, + {SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""}, + {SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""}, + {SEQ_TYPE_DODGE, "DODGE", 0, "Dodge", ""}, + {SEQ_TYPE_BURN, "BURN", 0, "Burn", ""}, + {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""}, + {SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""}, + {SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""}, + {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""}, + {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""}, + {SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""}, + {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""}, + {SEQ_TYPE_HUE, "HUE", 0, "Hue", ""}, + {SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""}, + {SEQ_TYPE_VALUE, "VALUE", 0, "Value", ""}, + {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, + {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1411,6 +1431,7 @@ static void rna_def_sequence(BlenderRNA *brna) {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""}, {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""}, {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""}, + {SEQ_TYPE_COLORMIX, "COLORMIX", 0, "Color Mix", ""}, {0, NULL, 0, NULL, NULL} }; @@ -2378,6 +2399,49 @@ static void rna_def_text(StructRNA *srna) RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); } +static void rna_def_color_mix(StructRNA *srna) +{ + static EnumPropertyItem blend_color_items[] = { + {SEQ_TYPE_ADD, "ADD", 0, "Add", ""}, + {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""}, + {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""}, + {SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""}, + {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""}, + {SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""}, + {SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""}, + {SEQ_TYPE_DODGE, "DODGE", 0, "Dodge", ""}, + {SEQ_TYPE_BURN, "BURN", 0, "Burn", ""}, + {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""}, + {SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""}, + {SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""}, + {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""}, + {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""}, + {SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""}, + {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""}, + {SEQ_TYPE_HUE, "HUE", 0, "Hue", ""}, + {SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""}, + {SEQ_TYPE_VALUE, "VALUE", 0, "Value", ""}, + {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, + {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""}, + {0, NULL, 0, NULL, NULL} + }; + + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "ColorMixVars", "effectdata"); + + prop = RNA_def_property(srna, "blend_effect", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "blend_effect"); + RNA_def_property_enum_items(prop, blend_color_items); + RNA_def_property_ui_text(prop, "Blend Effect", "Method for controlling how the strip combines with other strips"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); + + prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Blend Factor", "Percentage of how much the strip's colors affect other strips"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); +} + static EffectInfo def_effects[] = { {"AddSequence", "Add Sequence", "Add Sequence", NULL, 2}, {"AdjustmentSequence", "Adjustment Layer Sequence", @@ -2404,6 +2468,7 @@ static EffectInfo def_effects[] = { rna_def_gaussian_blur, 1}, {"TextSequence", "Text Sequence", "Sequence strip creating text", rna_def_text, 0}, + {"ColorMixSequence", "Color Mix Sequence", "Color Mix Sequence", rna_def_color_mix, 2}, {"", "", "", NULL, 0} }; diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index e1d3f3958a5..d447d2972f6 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -475,6 +475,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""}, {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""}, {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""}, + {SEQ_TYPE_COLORMIX, "COLORMIX", 0, "Color Mix", ""}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index a38136eed53..82283019fc8 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -227,6 +227,11 @@ static const EnumPropertyItem buttons_texture_context_items[] = { {0, NULL, 0, NULL, NULL} }; +static const EnumPropertyItem buttons_collection_context_items[] = { + {SB_COLLECTION_CTX_VIEW_LAYER, "VIEW_LAYER", ICON_RENDERLAYERS, "", "Show material textures"}, + {SB_COLLECTION_CTX_GROUP, "GROUP", ICON_GROUP, "", "Show world textures"}, + {0, NULL, 0, NULL, NULL} +}; static const EnumPropertyItem fileselectparams_recursion_level_items[] = { {0, "NONE", 0, "None", "Only list current directory's content, with no recursion"}, @@ -2745,6 +2750,11 @@ static void rna_def_space_buttons(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Limited Texture Context", "Use the limited version of texture user (for 'old shading' mode)"); + prop = RNA_def_property(srna, "collection_context", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, buttons_collection_context_items); + RNA_def_property_ui_text(prop, "Collection Context", "Which collection we want to show"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, NULL); + /* pinned data */ prop = RNA_def_property(srna, "pin_id", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "pinid"); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index ad3ed6f55ac..51bdc0ea9ff 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -60,8 +60,8 @@ const EnumPropertyItem rna_enum_icon_items[] = { #ifdef RNA_RUNTIME -const char *rna_translate_ui_text(const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop, - int translate) +const char *rna_translate_ui_text( + const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop, int translate) { /* Also return text if UI labels translation is disabled. */ if (!text || !text[0] || !translate || !BLT_translate_iface()) { diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index cbbe0df1d60..1cdd43eeffc 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -827,6 +827,16 @@ static void rna_def_userdef_theme_ui_wcol_state(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Driven Selected", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "inner_overridden", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Overridden", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "inner_overridden_sel", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Overridden Selected", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "blend", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Blend", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 7d821ee407b..36f07db727b 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -36,6 +36,8 @@ #include "BLT_translation.h" +#include "BKE_workspace.h" + #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -467,6 +469,7 @@ const EnumPropertyItem rna_enum_wm_report_items[] = { #include "WM_api.h" +#include "DNA_object_types.h" #include "DNA_workspace_types.h" #include "ED_screen.h" @@ -475,7 +478,6 @@ const EnumPropertyItem rna_enum_wm_report_items[] = { #include "BKE_global.h" #include "BKE_idprop.h" -#include "BKE_workspace.h" #include "MEM_guardedalloc.h" @@ -755,6 +757,49 @@ static void rna_workspace_screen_update(bContext *C, PointerRNA *ptr) } } +static PointerRNA rna_Window_view_layer_get(PointerRNA *ptr) +{ + wmWindow *win = ptr->data; + Scene *scene = WM_window_get_active_scene(win); + WorkSpace *workspace = WM_window_get_active_workspace(win); + ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene); + PointerRNA scene_ptr; + + RNA_id_pointer_create(&scene->id, &scene_ptr); + return rna_pointer_inherit_refine(&scene_ptr, &RNA_ViewLayer, view_layer); +} + +static void rna_Window_view_layer_set(PointerRNA *ptr, PointerRNA value) +{ + wmWindow *win = ptr->data; + Scene *scene = WM_window_get_active_scene(win); + WorkSpace *workspace = WM_window_get_active_workspace(win); + + BKE_workspace_view_layer_set(workspace, value.data, scene); +} + +#ifdef USE_WORKSPACE_MODE + +static int rna_Window_object_mode_get(PointerRNA *ptr) +{ + wmWindow *win = ptr->data; + Scene *scene = WM_window_get_active_scene(win); + WorkSpace *workspace = WM_window_get_active_workspace(win); + + return (int)BKE_workspace_object_mode_get(workspace, scene); +} + +static void rna_Window_object_mode_set(PointerRNA *ptr, int value) +{ + wmWindow *win = ptr->data; + Scene *scene = WM_window_get_active_scene(win); + WorkSpace *workspace = WM_window_get_active_workspace(win); + + BKE_workspace_object_mode_set(workspace, scene, value); +} + +#endif /* USE_WORKSPACE_MODE */ + static PointerRNA rna_KeyMapItem_properties_get(PointerRNA *ptr) { wmKeyMapItem *kmi = ptr->data; @@ -2024,6 +2069,20 @@ static void rna_def_window(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_NEVER_NULL | PROP_EDITABLE | PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, 0, "rna_workspace_screen_update"); + prop = RNA_def_property(srna, "view_layer", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "ViewLayer"); + RNA_def_property_pointer_funcs(prop, "rna_Window_view_layer_get", "rna_Window_view_layer_set", NULL, NULL); + RNA_def_property_ui_text(prop, "Active View Layer", "The active workspace view layer showing in the window"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL); + RNA_def_property_update(prop, NC_SCREEN | ND_LAYER, NULL); + +#ifdef USE_WORKSPACE_MODE + prop = RNA_def_property(srna, "object_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_object_mode_items); + RNA_def_property_enum_funcs(prop, "rna_Window_object_mode_get", "rna_Window_object_mode_set", NULL); + RNA_def_property_ui_text(prop, "Mode", "Object interaction mode used in this window"); +#endif + prop = RNA_def_property(srna, "x", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "posx"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c index 7e7b2eeccd7..0bed91f2807 100644 --- a/source/blender/makesrna/intern/rna_workspace.c +++ b/source/blender/makesrna/intern/rna_workspace.c @@ -67,22 +67,6 @@ static PointerRNA rna_workspace_screens_item_get(CollectionPropertyIterator *ite return rna_pointer_inherit_refine(&iter->parent, &RNA_Screen, screen); } -#ifdef USE_WORKSPACE_MODE - -static int rna_workspace_object_mode_get(PointerRNA *ptr) -{ - WorkSpace *workspace = ptr->data; - return (int)BKE_workspace_object_mode_get(workspace); -} - -static void rna_workspace_object_mode_set(PointerRNA *ptr, int value) -{ - WorkSpace *workspace = ptr->data; - BKE_workspace_object_mode_set(workspace, value); -} - -#endif /* USE_WORKSPACE_MODE */ - void rna_workspace_transform_orientations_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { WorkSpace *workspace = ptr->id.data; @@ -95,30 +79,6 @@ static PointerRNA rna_workspace_transform_orientations_item_get(CollectionProper return rna_pointer_inherit_refine(&iter->parent, &RNA_TransformOrientation, transform_orientation); } -static PointerRNA rna_workspace_view_layer_get(PointerRNA *ptr) -{ - WorkSpace *workspace = ptr->data; - ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace); - - /* XXX hmrf... lookup in getter... but how could we avoid it? */ - for (Scene *scene = G.main->scene.first; scene; scene = scene->id.next) { - if (BLI_findindex(&scene->view_layers, view_layer) != -1) { - PointerRNA scene_ptr; - - RNA_id_pointer_create(&scene->id, &scene_ptr); - return rna_pointer_inherit_refine(&scene_ptr, &RNA_ViewLayer, view_layer); - } - } - - return PointerRNA_NULL; -} - -static void rna_workspace_view_layer_set(PointerRNA *ptr, PointerRNA value) -{ - WorkSpace *workspace = ptr->data; - BKE_workspace_view_layer_set(workspace, value.data); -} - #else /* RNA_RUNTIME */ static void rna_def_workspace(BlenderRNA *brna) @@ -139,13 +99,6 @@ static void rna_def_workspace(BlenderRNA *brna) "rna_workspace_screens_item_get", NULL, NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Screens", "Screen layouts of a workspace"); -#ifdef USE_WORKSPACE_MODE - prop = RNA_def_property(srna, "object_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, rna_enum_object_mode_items); - RNA_def_property_enum_funcs(prop, "rna_workspace_object_mode_get", "rna_workspace_object_mode_set", NULL); - RNA_def_property_ui_text(prop, "Mode", "Object interaction mode"); -#endif - prop = RNA_def_property(srna, "tool_keymap", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "tool.keymap"); RNA_def_property_ui_text(prop, "Active Tool", "Currently active tool keymap"); @@ -168,14 +121,6 @@ static void rna_def_workspace(BlenderRNA *brna) "rna_workspace_transform_orientations_item_get", NULL, NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Transform Orientations", ""); - prop = RNA_def_property(srna, "view_layer", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "ViewLayer"); - RNA_def_property_pointer_funcs(prop, "rna_workspace_view_layer_get", "rna_workspace_view_layer_set", - NULL, NULL); - RNA_def_property_ui_text(prop, "Active View Layer", "The active view layer used in this workspace"); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL); - RNA_def_property_update(prop, NC_SCREEN | ND_LAYER, NULL); - /* View Render */ prop = RNA_def_property(srna, "view_render", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); diff --git a/source/blender/python/gawain/gwn_py_types.c b/source/blender/python/gawain/gwn_py_types.c index cc448d9ed90..5b602e85a12 100644 --- a/source/blender/python/gawain/gwn_py_types.c +++ b/source/blender/python/gawain/gwn_py_types.c @@ -671,6 +671,26 @@ static PyObject *bpygwn_VertBatch_draw(BPyGwn_Batch *self) Py_RETURN_NONE; } +static PyObject *bpygwn_VertBatch_program_use_begin(BPyGwn_Batch *self) +{ + if (!glIsProgram(self->batch->program)) { + PyErr_SetString(PyExc_ValueError, + "batch program has not not set"); + } + GWN_batch_program_use_begin(self->batch); + Py_RETURN_NONE; +} + +static PyObject *bpygwn_VertBatch_program_use_end(BPyGwn_Batch *self) +{ + if (!glIsProgram(self->batch->program)) { + PyErr_SetString(PyExc_ValueError, + "batch program has not not set"); + } + GWN_batch_program_use_end(self->batch); + Py_RETURN_NONE; +} + static struct PyMethodDef bpygwn_VertBatch_methods[] = { {"vertbuf_add", (PyCFunction)bpygwn_VertBatch_vertbuf_add, METH_O, bpygwn_VertBatch_vertbuf_add_doc}, @@ -684,6 +704,10 @@ static struct PyMethodDef bpygwn_VertBatch_methods[] = { METH_VARARGS, NULL}, {"draw", (PyCFunction) bpygwn_VertBatch_draw, METH_NOARGS, bpygwn_VertBatch_draw_doc}, + {"program_use_begin", (PyCFunction)bpygwn_VertBatch_program_use_begin, + METH_NOARGS, ""}, + {"program_use_end", (PyCFunction)bpygwn_VertBatch_program_use_end, + METH_NOARGS, ""}, {NULL, NULL, 0, NULL} }; diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index d49f9514b8c..36609c6f29b 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -412,6 +412,25 @@ PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *for return NULL; } +/** + * Use for Python callbacks run directly from C, + * when we can't use normal methods of raising exceptions. + */ +void PyC_Err_PrintWithFunc(PyObject *py_func) +{ + /* since we return to C code we can't leave the error */ + PyCodeObject *f_code = (PyCodeObject *)PyFunction_GET_CODE(py_func); + PyErr_Print(); + PyErr_Clear(); + + /* use py style error */ + fprintf(stderr, "File \"%s\", line %d, in %s\n", + _PyUnicode_AsString(f_code->co_filename), + f_code->co_firstlineno, + _PyUnicode_AsString(((PyFunctionObject *)py_func)->func_name) + ); +} + /* returns the exception string as a new PyUnicode object, depends on external traceback module */ #if 0 diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index 327d4e60954..25c88799027 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -38,6 +38,8 @@ PyObject * PyC_ExceptionBuffer_Simple(void); PyObject * PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...); PyObject * PyC_FrozenSetFromStrings(const char **strings); PyObject * PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...); +void PyC_Err_PrintWithFunc(PyObject *py_func); + void PyC_FileAndNum(const char **filename, int *lineno); void PyC_FileAndNum_Safe(const char **filename, int *lineno); /* checks python is running */ int PyC_AsArray_FAST( diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index 26fbc5d9eb2..41018468695 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -45,10 +45,6 @@ set(INC_SYS ) set(SRC - gpu.c - gpu_offscreen.c - gpu_py_matrix.c - gpu_py_select.c bpy.c bpy_app.c bpy_app_alembic.c @@ -61,6 +57,7 @@ set(SRC bpy_app_openvdb.c bpy_app_sdl.c bpy_app_translations.c + bpy_capi_utils.c bpy_driver.c bpy_interface.c bpy_interface_atexit.c @@ -68,6 +65,7 @@ set(SRC bpy_library_load.c bpy_library_write.c bpy_manipulator_wrap.c + bpy_msgbus.c bpy_operator.c bpy_operator_wrap.c bpy_path.c @@ -80,12 +78,14 @@ set(SRC bpy_rna_id_collection.c bpy_rna_manipulator.c bpy_traceback.c - bpy_util.c bpy_utils_previews.c bpy_utils_units.c + gpu.c + gpu_offscreen.c + gpu_py_matrix.c + gpu_py_select.c stubs.c - gpu.h bpy.h bpy_app.h bpy_app_alembic.h @@ -98,10 +98,12 @@ set(SRC bpy_app_openvdb.h bpy_app_sdl.h bpy_app_translations.h + bpy_capi_utils.h bpy_driver.h bpy_intern_string.h bpy_library.h bpy_manipulator_wrap.h + bpy_msgbus.h bpy_operator.h bpy_operator_wrap.h bpy_path.h @@ -113,9 +115,9 @@ set(SRC bpy_rna_id_collection.h bpy_rna_manipulator.h bpy_traceback.h - bpy_util.h bpy_utils_previews.h bpy_utils_units.h + gpu.h ../BPY_extern.h ) diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index c576786a54c..0b791b6acaa 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -42,7 +42,7 @@ #include "RNA_access.h" #include "bpy.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "bpy_rna.h" #include "bpy_app.h" #include "bpy_rna_id_collection.h" @@ -58,6 +58,7 @@ /* external util modules */ #include "../generic/idprop_py_api.h" +#include "bpy_msgbus.h" #ifdef WITH_FREESTYLE # include "BPy_Freestyle.h" @@ -350,6 +351,7 @@ void BPy_init_modules(void) PyModule_AddObject(mod, "app", BPY_app_struct()); PyModule_AddObject(mod, "_utils_units", BPY_utils_units()); PyModule_AddObject(mod, "_utils_previews", BPY_utils_previews_module()); + PyModule_AddObject(mod, "msgbus", BPY_msgbus_module()); /* bpy context */ RNA_pointer_create(NULL, &RNA_Context, (void *)BPy_GetContext(), &ctx_ptr); diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_capi_utils.c index c15ff50df04..7232e4ea821 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_capi_utils.c @@ -20,11 +20,11 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/python/intern/bpy_util.c +/** \file blender/python/intern/bpy_capi_utils.c * \ingroup pythonintern * - * This file contains blender/python utility functions for the api's internal - * use (unrelated to 'bpy.utils') + * This file contains Blender/Python utility functions to help implementing API's. + * This is not related to a particular module. */ #include <Python.h> @@ -32,7 +32,7 @@ #include "BLI_utildefines.h" #include "BLI_dynstr.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_capi_utils.h index 466941359a8..abb37d6e30c 100644 --- a/source/blender/python/intern/bpy_util.h +++ b/source/blender/python/intern/bpy_capi_utils.h @@ -20,12 +20,12 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/python/intern/bpy_util.h +/** \file blender/python/intern/bpy_capi_utils.h * \ingroup pythonintern */ -#ifndef __BPY_UTIL_H__ -#define __BPY_UTIL_H__ +#ifndef __BPY_CAPI_UTILS_H__ +#define __BPY_CAPI_UTILS_H__ #if PY_VERSION_HEX < 0x03060000 # error "Python 3.6 or greater is required, you'll need to update your python." @@ -50,4 +50,4 @@ void BPy_SetContext(struct bContext *C); extern void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate); extern void bpy_context_clear(struct bContext *C, PyGILState_STATE *gilstate); -#endif /* __BPY_UTIL_H__ */ +#endif /* __BPY_CAPI_UTILS_H__ */ diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 7ddb41c3b0d..11a233461d8 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -47,7 +47,7 @@ #include "gpu.h" #include "bpy_rna.h" #include "bpy_path.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "bpy_traceback.h" #include "bpy_intern_string.h" diff --git a/source/blender/python/intern/bpy_interface_atexit.c b/source/blender/python/intern/bpy_interface_atexit.c index 5c4f6ba327c..3608a26d113 100644 --- a/source/blender/python/intern/bpy_interface_atexit.c +++ b/source/blender/python/intern/bpy_interface_atexit.c @@ -33,7 +33,7 @@ #include "BLI_utildefines.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "bpy.h" /* own include */ #include "WM_api.h" diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 1b1d6294db6..4cd5e21bc22 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -48,7 +48,7 @@ #include "BLO_readfile.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "bpy_library.h" #include "../generic/py_capi_utils.h" diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c index c054183034a..9ca6092eab3 100644 --- a/source/blender/python/intern/bpy_library_write.c +++ b/source/blender/python/intern/bpy_library_write.c @@ -43,7 +43,7 @@ #include "RNA_types.h" #include "bpy_rna.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "bpy_library.h" #include "../generic/py_capi_utils.h" diff --git a/source/blender/python/intern/bpy_msgbus.c b/source/blender/python/intern/bpy_msgbus.c new file mode 100644 index 00000000000..945d2a9b6cc --- /dev/null +++ b/source/blender/python/intern/bpy_msgbus.c @@ -0,0 +1,400 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_msgbus.c + * \ingroup pythonintern + * This file defines '_bpy_msgbus' module, exposed as 'bpy.msgbus'. + */ + +#include <Python.h> + +#include "../generic/python_utildefines.h" +#include "../generic/py_capi_utils.h" +#include "../mathutils/mathutils.h" + +#include "BLI_utildefines.h" + +#include "BKE_context.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "WM_message.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "bpy_capi_utils.h" +#include "bpy_rna.h" +#include "bpy_intern_string.h" +#include "bpy_manipulator_wrap.h" /* own include */ + + +#include "bpy_msgbus.h" /* own include */ + + +/* -------------------------------------------------------------------- */ +/** \name Internal Utils + * \{ */ + +#define BPY_MSGBUS_RNA_MSGKEY_DOC \ +" :arg key: Represents the type of data being subscribed to\n" \ +"\n" \ +" Arguments include\n" \ +" - :class:`bpy.types.Property` instance.\n" \ +" - :class:`bpy.types.Struct` type.\n" \ +" - (:class:`bpy.types.Struct`, str) type and property name.\n" \ +" :type key: Muliple\n" + +/** + * There are multiple ways we can get RNA from Python, + * it's also possible to register a type instead of an instance. + * + * This function handles converting Python to RNA subscription information. + * + * \param py_sub: See #BPY_MSGBUS_RNA_MSGKEY_DOC for description. + * \param msg_key_params: Message key with all members zeroed out. + * \return -1 on failure, 0 on success. + */ +static int py_msgbus_rna_key_from_py( + PyObject *py_sub, + wmMsgParams_RNA *msg_key_params, + const char *error_prefix) +{ + + /* Allow common case, object rotation, location - etc. */ + if (BaseMathObject_CheckExact(py_sub)) { + BaseMathObject *py_sub_math = (BaseMathObject *)py_sub; + if (py_sub_math->cb_user == NULL) { + PyErr_Format( + PyExc_TypeError, + "%s: math argument has no owner", + error_prefix); + return -1; + } + py_sub = py_sub_math->cb_user; + /* Common case will use BPy_PropertyRNA_Check below. */ + } + + if (BPy_PropertyRNA_Check(py_sub)) { + BPy_PropertyRNA *data_prop = (BPy_PropertyRNA *)py_sub; + PYRNA_PROP_CHECK_INT(data_prop); + msg_key_params->ptr = data_prop->ptr; + msg_key_params->prop = data_prop->prop; + } + else if (BPy_StructRNA_Check(py_sub)) { + /* note, this isn't typically used since we don't edit structs directly. */ + BPy_StructRNA *data_srna = (BPy_StructRNA *)py_sub; + PYRNA_STRUCT_CHECK_INT(data_srna); + msg_key_params->ptr = data_srna->ptr; + } + /* TODO - property / type, not instance. */ + else if (PyType_Check(py_sub)) { + StructRNA *data_type = pyrna_struct_as_srna(py_sub, false, error_prefix); + if (data_type == NULL) { + return -1; + } + msg_key_params->ptr.type = data_type; + } + else if (PyTuple_CheckExact(py_sub)) { + if (PyTuple_GET_SIZE(py_sub) == 2) { + PyObject *data_type_py = PyTuple_GET_ITEM(py_sub, 0); + PyObject *data_prop_py = PyTuple_GET_ITEM(py_sub, 1); + StructRNA *data_type = pyrna_struct_as_srna(data_type_py, false, error_prefix); + if (data_type == NULL) { + return -1; + } + if (!PyUnicode_CheckExact(data_prop_py)) { + PyErr_Format( + PyExc_TypeError, + "%s: expected property to be a string", + error_prefix); + return -1; + } + PointerRNA data_type_ptr = { .type = data_type, }; + const char *data_prop_str = _PyUnicode_AsString(data_prop_py); + PropertyRNA *data_prop = RNA_struct_find_property(&data_type_ptr, data_prop_str); + + if (data_prop == NULL) { + PyErr_Format( + PyExc_TypeError, + "%s: struct %.200s does not contain property %.200s", + error_prefix, + RNA_struct_identifier(data_type), + data_prop_str); + return -1; + } + + msg_key_params->ptr.type = data_type; + msg_key_params->prop = data_prop; + } + else { + PyErr_Format( + PyExc_ValueError, + "%s: Expected a pair (type, property_id)", + error_prefix); + return -1; + } + } + return 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Callbacks + * \{ */ + +#define BPY_MSGBUS_USER_DATA_LEN 2 + +/* Follow wmMsgNotifyFn spec */ +static void bpy_msgbus_notify( + bContext *C, wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val) +{ + PyGILState_STATE gilstate; + bpy_context_set(C, &gilstate); + + PyObject *user_data = msg_val->user_data; + BLI_assert(PyTuple_GET_SIZE(user_data) == BPY_MSGBUS_USER_DATA_LEN); + + PyObject *callback_args = PyTuple_GET_ITEM(user_data, 0); + PyObject *callback_notify = PyTuple_GET_ITEM(user_data, 1); + + const bool is_write_ok = pyrna_write_check(); + if (!is_write_ok) { + pyrna_write_set(true); + } + + PyObject *ret = PyObject_CallObject(callback_notify, callback_args); + + if (ret == NULL) { + PyC_Err_PrintWithFunc(callback_notify); + } + else { + if (ret != Py_None) { + PyErr_SetString(PyExc_ValueError, "the return value must be None"); + PyC_Err_PrintWithFunc(callback_notify); + } + Py_DECREF(ret); + } + + bpy_context_clear(C, &gilstate); + + if (!is_write_ok) { + pyrna_write_set(false); + } +} + +/* Follow wmMsgSubscribeValueFreeDataFn spec */ +static void bpy_msgbus_subscribe_value_free_data( + struct wmMsgSubscribeKey *UNUSED(msg_key), struct wmMsgSubscribeValue *msg_val) +{ + PyGILState_STATE gilstate = PyGILState_Ensure(); + Py_DECREF(msg_val->owner); + Py_DECREF(msg_val->user_data); + PyGILState_Release(gilstate); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public Message Bus API + * \{ */ + +PyDoc_STRVAR(bpy_msgbus_subscribe_rna_doc, +".. function:: subscribe_rna(data, owner, args, notify)\n" +"\n" +BPY_MSGBUS_RNA_MSGKEY_DOC +" :arg owner: Handle for this subscription (compared by identity).\n" +" :type owner: Any type.\n" +"\n" +" Returns a new vector int property definition.\n" +); +static PyObject *bpy_msgbus_subscribe_rna(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + const char *error_prefix = "subscribe_rna"; + PyObject *py_sub = NULL; + PyObject *py_owner = NULL; + PyObject *callback_args = NULL; + PyObject *callback_notify = NULL; + + enum { + IS_PERSISTENT = (1 << 0), + }; + PyObject *py_options = NULL; + EnumPropertyItem py_options_enum[] = { + {IS_PERSISTENT, "PERSISTENT", 0, ""}, + {0, NULL, 0, NULL, NULL} + }; + int options = 0; + + static const char *_keywords[] = { + "key", + "owner", + "args", + "notify", + "options", + NULL, + }; + static _PyArg_Parser _parser = {"$OOO!OO!:subscribe_rna", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &py_sub, &py_owner, + &PyTuple_Type, &callback_args, + &callback_notify, + &PySet_Type, &py_options)) + { + return NULL; + } + + if (py_options && + (pyrna_set_to_enum_bitfield(py_options_enum, py_options, &options, error_prefix)) == -1) + { + return NULL; + } + + /* Note: we may want to have a way to pass this in. */ + bContext *C = (bContext *)BPy_GetContext(); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + wmMsgParams_RNA msg_key_params = {0}; + + wmMsgSubscribeValue msg_val_params = {0}; + + if (py_msgbus_rna_key_from_py(py_sub, &msg_key_params, error_prefix) == -1) { + return NULL; + } + + if (!PyFunction_Check(callback_notify)) { + PyErr_Format( + PyExc_TypeError, + "notify expects a function, found %.200s", + Py_TYPE(callback_notify)->tp_name); + return NULL; + } + + if (options != 0) { + if (options & IS_PERSISTENT) { + msg_val_params.is_persistent = true; + } + } + + /* owner can be anything. */ + { + msg_val_params.owner = py_owner; + Py_INCREF(py_owner); + } + + { + PyObject *user_data = PyTuple_New(2); + PyTuple_SET_ITEMS( + user_data, + Py_INCREF_RET(callback_args), + Py_INCREF_RET(callback_notify)); + msg_val_params.user_data = user_data; + } + + msg_val_params.notify = bpy_msgbus_notify; + msg_val_params.free_data = bpy_msgbus_subscribe_value_free_data; + + WM_msg_subscribe_rna_params(mbus, &msg_key_params, &msg_val_params, __func__); + + WM_msg_dump(mbus, __func__); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpy_msgbus_publish_rna_doc, +".. function:: publish_rna(data, owner, args, notify)\n" +"\n" +BPY_MSGBUS_RNA_MSGKEY_DOC +"\n" +" Notify subscribers of changes to this property\n" +" (this typically doesn't need to be called explicitly since changes will automatically publish updates).\n" +" In some cases it may be useful to publish changes explicitly using more general keys.\n" +); +static PyObject *bpy_msgbus_publish_rna(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + const char *error_prefix = "publish_rna"; + PyObject *py_sub = NULL; + + static const char *_keywords[] = { + "key", + NULL, + }; + static _PyArg_Parser _parser = {"$O:publish_rna", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &py_sub)) + { + return NULL; + } + + /* Note: we may want to have a way to pass this in. */ + bContext *C = (bContext *)BPy_GetContext(); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + wmMsgParams_RNA msg_key_params = {0}; + + if (py_msgbus_rna_key_from_py(py_sub, &msg_key_params, error_prefix) == -1) { + return NULL; + } + + WM_msg_publish_rna_params(mbus, &msg_key_params); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpy_msgbus_clear_by_owner_doc, +".. function:: clear_by_owner(owner)\n" +"\n" +" Clear all subscribers using this owner.\n" +); +static PyObject *bpy_msgbus_clear_by_owner(PyObject *UNUSED(self), PyObject *py_owner) +{ + bContext *C = (bContext *)BPy_GetContext(); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + WM_msgbus_clear_by_owner(mbus, py_owner); + Py_RETURN_NONE; +} + +static struct PyMethodDef BPy_msgbus_methods[] = { + {"subscribe_rna", (PyCFunction)bpy_msgbus_subscribe_rna, METH_VARARGS | METH_KEYWORDS, bpy_msgbus_subscribe_rna_doc}, + {"publish_rna", (PyCFunction)bpy_msgbus_publish_rna, METH_VARARGS | METH_KEYWORDS, bpy_msgbus_publish_rna_doc}, + {"clear_by_owner", (PyCFunction)bpy_msgbus_clear_by_owner, METH_O, bpy_msgbus_clear_by_owner_doc}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef _bpy_msgbus_def = { + PyModuleDef_HEAD_INIT, + .m_name = "msgbus", + .m_methods = BPy_msgbus_methods, +}; + + +PyObject *BPY_msgbus_module(void) +{ + PyObject *submodule; + + submodule = PyModule_Create(&_bpy_msgbus_def); + + return submodule; +} + +/** \} */ + diff --git a/source/blender/python/intern/bpy_msgbus.h b/source/blender/python/intern/bpy_msgbus.h new file mode 100644 index 00000000000..97b20e9b926 --- /dev/null +++ b/source/blender/python/intern/bpy_msgbus.h @@ -0,0 +1,30 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_msgbus.h + * \ingroup pythonintern + */ + +#ifndef __BPY_MSGBUS_H__ +#define __BPY_MSGBUS_H__ + +PyObject *BPY_msgbus_module(void); + +#endif /* __BPY_MSGBUS_H__ */ diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index c1fcb0792af..5b84a7cf73c 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -43,7 +43,7 @@ #include "bpy_operator.h" #include "bpy_operator_wrap.h" #include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */ -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "../generic/bpy_internal_import.h" #include "../generic/py_capi_utils.h" #include "../generic/python_utildefines.h" diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index c3d96227dea..d3eddff4b9a 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -37,7 +37,7 @@ #include "bpy_props.h" #include "bpy_rna.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "BKE_idprop.h" @@ -180,22 +180,6 @@ static PyObject *pyrna_struct_as_instance(PointerRNA *ptr) return self; } -/* could be moved into bpy_utils */ -static void printf_func_error(PyObject *py_func) -{ - /* since we return to C code we can't leave the error */ - PyCodeObject *f_code = (PyCodeObject *)PyFunction_GET_CODE(py_func); - PyErr_Print(); - PyErr_Clear(); - - /* use py style error */ - fprintf(stderr, "File \"%s\", line %d, in %s\n", - _PyUnicode_AsString(f_code->co_filename), - f_code->co_firstlineno, - _PyUnicode_AsString(((PyFunctionObject *)py_func)->func_name) - ); -} - static void bpy_prop_assign_flag(PropertyRNA *prop, const int flag) { const int flag_mask = ((PROP_ANIMATABLE) & ~flag); @@ -261,12 +245,12 @@ static void bpy_prop_update_cb(struct bContext *C, struct PointerRNA *ptr, struc Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } else { if (ret != Py_None) { PyErr_SetString(PyExc_ValueError, "the return value must be None"); - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } Py_DECREF(ret); @@ -313,14 +297,14 @@ static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); value = false; } else { value = PyC_Long_AsI32(ret); if (value == -1 && PyErr_Occurred()) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); value = false; } @@ -372,12 +356,12 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA * Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } else { if (ret != Py_None) { PyErr_SetString(PyExc_ValueError, "the return value must be None"); - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } Py_DECREF(ret); @@ -421,7 +405,7 @@ static int bpy_prop_poll_cb(struct PointerRNA *self, PointerRNA candidate, struc Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); result = false; } else { @@ -470,14 +454,14 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr, struct Propert Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); for (i = 0; i < len; ++i) values[i] = false; } else { if (PyC_AsArray(values, ret, len, &PyBool_Type, false, "BoolVectorProperty get") == -1) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); for (i = 0; i < len; ++i) values[i] = false; @@ -535,12 +519,12 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct Propert Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } else { if (ret != Py_None) { PyErr_SetString(PyExc_ValueError, "the return value must be None"); - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } Py_DECREF(ret); @@ -588,14 +572,14 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop) Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); value = 0.0f; } else { value = PyC_Long_AsI32(ret); if (value == -1 && PyErr_Occurred()) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); value = 0; } @@ -647,12 +631,12 @@ static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } else { if (ret != Py_None) { PyErr_SetString(PyExc_ValueError, "the return value must be None"); - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } Py_DECREF(ret); @@ -700,14 +684,14 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); for (i = 0; i < len; ++i) values[i] = 0; } else { if (PyC_AsArray(values, ret, len, &PyLong_Type, false, "IntVectorProperty get") == -1) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); for (i = 0; i < len; ++i) values[i] = 0; @@ -765,12 +749,12 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } else { if (ret != Py_None) { PyErr_SetString(PyExc_ValueError, "the return value must be None"); - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } Py_DECREF(ret); @@ -818,14 +802,14 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); value = 0.0f; } else { value = PyFloat_AsDouble(ret); if (value == -1.0f && PyErr_Occurred()) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); value = 0.0f; } @@ -877,12 +861,12 @@ static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pr Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } else { if (ret != Py_None) { PyErr_SetString(PyExc_ValueError, "the return value must be None"); - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } Py_DECREF(ret); @@ -930,14 +914,14 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr, struct PropertyR Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); for (i = 0; i < len; ++i) values[i] = 0.0f; } else { if (PyC_AsArray(values, ret, len, &PyFloat_Type, false, "FloatVectorProperty get") == -1) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); for (i = 0; i < len; ++i) values[i] = 0.0f; @@ -995,12 +979,12 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyR Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } else { if (ret != Py_None) { PyErr_SetString(PyExc_ValueError, "the return value must be None"); - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } Py_DECREF(ret); @@ -1047,14 +1031,14 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); value[0] = '\0'; } else if (!PyUnicode_Check(ret)) { PyErr_Format(PyExc_TypeError, "return value must be a string, not %.200s", Py_TYPE(ret)->tp_name); - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); value[0] = '\0'; Py_DECREF(ret); } @@ -1107,14 +1091,14 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); length = 0; } else if (!PyUnicode_Check(ret)) { PyErr_Format(PyExc_TypeError, "return value must be a string, not %.200s", Py_TYPE(ret)->tp_name); - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); length = 0; Py_DECREF(ret); } @@ -1167,7 +1151,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *p py_value = PyUnicode_FromString(value); if (!py_value) { PyErr_SetString(PyExc_ValueError, "the return value must be a string"); - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } else PyTuple_SET_ITEM(args, 1, py_value); @@ -1177,12 +1161,12 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *p Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } else { if (ret != Py_None) { PyErr_SetString(PyExc_ValueError, "the return value must be None"); - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } Py_DECREF(ret); @@ -1230,14 +1214,14 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); value = RNA_property_enum_get_default(ptr, prop); } else { value = PyC_Long_AsI32(ret); if (value == -1 && PyErr_Occurred()) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); value = RNA_property_enum_get_default(ptr, prop); } @@ -1289,12 +1273,12 @@ static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pro Py_DECREF(args); if (ret == NULL) { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } else { if (ret != Py_None) { PyErr_SetString(PyExc_ValueError, "the return value must be None"); - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); } Py_DECREF(ret); @@ -1572,7 +1556,7 @@ static const EnumPropertyItem *bpy_prop_enum_itemf_cb(struct bContext *C, Pointe *r_free = true; } else { - printf_func_error(py_func); + PyC_Err_PrintWithFunc(py_func); eitems = DummyRNA_NULL_items; } diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h index 614c1b4b708..fa2594f94d2 100644 --- a/source/blender/python/intern/bpy_props.h +++ b/source/blender/python/intern/bpy_props.h @@ -34,6 +34,6 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw); PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw); StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix); -#define PYRNA_STACK_ARRAY 32 +#define PYRNA_STACK_ARRAY RNA_STACK_ARRAY #endif diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 9630beb6e8b..fdad3a7d919 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -49,7 +49,7 @@ #include "bpy_rna.h" #include "bpy_rna_anim.h" #include "bpy_props.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "bpy_rna_callback.h" #include "bpy_intern_string.h" diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 8a0130babd5..9f9bb46c8bb 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -53,7 +53,7 @@ #include "WM_types.h" #include "bpy_rna.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "bpy_rna_anim.h" #include "../generic/python_utildefines.h" diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c index fe3565fc44e..68783feacd9 100644 --- a/source/blender/python/intern/bpy_rna_callback.c +++ b/source/blender/python/intern/bpy_rna_callback.c @@ -36,7 +36,7 @@ #include "bpy_rna.h" #include "bpy_rna_callback.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "DNA_space_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c index 8def52dc8fb..ee40d30d73b 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.c +++ b/source/blender/python/intern/bpy_rna_id_collection.c @@ -44,7 +44,7 @@ #include "DNA_object_types.h" #include "DNA_key_types.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "bpy_rna_id_collection.h" #include "../generic/py_capi_utils.h" diff --git a/source/blender/python/intern/bpy_rna_manipulator.c b/source/blender/python/intern/bpy_rna_manipulator.c index 4a326ae657b..950f7f98be0 100644 --- a/source/blender/python/intern/bpy_rna_manipulator.c +++ b/source/blender/python/intern/bpy_rna_manipulator.c @@ -37,7 +37,7 @@ #include "WM_api.h" #include "WM_types.h" -#include "bpy_util.h" +#include "bpy_capi_utils.h" #include "bpy_rna_manipulator.h" #include "../generic/py_capi_utils.h" diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h index d1fb6dcdb82..ec927a9e316 100644 --- a/source/blender/python/mathutils/mathutils.h +++ b/source/blender/python/mathutils/mathutils.h @@ -78,6 +78,10 @@ typedef struct { #include "mathutils_Euler.h" #include "mathutils_Color.h" +/* avoid checking all types */ +#define BaseMathObject_CheckExact(v) \ + (Py_TYPE(v)->tp_dealloc == (destructor)BaseMathObject_dealloc) + PyObject *BaseMathObject_owner_get(BaseMathObject *self, void *); PyObject *BaseMathObject_is_wrapped_get(BaseMathObject *self, void *); PyObject *BaseMathObject_is_frozen_get(BaseMathObject *self, void *); diff --git a/source/blender/python/mathutils/mathutils_Color.h b/source/blender/python/mathutils/mathutils_Color.h index 1290f73da62..e1a392de3da 100644 --- a/source/blender/python/mathutils/mathutils_Color.h +++ b/source/blender/python/mathutils/mathutils_Color.h @@ -30,7 +30,8 @@ #define __MATHUTILS_COLOR_H__ extern PyTypeObject color_Type; -#define ColorObject_Check(_v) PyObject_TypeCheck((_v), &color_Type) +#define ColorObject_Check(v) PyObject_TypeCheck((v), &color_Type) +#define ColorObject_CheckExact(v) (Py_TYPE(v) == &color_Type) typedef struct { BASE_MATH_MEMBERS(col); diff --git a/source/blender/python/mathutils/mathutils_Euler.h b/source/blender/python/mathutils/mathutils_Euler.h index 744f39faed1..4f5ba76b8df 100644 --- a/source/blender/python/mathutils/mathutils_Euler.h +++ b/source/blender/python/mathutils/mathutils_Euler.h @@ -29,7 +29,8 @@ */ extern PyTypeObject euler_Type; -#define EulerObject_Check(_v) PyObject_TypeCheck((_v), &euler_Type) +#define EulerObject_Check(v) PyObject_TypeCheck((v), &euler_Type) +#define EulerObject_CheckExact(v) (Py_TYPE(v) == &euler_Type) typedef struct { BASE_MATH_MEMBERS(eul); diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h index 9c84716d307..d2fbe6a04d5 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.h +++ b/source/blender/python/mathutils/mathutils_Matrix.h @@ -30,7 +30,10 @@ extern PyTypeObject matrix_Type; extern PyTypeObject matrix_access_Type; -#define MatrixObject_Check(_v) PyObject_TypeCheck((_v), &matrix_Type) + +#define MatrixObject_Check(v) PyObject_TypeCheck((v), &matrix_Type) +#define MatrixObject_CheckExact(v) (Py_TYPE(v) == &matrix_Type) + #define MATRIX_MAX_DIM 4 /* matrix[row][col] == MATRIX_ITEM_INDEX(matrix, row, col) */ diff --git a/source/blender/python/mathutils/mathutils_Quaternion.h b/source/blender/python/mathutils/mathutils_Quaternion.h index 66ee3362906..46f305b0f0e 100644 --- a/source/blender/python/mathutils/mathutils_Quaternion.h +++ b/source/blender/python/mathutils/mathutils_Quaternion.h @@ -28,7 +28,9 @@ */ extern PyTypeObject quaternion_Type; -#define QuaternionObject_Check(_v) PyObject_TypeCheck((_v), &quaternion_Type) + +#define QuaternionObject_Check(v) PyObject_TypeCheck((v), &quaternion_Type) +#define QuaternionObject_CheckExact(v) (Py_TYPE(v) == &quaternion_Type) typedef struct { BASE_MATH_MEMBERS(quat); diff --git a/source/blender/python/mathutils/mathutils_Vector.h b/source/blender/python/mathutils/mathutils_Vector.h index 74ca3336f4b..9ebf9457f2b 100644 --- a/source/blender/python/mathutils/mathutils_Vector.h +++ b/source/blender/python/mathutils/mathutils_Vector.h @@ -29,7 +29,9 @@ #define __MATHUTILS_VECTOR_H__ extern PyTypeObject vector_Type; -#define VectorObject_Check(_v) PyObject_TypeCheck((_v), &vector_Type) + +#define VectorObject_Check(v) PyObject_TypeCheck((v), &vector_Type) +#define VectorObject_CheckExact(v) (Py_TYPE(v) == &vector_Type) typedef struct { BASE_MATH_MEMBERS(vec); diff --git a/source/blender/python/mathutils/mathutils_bvhtree.h b/source/blender/python/mathutils/mathutils_bvhtree.h index 634556d68f7..445a393b93e 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.h +++ b/source/blender/python/mathutils/mathutils_bvhtree.h @@ -30,7 +30,7 @@ PyMODINIT_FUNC PyInit_mathutils_bvhtree(void); extern PyTypeObject PyBVHTree_Type; -#define PyBVHTree_Check(_v) PyObject_TypeCheck((_v), &PyBVHTree_Type) +#define PyBVHTree_Check(v) PyObject_TypeCheck((v), &PyBVHTree_Type) #define PyBVHTree_CheckExact(v) (Py_TYPE(v) == &PyBVHTree_Type) #endif /* __MATHUTILS_BVHTREE_H__ */ diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 81ed4c71b17..74de3fcded6 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -68,6 +68,7 @@ #include "BKE_displist.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" +#include "BKE_group.h" #include "BKE_key.h" #include "BKE_image.h" #include "BKE_lattice.h" @@ -3979,28 +3980,32 @@ static bool is_object_hidden(Render *re, Object *ob) /* layflag: allows material group to ignore layerflag */ static void add_lightgroup(Render *re, Group *group, int exclusive) { - GroupObject *go, *gol; - group->id.tag &= ~LIB_TAG_DOIT; +#if 0 /* it's a bit too many loops in loops... but will survive */ /* note that 'exclusive' will remove it from the global list */ - for (go= group->gobject.first; go; go= go->next) { - go->lampren= NULL; + FOREACH_GROUP_BASE(group, base) + { + Object *object = base->object; - if (is_object_hidden(re, go->ob)) + if (is_object_hidden(re, object)) { continue; - - if (go->ob->lay & re->lay) { - if (go->ob && go->ob->type==OB_LAMP) { - for (gol= re->lights.first; gol; gol= gol->next) { - if (gol->ob==go->ob) { - go->lampren= gol->lampren; + } + + if (base->flag & BASE_VISIBLED) { + if (object && object->type == OB_LAMP) { + for (GroupObject *gol = re->lights.first; gol; gol = gol->next) { + if (gol->ob == object) { + go->lampren = gol->lampren; break; } } - if (go->lampren==NULL) - gol= add_render_lamp(re, go->ob); + + if (go->lampren == NULL) { + gol= add_render_lamp(re, object); + } + if (gol && exclusive) { BLI_remlink(&re->lights, gol); MEM_freeN(gol); @@ -4008,6 +4013,10 @@ static void add_lightgroup(Render *re, Group *group, int exclusive) } } } + FOREACH_GROUP_BASE_END +#else + UNUSED_VARS(re, exclusive); +#endif } static void set_material_lightgroups(Render *re) @@ -4899,8 +4908,6 @@ static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, in { /* ugly function, but we need to set particle systems to their render * settings before calling object_duplilist, to get render level duplis */ - Group *group; - GroupObject *go; ParticleSystem *psys; DerivedMesh *dm; @@ -4932,11 +4939,13 @@ static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, in } } - if (ob->dup_group==NULL) return; - group= ob->dup_group; + if (ob->dup_group == NULL) return; - for (go= group->gobject.first; go; go= go->next) - dupli_render_particle_set(re, go->ob, timeoffset, level+1, enable); + FOREACH_GROUP_OBJECT(ob->dup_group, object) + { + dupli_render_particle_set(re, object, timeoffset, level+1, enable); + } + FOREACH_GROUP_OBJECT_END } static int get_vector_viewlayers(Scene *UNUSED(sce)) @@ -4946,29 +4955,27 @@ static int get_vector_viewlayers(Scene *UNUSED(sce)) static void add_group_render_dupli_obs(Render *re, Group *group, int nolamps, int onlyselected, Object *actob, int timeoffset, int level) { - GroupObject *go; - Object *ob; - - /* simple preventing of too deep nested groups */ - if (level>MAX_DUPLI_RECUR) return; - - /* recursively go into dupligroups to find objects with OB_RENDER_DUPLI - * that were not created yet */ - for (go= group->gobject.first; go; go= go->next) { - ob= go->ob; + /* Simple preventing of too deep nested groups. */ + if (level > MAX_DUPLI_RECUR) return; + /* Recursively go into dupligroups to find objects with OB_RENDER_DUPLI + * that were not created yet. */ + FOREACH_GROUP_OBJECT(group, ob) + { if (ob->flag & OB_DONE) { if (ob->transflag & OB_RENDER_DUPLI) { if (allow_render_object(re, ob, nolamps, onlyselected, actob)) { init_render_object(re, ob, NULL, NULL, NULL, timeoffset); ob->transflag &= ~OB_RENDER_DUPLI; - if (ob->dup_group) + if (ob->dup_group) { add_group_render_dupli_obs(re, ob->dup_group, nolamps, onlyselected, actob, timeoffset, level+1); + } } } } } + FOREACH_GROUP_OBJECT_END } static void database_init_objects(Render *re, unsigned int UNUSED(renderlay), int nolamps, int onlyselected, Object *actob, int timeoffset) diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 95a0371ba23..b5784fe543c 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -79,6 +79,9 @@ set(SRC manipulators/intern/wm_manipulator_map.c manipulators/intern/wm_manipulator_target_props.c manipulators/intern/wm_manipulator_type.c + message_bus/intern/wm_message_bus.c + message_bus/intern/wm_message_bus_rna.c + message_bus/intern/wm_message_bus_static.c WM_api.h WM_keymap.h @@ -96,6 +99,8 @@ set(SRC manipulators/wm_manipulator_fn.h manipulators/wm_manipulator_wmapi.h manipulators/intern/wm_manipulator_intern.h + message_bus/intern/wm_message_bus_intern.h + message_bus/wm_message_bus.h ) if(WITH_AUDASPACE) diff --git a/source/blender/windowmanager/WM_message.h b/source/blender/windowmanager/WM_message.h new file mode 100644 index 00000000000..48197ae99cd --- /dev/null +++ b/source/blender/windowmanager/WM_message.h @@ -0,0 +1,30 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/WM_message.h + * \ingroup wm + */ + +#ifndef __WM_MESSAGE_H__ +#define __WM_MESSAGE_H__ + +#include "message_bus/wm_message_bus.h" + +#endif /* __WM_MESSAGE_H__ */ diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 6e43d9715f1..27f872fc2bb 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -109,6 +109,7 @@ extern "C" { struct bContext; struct wmEvent; struct wmWindowManager; +struct wmMsgBus; struct wmOperator; struct ImBuf; diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 5d2bce791da..47fcbb1f523 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -56,6 +56,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "wm_window.h" #include "wm_event_system.h" #include "wm_draw.h" @@ -399,6 +400,10 @@ void WM_check(bContext *C) wm_window_ghostwindows_ensure(wm); } + if (wm->message_bus == NULL) { + wm->message_bus = WM_msgbus_create(); + } + /* case: fileread */ /* note: this runs in bg mode to set the screen context cb */ if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) { @@ -479,7 +484,11 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) } BLI_freelistN(&wm->queue); - + + if (wm->message_bus != NULL) { + WM_msgbus_destroy(wm->message_bus); + } + BLI_freelistN(&wm->paintcursors); WM_drag_free_list(&wm->drags); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 4220b8b4d62..02cf9981a3a 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -39,7 +39,6 @@ #include "DNA_screen_types.h" #include "DNA_scene_types.h" #include "DNA_windowmanager_types.h" -#include "DNA_workspace_types.h" #include "DNA_userdef_types.h" #include "MEM_guardedalloc.h" @@ -77,6 +76,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "wm.h" #include "wm_window.h" #include "wm_event_system.h" @@ -242,6 +242,14 @@ void WM_main_remove_notifier_reference(const void *reference) wm_notifier_clear(note); } } + + /* Remap instead. */ +#if 0 + if (wm->message_bus) { + WM_msg_id_remove(wm->message_bus, reference); + } +#endif + } } @@ -261,6 +269,17 @@ void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id) } } } + + wmWindowManager *wm = bmain->wm.first; + if (wm && wm->message_bus) { + struct wmMsgBus *mbus = wm->message_bus; + if (new_id != NULL) { + WM_msg_id_update(mbus, old_id, new_id); + } + else { + WM_msg_id_remove(mbus, old_id); + } + } } static void wm_notifier_clear(wmNotifier *note) @@ -328,7 +347,9 @@ void wm_event_do_notifiers(bContext *C) if (wm == NULL) return; - + + /* disable? - keep for now since its used for window level notifiers. */ +#if 1 /* cache & catch WM level notifiers, such as frame change, scene/screen set */ for (win = wm->windows.first; win; win = win->next) { Scene *scene = WM_window_get_active_scene(win); @@ -458,6 +479,16 @@ void wm_event_do_notifiers(bContext *C) MEM_freeN(note); } +#endif /* if 1 (postpone disabling for in favor of message-bus), eventually. */ + + /* Handle message bus. */ + { + for (win = wm->windows.first; win; win = win->next) { + CTX_wm_window_set(C, win); + WM_msgbus_handle(wm->message_bus, C); + } + CTX_wm_window_set(C, NULL); + } wm_event_do_refresh_wm_and_depsgraph(C); } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index c3ae4af1964..7c8059fcda9 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -123,6 +123,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "wm.h" #include "wm_files.h" #include "wm_window.h" @@ -504,7 +505,11 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); +#if 1 WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL); +#else + WM_msg_publish_static(CTX_wm_message_bus(C), WM_MSG_STATICTYPE_FILE_READ); +#endif /* report any errors. * currently disabled if addons aren't yet loaded */ diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 2086ade99d2..cd6a38cb9a8 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -159,7 +159,7 @@ typedef struct WMLinkAppendData { LinkNodePair items; int num_libraries; int num_items; - short flag; + int flag; /* Combines eFileSel_Params_Flag from DNA_space_types.h and BLO_LibLinkFlags from BLO_readfile.h */ /* Internal 'private' data */ MemArena *memarena; @@ -214,8 +214,7 @@ static WMLinkAppendDataItem *wm_link_append_data_item_add( } static void wm_link_do( - WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, ViewLayer *view_layer, - const bool use_placeholders, const bool force_indirect) + WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, ViewLayer *view_layer) { Main *mainl; BlendHandle *bh; @@ -262,8 +261,7 @@ static void wm_link_do( continue; } - new_id = BLO_library_link_named_part_ex( - mainl, &bh, item->idcode, item->name, flag, scene, view_layer, use_placeholders, force_indirect); + new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, view_layer); if (new_id) { /* If the link is successful, clear item's libs 'todo' flags. @@ -372,6 +370,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) scene = NULL; } + /* We need to add nothing from BLO_LibLinkFlags to flag here. */ + /* from here down, no error returns */ if (view_layer && RNA_boolean_get(op->ptr, "autoselect")) { @@ -453,7 +453,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* XXX We'd need re-entrant locking on Main for this to work... */ /* BKE_main_lock(bmain); */ - wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, false, false); + wm_link_do(lapp_data, op->reports, bmain, scene, view_layer); /* BKE_main_unlock(bmain); */ @@ -653,7 +653,7 @@ static void lib_relocate_do( BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); /* We do not want any instanciation here! */ - wm_link_do(lapp_data, reports, bmain, NULL, NULL, do_reload, do_reload); + wm_link_do(lapp_data, reports, bmain, NULL, NULL); BKE_main_lock(bmain); @@ -814,7 +814,7 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) return; } - WMLinkAppendData *lapp_data = wm_link_append_data_new(0); + WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT); wm_link_append_data_library_add(lapp_data, lib->filepath); @@ -924,6 +924,10 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) } } + if (do_reload) { + lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT; + } + lib_relocate_do(bmain, lib, lapp_data, op->reports, do_reload); wm_link_append_data_free(lapp_data); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index fc1805e102f..55ed8b2a091 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -93,6 +93,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "wm_cursors.h" #include "wm_event_system.h" @@ -178,8 +179,7 @@ void WM_init(bContext *C, int argc, const char **argv) BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */ BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */ DEG_editors_set_update_cb(ED_render_id_flush_update, - ED_render_scene_update, - ED_render_scene_update_pre); + ED_render_scene_update); ED_spacetypes_init(); /* editors/space_api/spacetype.c */ @@ -193,6 +193,8 @@ void WM_init(bContext *C, int argc, const char **argv) * but keep before file reading, since that may report errors */ wm_init_reports(C); + WM_msgbus_types_init(); + /* get the default database, plus a wm */ wm_homefile_read(C, NULL, G.factory_startup, false, true, NULL, NULL); diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_api.h b/source/blender/windowmanager/manipulators/WM_manipulator_api.h index a3875c50348..9214bccb6a0 100644 --- a/source/blender/windowmanager/manipulators/WM_manipulator_api.h +++ b/source/blender/windowmanager/manipulators/WM_manipulator_api.h @@ -51,6 +51,8 @@ struct wmManipulatorGroupType; struct wmManipulatorMap; struct wmManipulatorMapType; struct wmManipulatorMapType_Params; +struct wmMsgSubscribeKey; +struct wmMsgSubscribeValue; #include "wm_manipulator_fn.h" @@ -216,6 +218,11 @@ const struct wmManipulatorPropertyType *WM_manipulatortype_target_property_find( void WM_manipulatortype_target_property_def( struct wmManipulatorType *wt, const char *idname, int data_type, int array_length); +/* utilities */ +void WM_manipulator_do_msg_notify_tag_refresh( + struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val); +void WM_manipulator_target_property_subscribe_all( + struct wmManipulator *mpr, struct wmMsgBus *mbus, struct ARegion *ar); /* -------------------------------------------------------------------- */ /* wmManipulatorGroup */ @@ -245,6 +252,8 @@ void WM_manipulatormap_draw( void WM_manipulatormap_add_handlers(struct ARegion *ar, struct wmManipulatorMap *mmap); bool WM_manipulatormap_select_all(struct bContext *C, struct wmManipulatorMap *mmap, const int action); bool WM_manipulatormap_cursor_set(const struct wmManipulatorMap *mmap, struct wmWindow *win); +void WM_manipulatormap_message_subscribe( + struct bContext *C, struct wmManipulatorMap *mmap, struct ARegion *ar, struct wmMsgBus *mbus); bool WM_manipulatormap_is_any_selected(const struct wmManipulatorMap *mmap); bool WM_manipulatormap_minmax( const struct wmManipulatorMap *mmap, bool use_hidden, bool use_select, diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_types.h b/source/blender/windowmanager/manipulators/WM_manipulator_types.h index d4477b8e508..5fa89b8d35f 100644 --- a/source/blender/windowmanager/manipulators/WM_manipulator_types.h +++ b/source/blender/windowmanager/manipulators/WM_manipulator_types.h @@ -346,6 +346,11 @@ typedef struct wmManipulatorGroupType { * will fall back to default tweak keymap when left NULL. */ wmManipulatorGroupFnSetupKeymap setup_keymap; + /* Optionally subscribe to wmMsgBus events, + * these are calculated automatically from RNA properties, + * only needed if manipulators depend indirectly on properties. */ + wmManipulatorGroupFnMsgBusSubscribe message_subscribe; + /* keymap created with callback from above */ struct wmKeyMap *keymap; /* Only for convenient removal. */ diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c index a174d7720e3..5d9810272cc 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c @@ -305,6 +305,7 @@ static bool manipulator_prepare_drawing( /* skip */ } else { + /* Ensure we get RNA updates */ if (do_draw & WM_MANIPULATOR_IS_VISIBLE_UPDATE) { /* hover manipulators need updating, even if we don't draw them */ wm_manipulator_update(mpr, C, (mmap->update_flag[drawstep] & MANIPULATORMAP_IS_PREPARE_DRAW) != 0); @@ -953,6 +954,25 @@ ListBase *wm_manipulatormap_groups_get(wmManipulatorMap *mmap) return &mmap->groups; } +void WM_manipulatormap_message_subscribe( + bContext *C, wmManipulatorMap *mmap, ARegion *ar, struct wmMsgBus *mbus) +{ + for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) { + if (!wm_manipulatorgroup_is_visible(mgroup, C)) { + continue; + } + for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) { + if (mpr->flag & WM_MANIPULATOR_HIDDEN) { + continue; + } + WM_manipulator_target_property_subscribe_all(mpr, mbus, ar); + } + if (mgroup->type->message_subscribe != NULL) { + mgroup->type->message_subscribe(C, mgroup, mbus); + } + } +} + /** \} */ /* wmManipulatorMap */ diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c index 836376f1c54..137e8f5639d 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c @@ -35,6 +35,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "wm.h" @@ -311,3 +312,53 @@ void WM_manipulatortype_target_property_def( } /** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Property Utilities + * \{ */ + +void WM_manipulator_do_msg_notify_tag_refresh( + bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val) +{ + ARegion *ar = msg_val->owner; + wmManipulatorMap *mmap = msg_val->user_data; + + ED_region_tag_redraw(ar); + WM_manipulatormap_tag_refresh(mmap); +} + +/** + * Runs on the "prepare draw" pass, + * drawing the region clears. + */ +void WM_manipulator_target_property_subscribe_all( + wmManipulator *mpr, struct wmMsgBus *mbus, ARegion *ar) +{ + if (mpr->type->target_property_defs_len) { + wmManipulatorProperty *mpr_prop_array = WM_manipulator_target_property_array(mpr); + for (int i = 0; i < mpr->type->target_property_defs_len; i++) { + wmManipulatorProperty *mpr_prop = &mpr_prop_array[i]; + if (WM_manipulator_target_property_is_valid(mpr_prop)) { + if (mpr_prop->prop) { + WM_msg_subscribe_rna( + mbus, &mpr_prop->ptr, mpr_prop->prop, + &(const wmMsgSubscribeValue){ + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }, __func__); + WM_msg_subscribe_rna( + mbus, &mpr_prop->ptr, mpr_prop->prop, + &(const wmMsgSubscribeValue){ + .owner = ar, + .user_data = mpr->parent_mgroup->parent_mmap, + .notify = WM_manipulator_do_msg_notify_tag_refresh, + }, __func__); + } + } + } + } +} + +/** \} */ diff --git a/source/blender/windowmanager/manipulators/wm_manipulator_fn.h b/source/blender/windowmanager/manipulators/wm_manipulator_fn.h index c54024529c3..7e163f8a785 100644 --- a/source/blender/windowmanager/manipulators/wm_manipulator_fn.h +++ b/source/blender/windowmanager/manipulators/wm_manipulator_fn.h @@ -42,6 +42,8 @@ typedef void (*wmManipulatorGroupFnDrawPrepare)( typedef struct wmKeyMap *(*wmManipulatorGroupFnSetupKeymap)( const struct wmManipulatorGroupType *, struct wmKeyConfig *) ATTR_WARN_UNUSED_RESULT; +typedef void (*wmManipulatorGroupFnMsgBusSubscribe)( + const struct bContext *, struct wmManipulatorGroup *, struct wmMsgBus *); /* wmManipulator */ /* See: wmManipulatorType for docs on each type. */ diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c new file mode 100644 index 00000000000..7183655b0de --- /dev/null +++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c @@ -0,0 +1,247 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/message_bus/intern/wm_message_bus.c + * \ingroup wm + */ + +#include <string.h> + +#include "BLI_utildefines.h" +#include "BLI_listbase.h" + +#include "BLI_ghash.h" + +#include "WM_types.h" + +#include "MEM_guardedalloc.h" + +#include "message_bus/wm_message_bus.h" +#include "message_bus/intern/wm_message_bus_intern.h" + +/* -------------------------------------------------------------------------- */ +/** \name Public API + * \{ */ + +static wmMsgTypeInfo wm_msg_types[WM_MSG_TYPE_NUM] = {NULL}; + +typedef void (*wmMsgTypeInitFn)(wmMsgTypeInfo *); + +static wmMsgTypeInitFn wm_msg_init_fn[WM_MSG_TYPE_NUM] = { + WM_msgtypeinfo_init_rna, + WM_msgtypeinfo_init_static, +}; + +void WM_msgbus_types_init(void) +{ + for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) { + wm_msg_init_fn[i](&wm_msg_types[i]); + } +} + +struct wmMsgBus *WM_msgbus_create(void) +{ + struct wmMsgBus *mbus = MEM_callocN(sizeof(*mbus), __func__); + const uint gset_reserve = 512; + for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) { + wmMsgTypeInfo *info = &wm_msg_types[i]; + mbus->messages_gset[i] = BLI_gset_new_ex(info->gset.hash_fn, info->gset.cmp_fn, __func__, gset_reserve); + } + return mbus; +} + +void WM_msgbus_destroy(struct wmMsgBus *mbus) +{ + for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) { + wmMsgTypeInfo *info = &wm_msg_types[i]; + BLI_gset_free(mbus->messages_gset[i], info->gset.key_free_fn); + } + MEM_freeN(mbus); +} + +void WM_msgbus_clear_by_owner(struct wmMsgBus *mbus, void *owner) +{ + wmMsgSubscribeKey *msg_key, *msg_key_next; + for (msg_key = mbus->messages.first; msg_key; msg_key = msg_key_next) { + msg_key_next = msg_key->next; + + wmMsgSubscribeValueLink *msg_lnk_next; + for (wmMsgSubscribeValueLink *msg_lnk = msg_key->values.first; msg_lnk; msg_lnk = msg_lnk_next) { + msg_lnk_next = msg_lnk->next; + if (msg_lnk->params.owner == owner) { + if (msg_lnk->params.free_data) { + msg_lnk->params.free_data(msg_key, &msg_lnk->params); + } + BLI_remlink(&msg_key->values, msg_lnk); + MEM_freeN(msg_lnk); + } + } + + if (BLI_listbase_is_empty(&msg_key->values)) { + const wmMsg *msg = wm_msg_subscribe_value_msg_cast(msg_key); + wmMsgTypeInfo *info = &wm_msg_types[msg->type]; + BLI_remlink(&mbus->messages, msg_key); + bool ok = BLI_gset_remove(mbus->messages_gset[msg->type], msg_key, info->gset.key_free_fn); + BLI_assert(ok); + UNUSED_VARS_NDEBUG(ok); + } + } +} + +void WM_msg_dump(struct wmMsgBus *mbus, const char *info_str) +{ + printf(">>>> %s\n", info_str); + for (wmMsgSubscribeKey *key = mbus->messages.first; key; key = key->next) { + const wmMsg *msg = wm_msg_subscribe_value_msg_cast(key); + const wmMsgTypeInfo *info = &wm_msg_types[msg->type]; + info->repr(stdout, key); + } + printf("<<<< %s\n", info_str); +} + +void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C) +{ + if (mbus->messages_tag_count == 0) { + // printf("msgbus: skipping\n"); + return; + } + + if (false) { + WM_msg_dump(mbus, __func__); + } + + // uint a = 0, b = 0; + for (wmMsgSubscribeKey *key = mbus->messages.first; key; key = key->next) { + for (wmMsgSubscribeValueLink *msg_lnk = key->values.first; msg_lnk; msg_lnk = msg_lnk->next) { + if (msg_lnk->params.tag) { + msg_lnk->params.notify(C, key, &msg_lnk->params); + msg_lnk->params.tag = false; + mbus->messages_tag_count -= 1; + } + // b++; + } + // a++; + } + BLI_assert(mbus->messages_tag_count == 0); + mbus->messages_tag_count = 0; + // printf("msgbus: keys=%u values=%u\n", a, b); +} + +/** + * \param msg_key_test: Needs following #wmMsgSubscribeKey fields filled in: + * - msg.params + * - msg.head.type + * - msg.head.id + * .. other values should be zeroed. + * + * \return The key for this subscription. + * note that this is only needed in rare cases when the key needs further manipulation. + */ +wmMsgSubscribeKey *WM_msg_subscribe_with_key( + struct wmMsgBus *mbus, + const wmMsgSubscribeKey *msg_key_test, + const wmMsgSubscribeValue *msg_val_params) +{ + const uint type = wm_msg_subscribe_value_msg_cast(msg_key_test)->type; + const wmMsgTypeInfo *info = &wm_msg_types[type]; + wmMsgSubscribeKey *key; + + BLI_assert(wm_msg_subscribe_value_msg_cast(msg_key_test)->id != NULL); + + void **r_key; + if (!BLI_gset_ensure_p_ex(mbus->messages_gset[type], msg_key_test, &r_key)) { + key = *r_key = MEM_mallocN(info->msg_key_size, __func__); + memcpy(key, msg_key_test, info->msg_key_size); + BLI_addtail(&mbus->messages, key); + } + else { + key = *r_key; + for (wmMsgSubscribeValueLink *msg_lnk = key->values.first; msg_lnk; msg_lnk = msg_lnk->next) { + if ((msg_lnk->params.notify == msg_val_params->notify) && + (msg_lnk->params.owner == msg_val_params->owner) && + (msg_lnk->params.user_data == msg_val_params->user_data)) + { + return key; + } + } + } + + wmMsgSubscribeValueLink *msg_lnk = MEM_mallocN(sizeof(wmMsgSubscribeValueLink), __func__); + msg_lnk->params = *msg_val_params; + BLI_addtail(&key->values, msg_lnk); + return key; +} + +void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key) +{ + for (wmMsgSubscribeValueLink *msg_lnk = msg_key->values.first; msg_lnk; msg_lnk = msg_lnk->next) { + if (false) { /* make an option? */ + msg_lnk->params.notify(NULL, msg_key, &msg_lnk->params); + } + else { + if (msg_lnk->params.tag == false) { + msg_lnk->params.tag = true; + mbus->messages_tag_count += 1; + } + } + } +} + +void WM_msg_id_update( + struct wmMsgBus *mbus, + struct ID *id_src, struct ID *id_dst) +{ + for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) { + wmMsgTypeInfo *info = &wm_msg_types[i]; + if (info->update_by_id != NULL) { + info->update_by_id(mbus, id_src, id_dst); + } + } +} + +void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id) +{ + for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) { + wmMsgTypeInfo *info = &wm_msg_types[i]; + if (info->remove_by_id != NULL) { + info->remove_by_id(mbus, id); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------------- */ +/** \name Internal API + * + * \note While we could have a separate type for ID's, use RNA since there is enough overlap. + * \{ */ + +void wm_msg_subscribe_value_free( + wmMsgSubscribeKey *msg_key, wmMsgSubscribeValueLink *msg_lnk) +{ + if (msg_lnk->params.free_data) { + msg_lnk->params.free_data(msg_key, &msg_lnk->params); + } + BLI_remlink(&msg_key->values, msg_lnk); + MEM_freeN(msg_lnk); +} + +/** \} */ diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h new file mode 100644 index 00000000000..db8b481a3c2 --- /dev/null +++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h @@ -0,0 +1,55 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/message_bus/intern/wm_message_bus_intern.h + * \ingroup wm + */ + +#ifndef __WM_MESSAGE_BUS_INTERN_H__ +#define __WM_MESSAGE_BUS_INTERN_H__ + +/* wm_message_bus.h must be included first */ + +struct wmMsgBus { + struct GSet *messages_gset[WM_MSG_TYPE_NUM]; + /** Messages in order of being added. */ + ListBase messages; + /** Avoid checking messages when no tags exist. */ + uint messages_tag_count; +}; + +void wm_msg_subscribe_value_free( + struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValueLink *msg_lnk); + +typedef struct wmMsgSubscribeKey_Generic { + wmMsgSubscribeKey head; + wmMsg msg; +} wmMsgSubscribeKey_Generic; + +BLI_INLINE const wmMsg *wm_msg_subscribe_value_msg_cast(const wmMsgSubscribeKey *key) +{ + return &((wmMsgSubscribeKey_Generic *)key)->msg; +} +BLI_INLINE wmMsg *wm_msg_subscribe_value_msg_cast_mut(wmMsgSubscribeKey *key) +{ + return &((wmMsgSubscribeKey_Generic *)key)->msg; +} + +#endif /* __WM_MESSAGE_BUS_INTERN_H__ */ diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c new file mode 100644 index 00000000000..f9d8d968b84 --- /dev/null +++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c @@ -0,0 +1,316 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/intern/wm_message_bus_rna.c + * \ingroup wm + */ + +#include <stdio.h> +#include "DNA_ID.h" + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_listbase.h" + +#include "WM_types.h" +#include "WM_message.h" +#include "message_bus/intern/wm_message_bus_intern.h" + +#include "RNA_access.h" + +#include "MEM_guardedalloc.h" + +/* -------------------------------------------------------------------------- */ + +BLI_INLINE uint void_hash_uint(const void *key) +{ + size_t y = (size_t)key >> (sizeof(void *)); + return (unsigned int)y; +} + +static uint wm_msg_rna_gset_hash(const void *key_p) +{ + const wmMsgSubscribeKey_RNA *key = key_p; + const wmMsgParams_RNA *params = &key->msg.params; +// printf("%s\n", RNA_struct_identifier(params->ptr.type)); + uint k = void_hash_uint(params->ptr.type); + k ^= void_hash_uint(params->ptr.data); + k ^= void_hash_uint(params->ptr.id.data); + k ^= void_hash_uint(params->prop); + return k; +} +static bool wm_msg_rna_gset_cmp(const void *key_a_p, const void *key_b_p) +{ + const wmMsgParams_RNA *params_a = &((const wmMsgSubscribeKey_RNA *)key_a_p)->msg.params; + const wmMsgParams_RNA *params_b = &((const wmMsgSubscribeKey_RNA *)key_b_p)->msg.params; + return !( + (params_a->ptr.type == + params_b->ptr.type) && + (params_a->ptr.id.data == + params_b->ptr.id.data) && + (params_a->ptr.data == + params_b->ptr.data) && + (params_a->prop == + params_b->prop) + ); +} +static void wm_msg_rna_gset_key_free(void *key_p) +{ + wmMsgSubscribeKey_RNA *key = key_p; + wmMsgSubscribeValueLink *msg_lnk_next; + for (wmMsgSubscribeValueLink *msg_lnk = key->head.values.first; msg_lnk; msg_lnk = msg_lnk_next) { + msg_lnk_next = msg_lnk->next; + wm_msg_subscribe_value_free(&key->head, msg_lnk); + } + if (key->msg.params.data_path != NULL) { + MEM_freeN(key->msg.params.data_path); + } + MEM_freeN(key); +} + +static void wm_msg_rna_repr(FILE *stream, const wmMsgSubscribeKey *msg_key) +{ + const wmMsgSubscribeKey_RNA *m = (wmMsgSubscribeKey_RNA *)msg_key; + const char *none = "<none>"; + fprintf(stream, + "<wmMsg_RNA %p, " + "id='%s', " + "%s.%s values_len=%d\n", + m, m->msg.head.id, + m->msg.params.ptr.type ? RNA_struct_identifier(m->msg.params.ptr.type) : none, + m->msg.params.prop ? RNA_property_identifier((PropertyRNA *)m->msg.params.prop) : none, + BLI_listbase_count(&m->head.values)); +} + +static void wm_msg_rna_update_by_id( + struct wmMsgBus *mbus, + ID *id_src, ID *id_dst) +{ + GSet *gs = mbus->messages_gset[WM_MSG_TYPE_RNA]; + GSetIterator gs_iter; + BLI_gsetIterator_init(&gs_iter, gs); + while (BLI_gsetIterator_done(&gs_iter) == false) { + wmMsgSubscribeKey_RNA *key = BLI_gsetIterator_getKey(&gs_iter); + BLI_gsetIterator_step(&gs_iter); + if (key->msg.params.ptr.id.data == id_src) { + + /* GSet always needs updating since the key changes. */ + BLI_gset_remove(gs, key, NULL); + + /* Remove any non-persistent values, so a single persistent + * value doesn't modify behavior for the rest. */ + wmMsgSubscribeValueLink *msg_lnk_next; + for (wmMsgSubscribeValueLink *msg_lnk = key->head.values.first; msg_lnk; msg_lnk = msg_lnk_next) { + msg_lnk_next = msg_lnk->next; + if (msg_lnk->params.is_persistent == false) { + wm_msg_subscribe_value_free(&key->head, msg_lnk); + } + } + + bool remove = true; + + if (BLI_listbase_is_empty(&key->head.values)) { + /* Remove, no reason to keep. */ + } + else if (key->msg.params.ptr.data == key->msg.params.ptr.id.data) { + /* Simple, just update the ID. */ + key->msg.params.ptr.data = id_dst; + key->msg.params.ptr.id.data = id_dst; + remove = false; + } + else { + /* we need to resolve this from the */ + PointerRNA idptr; + RNA_id_pointer_create(id_dst, &idptr); + PointerRNA ptr; + PropertyRNA *prop; + if (!RNA_path_resolve(&idptr, key->msg.params.data_path, &ptr, &prop)) { + key->msg.params.ptr = ptr; + key->msg.params.prop = prop; + remove = false; + } + } + + printf("AAA ~ %d\n", remove); + if (remove) { + /* Failed to persist, remove the key. */ + BLI_remlink(&mbus->messages, key); + wm_msg_rna_gset_key_free(key); + } + else { + /* note that it's not impossible this key exists, however it is very unlikely + * since a subscriber would need to register in the middle of an undo for eg. so assert for now. */ + BLI_assert(!BLI_gset_haskey(gs, key)); + BLI_gset_add(gs, key); + } + } + } +} + +static void wm_msg_rna_remove_by_id(struct wmMsgBus *mbus, const ID *id) +{ + GSet *gs = mbus->messages_gset[WM_MSG_TYPE_RNA]; + GSetIterator gs_iter; + BLI_gsetIterator_init(&gs_iter, gs); + while (BLI_gsetIterator_done(&gs_iter) == false) { + wmMsgSubscribeKey_RNA *key = BLI_gsetIterator_getKey(&gs_iter); + BLI_gsetIterator_step(&gs_iter); + if (key->msg.params.ptr.id.data == id) { + BLI_remlink(&mbus->messages, key); + BLI_gset_remove(gs, key, NULL); + wm_msg_rna_gset_key_free(key); + } + } +} + +void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info) +{ + msgtype_info->gset.hash_fn = wm_msg_rna_gset_hash; + msgtype_info->gset.cmp_fn = wm_msg_rna_gset_cmp; + msgtype_info->gset.key_free_fn = wm_msg_rna_gset_key_free; + + msgtype_info->repr = wm_msg_rna_repr; + msgtype_info->update_by_id = wm_msg_rna_update_by_id; + msgtype_info->remove_by_id = wm_msg_rna_remove_by_id; + + msgtype_info->msg_key_size = sizeof(wmMsgSubscribeKey_RNA); +} + +/* -------------------------------------------------------------------------- */ + + +wmMsgSubscribeKey_RNA *WM_msg_lookup_rna(struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params) +{ + wmMsgSubscribeKey_RNA key_test; + key_test.msg.params = *msg_key_params; + return BLI_gset_lookup(mbus->messages_gset[WM_MSG_TYPE_RNA], &key_test); +} + +void WM_msg_publish_rna_params(struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params) +{ + wmMsgSubscribeKey_RNA *key; + + if ((key = WM_msg_lookup_rna(mbus, msg_key_params))) { + WM_msg_publish_with_key(mbus, &key->head); + } + + /* Support anonymous subscribers, this may be some extra overhead + * but we want to be able to be more ambiguous. */ + if (msg_key_params->ptr.id.data || msg_key_params->ptr.data) { + wmMsgParams_RNA msg_key_params_anon = *msg_key_params; + + /* We might want to enable this later? */ + if (msg_key_params_anon.prop != NULL) { + /* All properties for this type. */ + msg_key_params_anon.prop = NULL; + if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) { + WM_msg_publish_with_key(mbus, &key->head); + } + msg_key_params_anon.prop = msg_key_params->prop; + } + + msg_key_params_anon.ptr.id.data = NULL; + msg_key_params_anon.ptr.data = NULL; + if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) { + WM_msg_publish_with_key(mbus, &key->head); + } + + /* Support subscribers to a type. */ + if (msg_key_params->prop) { + msg_key_params_anon.prop = NULL; + if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) { + WM_msg_publish_with_key(mbus, &key->head); + } + } + } +} + +void WM_msg_publish_rna(struct wmMsgBus *mbus, PointerRNA *ptr, PropertyRNA *prop) +{ + WM_msg_publish_rna_params(mbus, &(wmMsgParams_RNA){ .ptr = *ptr, .prop = prop, }); +} + +void WM_msg_subscribe_rna_params( + struct wmMsgBus *mbus, + const wmMsgParams_RNA *msg_key_params, + const wmMsgSubscribeValue *msg_val_params, + const char *id_repr) +{ + wmMsgSubscribeKey_RNA msg_key_test = {{NULL}}; + + /* use when added */ + msg_key_test.msg.head.id = id_repr; + msg_key_test.msg.head.type = WM_MSG_TYPE_RNA; + /* for lookup */ + msg_key_test.msg.params = *msg_key_params; + + wmMsgSubscribeKey_RNA *msg_key = (wmMsgSubscribeKey_RNA *)WM_msg_subscribe_with_key( + mbus, &msg_key_test.head, msg_val_params); + + if (msg_val_params->is_persistent) { + if (msg_key->msg.params.data_path == NULL) { + if (msg_key->msg.params.ptr.data != msg_key->msg.params.ptr.id.data) { + /* We assume prop type can't change. */ + msg_key->msg.params.data_path = RNA_path_from_ID_to_struct(&msg_key->msg.params.ptr); + } + } + } +} + +void WM_msg_subscribe_rna( + struct wmMsgBus *mbus, + PointerRNA *ptr, const PropertyRNA *prop, + const wmMsgSubscribeValue *msg_val_params, + const char *id_repr) +{ + WM_msg_subscribe_rna_params( + mbus, + &(const wmMsgParams_RNA){ + .ptr = *ptr, + .prop = prop, + }, + msg_val_params, id_repr); +} + +/** \} */ + +/* -------------------------------------------------------------------------- */ +/** \name ID variants of RNA API + * + * \note While we could have a separate type for ID's, use RNA since there is enough overlap. + * \{ */ + +void WM_msg_subscribe_ID( + struct wmMsgBus *mbus, ID *id, const wmMsgSubscribeValue *msg_val_params, + const char *id_repr) +{ + wmMsgParams_RNA msg_key_params = {NULL}; + RNA_id_pointer_create(id, &msg_key_params.ptr); + WM_msg_subscribe_rna_params(mbus, &msg_key_params, msg_val_params, id_repr); +} + +void WM_msg_publish_ID(struct wmMsgBus *mbus, ID *id) +{ + wmMsgParams_RNA msg_key_params = {NULL}; + RNA_id_pointer_create(id, &msg_key_params.ptr); + WM_msg_publish_rna_params(mbus, &msg_key_params); +} + +/** \} */ diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_static.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_static.c new file mode 100644 index 00000000000..59bebad7f7b --- /dev/null +++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_static.c @@ -0,0 +1,136 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/intern/wm_message_bus_static.c + * \ingroup wm + */ + +#include <stdio.h> + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_listbase.h" + +#include "WM_types.h" +#include "WM_message.h" +#include "message_bus/intern/wm_message_bus_intern.h" + +#include "MEM_guardedalloc.h" + +/* -------------------------------------------------------------------------- */ + +static uint wm_msg_static_gset_hash(const void *key_p) +{ + const wmMsgSubscribeKey_Static *key = key_p; + const wmMsgParams_Static *params = &key->msg.params; + uint k = params->event; + return k; +} +static bool wm_msg_static_gset_cmp(const void *key_a_p, const void *key_b_p) +{ + const wmMsgParams_Static *params_a = &((const wmMsgSubscribeKey_Static *)key_a_p)->msg.params; + const wmMsgParams_Static *params_b = &((const wmMsgSubscribeKey_Static *)key_b_p)->msg.params; + return !( + (params_a->event == + params_b->event) + ); +} +static void wm_msg_static_gset_key_free(void *key_p) +{ + wmMsgSubscribeKey *key = key_p; + wmMsgSubscribeValueLink *msg_lnk_next; + for (wmMsgSubscribeValueLink *msg_lnk = key->values.first; msg_lnk; msg_lnk = msg_lnk_next) { + msg_lnk_next = msg_lnk->next; + BLI_remlink(&key->values, msg_lnk); + MEM_freeN(msg_lnk); + } + MEM_freeN(key); +} + +static void wm_msg_static_repr(FILE *stream, const wmMsgSubscribeKey *msg_key) +{ + const wmMsgSubscribeKey_Static *m = (wmMsgSubscribeKey_Static *)msg_key; + fprintf(stream, + "<wmMsg_Static %p, " + "id='%s', " + "values_len=%d\n", + m, m->msg.head.id, + BLI_listbase_count(&m->head.values)); +} + + +void WM_msgtypeinfo_init_static(wmMsgTypeInfo *msgtype_info) +{ + msgtype_info->gset.hash_fn = wm_msg_static_gset_hash; + msgtype_info->gset.cmp_fn = wm_msg_static_gset_cmp; + msgtype_info->gset.key_free_fn = wm_msg_static_gset_key_free; + msgtype_info->repr = wm_msg_static_repr; + + msgtype_info->msg_key_size = sizeof(wmMsgSubscribeKey_Static); +} + +/* -------------------------------------------------------------------------- */ + + +wmMsgSubscribeKey_Static *WM_msg_lookup_static(struct wmMsgBus *mbus, const wmMsgParams_Static *msg_key_params) +{ + wmMsgSubscribeKey_Static key_test; + key_test.msg.params = *msg_key_params; + return BLI_gset_lookup(mbus->messages_gset[WM_MSG_TYPE_STATIC], &key_test); +} + +void WM_msg_publish_static_params(struct wmMsgBus *mbus, const wmMsgParams_Static *msg_key_params) +{ + wmMsgSubscribeKey_Static *key = WM_msg_lookup_static(mbus, msg_key_params); + if (key) { + WM_msg_publish_with_key(mbus, &key->head); + } +} + +void WM_msg_publish_static(struct wmMsgBus *mbus, int event) +{ + WM_msg_publish_static_params(mbus, &(wmMsgParams_Static){ .event = event, }); +} + +void WM_msg_subscribe_static_params( + struct wmMsgBus *mbus, + const wmMsgParams_Static *msg_key_params, + const wmMsgSubscribeValue *msg_val_params, + const char *id_repr) +{ + wmMsgSubscribeKey_Static msg_key_test = {{NULL}}; + + /* use when added */ + msg_key_test.msg.head.id = id_repr; + msg_key_test.msg.head.type = WM_MSG_TYPE_STATIC; + /* for lookup */ + msg_key_test.msg.params = *msg_key_params; + + WM_msg_subscribe_with_key(mbus, &msg_key_test.head, msg_val_params); +} + +void WM_msg_subscribe_static( + struct wmMsgBus *mbus, + int event, + const wmMsgSubscribeValue *msg_val_params, + const char *id_repr) +{ + WM_msg_subscribe_static_params(mbus, &(const wmMsgParams_Static){ .event = event, }, msg_val_params, id_repr); +} diff --git a/source/blender/windowmanager/message_bus/wm_message_bus.h b/source/blender/windowmanager/message_bus/wm_message_bus.h new file mode 100644 index 00000000000..53f283cacd2 --- /dev/null +++ b/source/blender/windowmanager/message_bus/wm_message_bus.h @@ -0,0 +1,256 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/wm_message_bus.h + * \ingroup wm + */ + +#ifndef __WM_MESSAGE_BUS_H__ +#define __WM_MESSAGE_BUS_H__ + +struct GSet; +struct ID; +struct bContext; +struct wmMsg; + +/* opaque (don't expose outside wm_message_bus.c) */ +struct wmMsgBus; +struct wmMsgSubscribeKey; +struct wmMsgSubscribeValue; +struct wmMsgSubscribeValueLink; + +typedef void (*wmMsgNotifyFn)( + struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val); +typedef void (*wmMsgSubscribeValueFreeDataFn)( + struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val); + +/* Exactly what arguments here is not obvious. */ +typedef void (*wmMsgSubscribeValueUpdateIdFn)( + struct bContext *C, + struct wmMsgBus *mbus, + struct ID *id_src, struct ID *id_dst, + struct wmMsgSubscribeValue *msg_val); +enum { + WM_MSG_TYPE_RNA = 0, + WM_MSG_TYPE_STATIC = 1, +}; +#define WM_MSG_TYPE_NUM 2 + +typedef struct wmMsgTypeInfo { + struct { + unsigned int (*hash_fn)(const void *msg); + bool (*cmp_fn)(const void *a, const void *b); + void (*key_free_fn)(void *key); + } gset; + + void (*update_by_id)(struct wmMsgBus *mbus, struct ID *id_src, struct ID *id_dst); + void (*remove_by_id)(struct wmMsgBus *mbus, const struct ID *id); + void (*repr)(FILE *stream, const struct wmMsgSubscribeKey *msg_key); + + /* sizeof(wmMsgSubscribeKey_*) */ + uint msg_key_size; +} wmMsgTypeInfo; + +typedef struct wmMsg { + unsigned int type; +// #ifdef DEBUG + /* For debugging: '__func__:__LINE__'. */ + const char *id; +// #endif +} wmMsg; + +typedef struct wmMsgSubscribeKey { + /** Linked list for predicable ordering, otherwise we would depend on ghash bucketing. */ + struct wmMsgSubscribeKey *next, *prev; + ListBase values; + /* over-alloc, eg: wmMsgSubscribeKey_RNA */ + /* Last member will be 'wmMsg_*' */ +} wmMsgSubscribeKey; + +/** One of many in #wmMsgSubscribeKey.values */ +typedef struct wmMsgSubscribeValue { + struct wmMsgSubscribe *next, *prev; + + /** Handle, used to iterate and clear. */ + void *owner; + /** User data, can be whatever we like, free using the 'free_data' callback if it's owned. */ + void *user_data; + + /** Callbacks */ + wmMsgNotifyFn notify; + wmMsgSubscribeValueUpdateIdFn update_id; + wmMsgSubscribeValueFreeDataFn free_data; + + /** Keep this subscriber if possible. */ + uint is_persistent : 1; + /* tag to run when handling events, + * we may want option for immediate execution. */ + uint tag : 1; +} wmMsgSubscribeValue; + +/** One of many in #wmMsgSubscribeKey.values */ +typedef struct wmMsgSubscribeValueLink { + struct wmMsgSubscribeValueLink *next, *prev; + wmMsgSubscribeValue params; +} wmMsgSubscribeValueLink; + +void WM_msgbus_types_init(void); + +struct wmMsgBus *WM_msgbus_create(void); +void WM_msgbus_destroy(struct wmMsgBus *mbus); + +void WM_msgbus_clear_by_owner(struct wmMsgBus *mbus, void *owner); + +void WM_msg_dump(struct wmMsgBus *mbus, const char *info); +void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C); + +void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key); +wmMsgSubscribeKey *WM_msg_subscribe_with_key( + struct wmMsgBus *mbus, + const wmMsgSubscribeKey *msg_key_test, + const wmMsgSubscribeValue *msg_val_params); + +void WM_msg_id_update( + struct wmMsgBus *mbus, + struct ID *id_src, struct ID *id_dst); +void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id); + +/* -------------------------------------------------------------------------- */ +/* wm_message_bus_static.c */ + +enum { + /* generic window redraw */ + WM_MSG_STATICTYPE_WINDOW_DRAW = 0, + WM_MSG_STATICTYPE_SCREEN_EDIT = 1, + WM_MSG_STATICTYPE_FILE_READ = 2, +}; + +typedef struct wmMsgParams_Static { + int event; +} wmMsgParams_Static; + +typedef struct wmMsg_Static { + wmMsg head; /* keep first */ + wmMsgParams_Static params; +} wmMsg_Static; + +typedef struct wmMsgSubscribeKey_Static { + wmMsgSubscribeKey head; + wmMsg_Static msg; +} wmMsgSubscribeKey_Static; + +void WM_msgtypeinfo_init_static(wmMsgTypeInfo *msg_type); + +wmMsgSubscribeKey_Static *WM_msg_lookup_static( + struct wmMsgBus *mbus, const wmMsgParams_Static *msg_key_params); +void WM_msg_publish_static_params( + struct wmMsgBus *mbus, + const wmMsgParams_Static *msg_key_params); +void WM_msg_publish_static( + struct wmMsgBus *mbus, + /* wmMsgParams_Static (expanded) */ + int event); +void WM_msg_subscribe_static_params( + struct wmMsgBus *mbus, + const wmMsgParams_Static *msg_key_params, + const wmMsgSubscribeValue *msg_val_params, + const char *id_repr); +void WM_msg_subscribe_static( + struct wmMsgBus *mbus, + int event, + const wmMsgSubscribeValue *msg_val_params, + const char *id_repr); + +/* -------------------------------------------------------------------------- */ +/* wm_message_bus_rna.c */ + +typedef struct wmMsgParams_RNA { + /** when #PointerRNA.data & id.data are NULL. match against all. */ + PointerRNA ptr; + /** when NULL, match against any property. */ + const PropertyRNA *prop; + + /** + * Optional RNA data path for persistent RNA properties, ignore if NULL. + * otherwise it's allocated. + */ + char *data_path; +} wmMsgParams_RNA; + +typedef struct wmMsg_RNA { + wmMsg head; /* keep first */ + wmMsgParams_RNA params; +} wmMsg_RNA; + +typedef struct wmMsgSubscribeKey_RNA { + wmMsgSubscribeKey head; + wmMsg_RNA msg; +} wmMsgSubscribeKey_RNA; + +void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msg_type); + +wmMsgSubscribeKey_RNA *WM_msg_lookup_rna( + struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params); +void WM_msg_publish_rna_params( + struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params); +void WM_msg_publish_rna( + struct wmMsgBus *mbus, + /* wmMsgParams_RNA (expanded) */ + PointerRNA *ptr, PropertyRNA *prop); +void WM_msg_subscribe_rna_params( + struct wmMsgBus *mbus, + const wmMsgParams_RNA *msg_key_params, + const wmMsgSubscribeValue *msg_val_params, + const char *id_repr); +void WM_msg_subscribe_rna( + struct wmMsgBus *mbus, + PointerRNA *ptr, const PropertyRNA *prop, + const wmMsgSubscribeValue *msg_val_params, + const char *id_repr); + +/* ID variants */ +void WM_msg_subscribe_ID( + struct wmMsgBus *mbus, struct ID *id, const wmMsgSubscribeValue *msg_val_params, + const char *id_repr); +void WM_msg_publish_ID( + struct wmMsgBus *mbus, struct ID *id); + +/* Anonymous variants (for convenience) */ +#define WM_msg_subscribe_rna_anon_type(mbus, type_, value) { \ + WM_msg_subscribe_rna_params( \ + mbus, \ + &(const wmMsgParams_RNA){ \ + .ptr = (PointerRNA){.type = &RNA_##type_}, \ + .prop = NULL, \ + }, \ + value, __func__); \ +} ((void)0) +#define WM_msg_subscribe_rna_anon_prop(mbus, type_, prop_, value) { \ + extern PropertyRNA rna_##type_##_##prop_; \ + WM_msg_subscribe_rna_params( \ + mbus, \ + &(const wmMsgParams_RNA){ \ + .ptr = (PointerRNA){.type = &RNA_##type_}, \ + .prop = &rna_##type_##_##prop_, \ + }, \ + value, __func__); \ +} ((void)0) + +#endif /* __WM_MESSAGE_BUS_H__ */ diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index ce6c0867f1d..e7edeed6a64 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -146,6 +146,8 @@ struct wmManipulatorMap; # pragma GCC diagnostic ignored "-Wunused-parameter" #endif +#include <stdio.h> /* FILE */ + #include "../../intern/dualcon/dualcon.h" #include "../../intern/elbeem/extern/elbeem.h" #include "../blender/blenkernel/BKE_modifier.h" @@ -195,6 +197,7 @@ struct wmManipulatorMap; #include "../blender/draw/DRW_engine.h" #include "../blender/windowmanager/WM_api.h" #include "../blender/windowmanager/WM_types.h" +#include "../blender/windowmanager/WM_message.h" /* -------------------------------------------------------------------- */ @@ -233,7 +236,6 @@ bool BPY_string_is_keyword(const char *str) { return false; } #define RET_ARG(arg) {STUB_ASSERT(0); return arg; } #define RET_NONE {STUB_ASSERT(0);} - /* -------------------------------------------------------------------- */ /* Stubs */ @@ -342,6 +344,9 @@ void WM_jobs_kill_all_except(struct wmWindowManager *wm, void *owner) RET_NONE void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports) RET_NONE +void WM_msg_publish_rna(struct wmMsgBus *mbus, PointerRNA *ptr, PropertyRNA *prop) RET_NONE + + char *WM_clipboard_text_get(bool selection, int *r_len) RET_NULL char *WM_clipboard_text_get_firstline(bool selection, int *r_len) RET_NULL void WM_clipboard_text_set(const char *buf, bool selection) RET_NONE diff --git a/source/creator/creator.c b/source/creator/creator.c index 4e090b0b19f..78bab14cd96 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -231,7 +231,8 @@ int main( /* --- end declarations --- */ - /* ensure we free data on early-exit */ struct CreatorAtExitData app_init_data = {NULL}; + /* ensure we free data on early-exit */ + struct CreatorAtExitData app_init_data = {NULL}; BKE_blender_atexit_register(callback_main_atexit, &app_init_data); #ifdef WIN32 diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index ad9855586ee..acd425e788a 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -147,6 +147,7 @@ extern "C" { #include "BKE_customdata.h" #include "BKE_cdderivedmesh.h" #include "BKE_DerivedMesh.h" +#include "BKE_group.h" #include "BKE_layer.h" #include "BKE_material.h" /* give_current_material */ #include "BKE_image.h" @@ -2052,10 +2053,8 @@ void BL_ConvertBlenderObjects(struct Main* maggie, for (git=tempglist.begin(); git!=tempglist.end(); git++) { Group* group = *git; - GroupObject* go; - for (go=(GroupObject*)group->gobject.first; go; go=(GroupObject*)go->next) + FOREACH_GROUP_OBJECT(group, blenderobject) { - Object* blenderobject = go->ob; if (converter->FindGameObject(blenderobject) == NULL) { allblobj.insert(blenderobject); @@ -2090,6 +2089,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, } } } + FOREACH_GROUP_OBJECT_END } } } diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index b3061087344..48b50d24975 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -105,6 +105,7 @@ #include "KX_Light.h" +#include "BKE_group.h" #include "BLI_task.h" static void *KX_SceneReplicationFunc(SG_IObject* node,void* gameobj,void* scene) @@ -720,7 +721,6 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) KX_GameObject* gameobj; Object* blgroupobj = groupobj->GetBlenderObject(); Group* group; - GroupObject *go; vector<KX_GameObject*> duplilist; if (!groupobj->GetSGNode() || @@ -738,9 +738,9 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) m_groupGameObjects.clear(); group = blgroupobj->dup_group; - for (go=(GroupObject*)group->gobject.first; go; go=(GroupObject*)go->next) + FOREACH_GROUP_BASE(group, base) { - Object* blenderobj = go->ob; + Object *blenderobj = base->object; if (blgroupobj == blenderobj) // this check is also in group_duplilist() continue; @@ -755,13 +755,13 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) gameobj->SetBlenderGroupObject(blgroupobj); - if ((blenderobj->lay & group->layer)==0) - { + if ((base->flag & BASE_VISIBLED) == 0) { // object is not visible in the 3D view, will not be instantiated continue; } m_groupGameObjects.insert(gameobj); } + FOREACH_GROUP_BASE_END set<CValue*>::iterator oit; for (oit=m_groupGameObjects.begin(); oit != m_groupGameObjects.end(); oit++) diff --git a/tests/python/bl_alembic_import_test.py b/tests/python/bl_alembic_import_test.py index 5062e8ff073..e9499fb08f0 100644 --- a/tests/python/bl_alembic_import_test.py +++ b/tests/python/bl_alembic_import_test.py @@ -184,7 +184,7 @@ class SimpleImportTest(AbstractAlembicTest): # Check that the file loaded ok. bpy.context.scene.frame_set(6) scene = bpy.context.scene - layer = scene.render_layers[scene.active_layer] + layer = scene.view_layers[scene.active_layer] mesh = plane.to_mesh(scene, layer, True, 'RENDER') self.assertAlmostEqual(-1, mesh.vertices[0].co.x) self.assertAlmostEqual(-1, mesh.vertices[0].co.y) diff --git a/tests/python/view_layer/CMakeLists.txt b/tests/python/view_layer/CMakeLists.txt index e5b271dcb1e..22cfcd344f3 100644 --- a/tests/python/view_layer/CMakeLists.txt +++ b/tests/python/view_layer/CMakeLists.txt @@ -87,6 +87,10 @@ VIEW_LAYER_TEST(evaluation_selectability_c) VIEW_LAYER_TEST(evaluation_selectability_d) VIEW_LAYER_TEST(evaluation_selectability_e) VIEW_LAYER_TEST(evaluation_selectability_f) +VIEW_LAYER_TEST(group_a) +VIEW_LAYER_TEST(group_b) +VIEW_LAYER_TEST(group_c) +VIEW_LAYER_TEST(group_d) VIEW_LAYER_TEST(object_add_cylinder) VIEW_LAYER_TEST(object_add_empty) VIEW_LAYER_TEST(object_add_torus) diff --git a/tests/python/view_layer/test_evaluation_selectability_a.py b/tests/python/view_layer/test_evaluation_selectability_a.py index 4dba8ab224d..82404d54fe3 100644 --- a/tests/python/view_layer/test_evaluation_selectability_a.py +++ b/tests/python/view_layer/test_evaluation_selectability_a.py @@ -21,13 +21,13 @@ class UnitTesting(ViewLayerTesting): import bpy scene = bpy.context.scene - workspace = bpy.context.workspace + window = bpy.context.window cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh')) layer = scene.view_layers.new('Selectability Test') layer.collections.unlink(layer.collections[0]) scene.view_layers.active = layer - workspace.view_layer = layer + window.view_layer = layer scene_collection_mom = scene.master_collection.collections.new("Mom") scene_collection_kid = scene_collection_mom.collections.new("Kid") diff --git a/tests/python/view_layer/test_evaluation_selectability_b.py b/tests/python/view_layer/test_evaluation_selectability_b.py index 9cb2cd76f17..f05ab5de2e1 100644 --- a/tests/python/view_layer/test_evaluation_selectability_b.py +++ b/tests/python/view_layer/test_evaluation_selectability_b.py @@ -21,13 +21,13 @@ class UnitTesting(ViewLayerTesting): import bpy scene = bpy.context.scene - workspace = bpy.context.workspace + window = bpy.context.window cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh')) layer = scene.view_layers.new('Selectability Test') layer.collections.unlink(layer.collections[0]) scene.view_layers.active = layer - workspace.view_layer = layer + window.view_layer = layer scene_collection_mom = scene.master_collection.collections.new("Mom") scene_collection_kid = scene_collection_mom.collections.new("Kid") diff --git a/tests/python/view_layer/test_evaluation_selectability_c.py b/tests/python/view_layer/test_evaluation_selectability_c.py index 9536aaf4edc..71452bc1354 100644 --- a/tests/python/view_layer/test_evaluation_selectability_c.py +++ b/tests/python/view_layer/test_evaluation_selectability_c.py @@ -21,13 +21,13 @@ class UnitTesting(ViewLayerTesting): import bpy scene = bpy.context.scene - workspace = bpy.context.workspace + window = bpy.context.window cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh')) layer = scene.view_layers.new('Selectability Test') layer.collections.unlink(layer.collections[0]) scene.view_layers.active = layer - workspace.view_layer = layer + window.view_layer = layer scene_collection_mom = scene.master_collection.collections.new("Mom") scene_collection_kid = scene_collection_mom.collections.new("Kid") diff --git a/tests/python/view_layer/test_evaluation_selectability_d.py b/tests/python/view_layer/test_evaluation_selectability_d.py index ddfec6132e6..529a36c101e 100644 --- a/tests/python/view_layer/test_evaluation_selectability_d.py +++ b/tests/python/view_layer/test_evaluation_selectability_d.py @@ -21,13 +21,13 @@ class UnitTesting(ViewLayerTesting): import bpy scene = bpy.context.scene - workspace = bpy.context.workspace + window = bpy.context.window cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh')) layer = scene.view_layers.new('Selectability Test') layer.collections.unlink(layer.collections[0]) scene.view_layers.active = layer - workspace.view_layer = layer + window.view_layer = layer scene_collection_mom = scene.master_collection.collections.new("Mom") scene_collection_kid = scene_collection_mom.collections.new("Kid") diff --git a/tests/python/view_layer/test_evaluation_selectability_e.py b/tests/python/view_layer/test_evaluation_selectability_e.py index 02017321734..a26fa0df304 100644 --- a/tests/python/view_layer/test_evaluation_selectability_e.py +++ b/tests/python/view_layer/test_evaluation_selectability_e.py @@ -21,13 +21,13 @@ class UnitTesting(ViewLayerTesting): import bpy scene = bpy.context.scene - workspace = bpy.context.workspace + window = bpy.context.window cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh')) layer = scene.view_layers.new('Selectability Test') layer.collections.unlink(layer.collections[0]) scene.view_layers.active = layer - workspace.view_layer = layer + window.view_layer = layer scene_collection_mom = scene.master_collection.collections.new("Mom") scene_collection_kid = scene_collection_mom.collections.new("Kid") diff --git a/tests/python/view_layer/test_evaluation_visibility_a.py b/tests/python/view_layer/test_evaluation_visibility_a.py index ad9b92dd937..3ae567df82c 100644 --- a/tests/python/view_layer/test_evaluation_visibility_a.py +++ b/tests/python/view_layer/test_evaluation_visibility_a.py @@ -21,13 +21,13 @@ class UnitTesting(ViewLayerTesting): import bpy scene = bpy.context.scene - workspace = bpy.context.workspace + window = bpy.context.window cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh')) layer = scene.view_layers.new('Visibility Test') layer.collections.unlink(layer.collections[0]) scene.view_layers.active = layer - workspace.view_layer = layer + window.view_layer = layer scene_collection_mom = scene.master_collection.collections.new("Mom") scene_collection_kid = scene.master_collection.collections.new("Kid") diff --git a/tests/python/view_layer/test_evaluation_visibility_b.py b/tests/python/view_layer/test_evaluation_visibility_b.py index 1a3c6605027..93ace3928f2 100644 --- a/tests/python/view_layer/test_evaluation_visibility_b.py +++ b/tests/python/view_layer/test_evaluation_visibility_b.py @@ -21,13 +21,13 @@ class UnitTesting(ViewLayerTesting): import bpy scene = bpy.context.scene - workspace = bpy.context.workspace + window = bpy.context.window cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh')) layer = scene.view_layers.new('Visibility Test') layer.collections.unlink(layer.collections[0]) scene.view_layers.active = layer - workspace.view_layer = layer + window.view_layer = layer scene_collection_mom = scene.master_collection.collections.new("Mom") scene_collection_kid = scene_collection_mom.collections.new("Kid") diff --git a/tests/python/view_layer/test_evaluation_visibility_c.py b/tests/python/view_layer/test_evaluation_visibility_c.py index 7285c1cdea5..05db8577167 100644 --- a/tests/python/view_layer/test_evaluation_visibility_c.py +++ b/tests/python/view_layer/test_evaluation_visibility_c.py @@ -21,13 +21,13 @@ class UnitTesting(ViewLayerTesting): import bpy scene = bpy.context.scene - workspace = bpy.context.workspace + window = bpy.context.window cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh')) layer = scene.view_layers.new('Visibility Test') layer.collections.unlink(layer.collections[0]) scene.view_layers.active = layer - workspace.view_layer = layer + window.view_layer = layer scene_collection_mom = scene.master_collection.collections.new("Mom") scene_collection_kid = scene_collection_mom.collections.new("Kid") diff --git a/tests/python/view_layer/test_evaluation_visibility_d.py b/tests/python/view_layer/test_evaluation_visibility_d.py index ed5d452e4ca..e08ab4d571e 100644 --- a/tests/python/view_layer/test_evaluation_visibility_d.py +++ b/tests/python/view_layer/test_evaluation_visibility_d.py @@ -21,13 +21,13 @@ class UnitTesting(ViewLayerTesting): import bpy scene = bpy.context.scene - workspace = bpy.context.workspace + window = bpy.context.window cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh')) layer = scene.view_layers.new('Visibility Test') layer.collections.unlink(layer.collections[0]) scene.view_layers.active = layer - workspace.view_layer = layer + window.view_layer = layer scene_collection_mom = scene.master_collection.collections.new("Mom") scene_collection_kid = scene_collection_mom.collections.new("Kid") diff --git a/tests/python/view_layer/test_evaluation_visibility_e.py b/tests/python/view_layer/test_evaluation_visibility_e.py index 006836f27b9..b54238337c6 100644 --- a/tests/python/view_layer/test_evaluation_visibility_e.py +++ b/tests/python/view_layer/test_evaluation_visibility_e.py @@ -21,13 +21,13 @@ class UnitTesting(ViewLayerTesting): import bpy scene = bpy.context.scene - workspace = bpy.context.workspace + window = bpy.context.window cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh')) layer = scene.view_layers.new('Visibility Test') layer.collections.unlink(layer.collections[0]) scene.view_layers.active = layer - workspace.view_layer = layer + window.view_layer = layer scene_collection_mom = scene.master_collection.collections.new("Mom") scene_collection_kid = scene_collection_mom.collections.new("Kid") diff --git a/tests/python/view_layer/test_evaluation_visibility_f.py b/tests/python/view_layer/test_evaluation_visibility_f.py index bc0050d8efa..e532a19e3ef 100644 --- a/tests/python/view_layer/test_evaluation_visibility_f.py +++ b/tests/python/view_layer/test_evaluation_visibility_f.py @@ -21,13 +21,13 @@ class UnitTesting(ViewLayerTesting): import bpy scene = bpy.context.scene - workspace = bpy.context.workspace + window = bpy.context.window cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh')) layer = scene.view_layers.new('Visibility Test') layer.collections.unlink(layer.collections[0]) scene.view_layers.active = layer - workspace.view_layer = layer + window.view_layer = layer scene_collection_mom = scene.master_collection.collections.new("Mom") scene_collection_kid = scene_collection_mom.collections.new("Kid") diff --git a/tests/python/view_layer/test_group_a.py b/tests/python/view_layer/test_group_a.py new file mode 100644 index 00000000000..6e1b83efbe5 --- /dev/null +++ b/tests/python/view_layer/test_group_a.py @@ -0,0 +1,46 @@ +# ############################################################ +# Importing - Same For All Render Layer Tests +# ############################################################ + +import unittest +import os +import sys + +from view_layer_common import * + + +# ############################################################ +# Testing +# ############################################################ + +class UnitTesting(ViewLayerTesting): + def test_group_create_basic(self): + """ + See if the creation of new groups is not crashing anything. + """ + import bpy + scene = bpy.context.scene + layer_collection = bpy.context.layer_collection + + # Cleanup Viewport view layer + # technically this shouldn't be needed but + # for now we need it because depsgraph build all the view layers + # at once. + + while len(scene.view_layers) > 1: + scene.view_layers.remove(scene.view_layers[1]) + + # create group + group = layer_collection.create_group() + + # update depsgraph + scene.update() + + +# ############################################################ +# Main - Same For All Render Layer Tests +# ############################################################ + +if __name__ == '__main__': + UnitTesting._extra_arguments = setup_extra_arguments(__file__) + unittest.main() diff --git a/tests/python/view_layer/test_group_b.py b/tests/python/view_layer/test_group_b.py new file mode 100644 index 00000000000..6a4478aeba8 --- /dev/null +++ b/tests/python/view_layer/test_group_b.py @@ -0,0 +1,72 @@ +# ############################################################ +# Importing - Same For All Render Layer Tests +# ############################################################ + +import unittest +import os +import sys + +from view_layer_common import * + + +# ############################################################ +# Testing +# ############################################################ + +class UnitTesting(ViewLayerTesting): + def test_group_create_basic(self): + """ + See if the creation of new groups is preserving visibility flags + from the original collections. + """ + import bpy + scene = bpy.context.scene + + # clean slate + self.cleanup_tree() + + master_collection = scene.master_collection + grandma = master_collection.collections.new('бабушка') + mom = grandma.collections.new('матушка') + + child = bpy.data.objects.new("Child", None) + mom.objects.link(child) + + grandma_layer_collection = scene.view_layers[0].collections.link(grandma) + mom_layer_collection = grandma_layer_collection.collections[0] + + grandma_layer_collection.hide = False + grandma_layer_collection.hide = False + mom_layer_collection.hide = True + mom_layer_collection.hide_select = False + + # update depsgraph + scene.update() + + # create group + group = grandma_layer_collection.create_group() + + # update depsgraph + scene.update() + + # compare + self.assertEqual(len(group.view_layer.collections), 1) + grandma_group_layer = group.view_layer.collections[0] + + self.assertEqual(grandma_group_layer.hide, False) + self.assertEqual(grandma_group_layer.hide_select, False) + + self.assertEqual(len(grandma_group_layer.collections), 1) + mom_group_layer = grandma_group_layer.collections[0] + + self.assertEqual(mom_group_layer.hide, True) + self.assertEqual(mom_group_layer.hide_select, False) + + +# ############################################################ +# Main - Same For All Render Layer Tests +# ############################################################ + +if __name__ == '__main__': + UnitTesting._extra_arguments = setup_extra_arguments(__file__) + unittest.main() diff --git a/tests/python/view_layer/test_group_c.py b/tests/python/view_layer/test_group_c.py new file mode 100644 index 00000000000..69feab1a56e --- /dev/null +++ b/tests/python/view_layer/test_group_c.py @@ -0,0 +1,56 @@ +# ############################################################ +# Importing - Same For All Render Layer Tests +# ############################################################ + +import unittest +import os +import sys + +from view_layer_common import * + + +# ############################################################ +# Testing +# ############################################################ + +class UnitTesting(ViewLayerTesting): + def test_group_create_basic(self): + """ + More advanced creation of group from a collection not directly linked + to the scene layer. + """ + import bpy + scene = bpy.context.scene + + # clean slate + self.cleanup_tree() + + children = [bpy.data.objects.new("Child", None) for i in range(3)] + master_collection = scene.master_collection + + grandma_scene_collection = master_collection.collections.new('Grand-Mother') + mom_scene_collection = grandma_scene_collection.collections.new('Mother') + + grandma_scene_collection.objects.link(children[0]) + mom_scene_collection.objects.link(children[1]) + + grandma_layer_collection = scene.view_layers[0].collections.link(grandma_scene_collection) + mom_layer_collection = grandma_layer_collection.collections[mom_scene_collection.name] + + # update depsgraph + scene.update() + + # create group + group = mom_layer_collection.create_group() + + # update depsgraph + scene.update() + + +# ############################################################ +# Main - Same For All Render Layer Tests +# ############################################################ + +if __name__ == '__main__': + UnitTesting._extra_arguments = setup_extra_arguments(__file__) + unittest.main() diff --git a/tests/python/view_layer/test_group_d.py b/tests/python/view_layer/test_group_d.py new file mode 100644 index 00000000000..6f54ca5340a --- /dev/null +++ b/tests/python/view_layer/test_group_d.py @@ -0,0 +1,76 @@ +# ############################################################ +# Importing - Same For All Render Layer Tests +# ############################################################ + +import unittest +import os +import sys + +from view_layer_common import * + + +# ############################################################ +# Testing +# ############################################################ + +class UnitTesting(ViewLayerTesting): + def test_group_write_load(self): + """ + See if saving/loading is working for groups + """ + import bpy + scene = bpy.context.scene + layer_collection = bpy.context.layer_collection + + while len(scene.view_layers) > 1: + scene.view_layers.remove(scene.view_layers[1]) + + # create group + group = layer_collection.create_group() + + self.assertEqual(1, len(bpy.data.groups)) + self.assertEqual(1, bpy.data.groups[0].users) + self.assertEqual(3, len(bpy.data.groups[0].objects)) + + import os + import tempfile + with tempfile.TemporaryDirectory() as dirpath: + filepath = os.path.join(dirpath, 'layers.blend') + + for i in range(3): + # save and re-open file + bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath) + bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath) + + self.assertEqual(1, len(bpy.data.groups)) + self.assertEqual(1, bpy.data.groups[0].users) + self.assertEqual(3, len(bpy.data.groups[0].objects)) + + + # empty the group of objects + group = bpy.data.groups[0] + while group.objects: + group.view_layer.collections[0].collection.objects.unlink(group.objects[0]) + + # save and re-open file + bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath) + bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath) + + self.assertEqual(1, len(bpy.data.groups)) + self.assertEqual(0, bpy.data.groups[0].users) + self.assertEqual(0, len(bpy.data.groups[0].objects)) + + # save and re-open file + bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath) + bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath) + + self.assertEqual(0, len(bpy.data.groups)) + + +# ############################################################ +# Main - Same For All Render Layer Tests +# ############################################################ + +if __name__ == '__main__': + UnitTesting._extra_arguments = setup_extra_arguments(__file__) + unittest.main() diff --git a/tests/python/view_layer/test_object_copy.py b/tests/python/view_layer/test_object_copy.py index eab2c73f3b3..a15b9e2c941 100644 --- a/tests/python/view_layer/test_object_copy.py +++ b/tests/python/view_layer/test_object_copy.py @@ -42,7 +42,7 @@ class UnitTesting(ViewLayerTesting): layer.collections.link(subzero) scene.view_layers.active_index = len(scene.view_layers) - 1 - bpy.context.workspace.view_layer = bpy.context.scene.view_layers['Fresh new Layer'] + bpy.context.window.view_layer = bpy.context.scene.view_layers['Fresh new Layer'] if mode == 'DUPLICATE': # assuming the latest layer is the active layer diff --git a/tests/python/view_layer/test_object_link_b.py b/tests/python/view_layer/test_object_link_b.py index 3a7f9438071..361ea7fc3a5 100644 --- a/tests/python/view_layer/test_object_link_b.py +++ b/tests/python/view_layer/test_object_link_b.py @@ -20,7 +20,7 @@ class UnitTesting(ViewLayerTesting): """ import bpy bpy.context.scene.view_layers.active_index = len(bpy.context.scene.view_layers) - 1 - bpy.context.workspace.view_layer = bpy.context.scene.view_layers['Viewport'] + bpy.context.window.view_layer = bpy.context.scene.view_layers['Viewport'] master_collection = bpy.context.scene_collection self.do_object_link(master_collection) diff --git a/tests/python/view_layer/test_operator_context.py b/tests/python/view_layer/test_operator_context.py index 4c665b1d960..ff751bc0fa5 100644 --- a/tests/python/view_layer/test_operator_context.py +++ b/tests/python/view_layer/test_operator_context.py @@ -88,11 +88,11 @@ class UnitTesting(ViewLayerTesting): layer.collections.active_index = 3 self.assertEqual(layer.collections.active.name, 'scorpion') - # Change active scene layer (do it for workspace too just to don't get mangled in workspace bugs) + # Change active scene layer (do it for window too just to don't get mangled in window bugs) scene = bpy.context.scene scene.view_layers.active_index = len(scene.view_layers) - 2 self.assertEqual(scene.view_layers.active.name, "Viewport") - bpy.context.workspace.view_layer = bpy.context.scene.view_layers['Viewport'] + bpy.context.window.view_layer = bpy.context.scene.view_layers['Viewport'] # old layer self.assertEqual(bpy.ops.testing.sample(view_layer='Viewport', use_verbose=True), {'FINISHED'}) diff --git a/tests/python/view_layer/view_layer_common.py b/tests/python/view_layer/view_layer_common.py index 166d683da5a..1d9d321e532 100644 --- a/tests/python/view_layer/view_layer_common.py +++ b/tests/python/view_layer/view_layer_common.py @@ -760,7 +760,7 @@ class Clay: layer = self._scene.view_layers.new('Evaluation Test') layer.collections.unlink(layer.collections[0]) self._scene.view_layers.active = layer - bpy.context.workspace.view_layer = layer + bpy.context.window.view_layer = layer # remove all other layers for layer_iter in self._scene.view_layers: |