diff --git a/CMakeLists.txt b/CMakeLists.txt index 020c95cee0c..8cd3afc2e12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -521,7 +521,8 @@ endif() if(NOT APPLE) option(WITH_CYCLES_DEVICE_HIP "Enable Cycles AMD HIP support" ON) option(WITH_CYCLES_HIP_BINARIES "Build Cycles AMD HIP binaries" OFF) - set(CYCLES_HIP_BINARIES_ARCH gfx900 gfx906 gfx90c gfx902 gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 gfx1035 gfx1100 gfx1101 gfx1102 CACHE STRING "AMD HIP architectures to build binaries for") + # Radeon VII (gfx906) not currently working with HIP SDK, so left out of the list. + set(CYCLES_HIP_BINARIES_ARCH gfx900 gfx90c gfx902 gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 gfx1035 gfx1100 gfx1101 gfx1102 CACHE STRING "AMD HIP architectures to build binaries for") mark_as_advanced(WITH_CYCLES_DEVICE_HIP) mark_as_advanced(CYCLES_HIP_BINARIES_ARCH) endif() diff --git a/build_files/build_environment/cmake/dpcpp.cmake b/build_files/build_environment/cmake/dpcpp.cmake index 272a360fc67..e3c8bbeee98 100644 --- a/build_files/build_environment/cmake/dpcpp.cmake +++ b/build_files/build_environment/cmake/dpcpp.cmake @@ -113,8 +113,14 @@ add_dependencies( if(BUILD_MODE STREQUAL Release AND WIN32) ExternalProject_Add_Step(external_dpcpp after_install - COMMAND ${CMAKE_COMMAND} -E rm -f ${LIBDIR}/dpcpp/bin/clang-cl.exe - COMMAND ${CMAKE_COMMAND} -E rm -f ${LIBDIR}/dpcpp/bin/clang-cpp.exe COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/dpcpp ${HARVEST_TARGET}/dpcpp + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/clang-cl.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/clang-cpp.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/clang.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/ld.lld.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/ld64.lld.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/lld.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/lld-link.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/wasm-ld.exe ) endif() diff --git a/build_files/cmake/Modules/FindHIP.cmake b/build_files/cmake/Modules/FindHIP.cmake index 9625a91d280..c6358c9ef7b 100644 --- a/build_files/cmake/Modules/FindHIP.cmake +++ b/build_files/cmake/Modules/FindHIP.cmake @@ -37,18 +37,24 @@ elseif(HIP_HIPCC_EXECUTABLE) set(HIP_VERSION_MINOR 0) set(HIP_VERSION_PATCH 0) + if(WIN32) + set(_hipcc_executable ${HIP_HIPCC_EXECUTABLE}.bat) + else() + set(_hipcc_executable ${HIP_HIPCC_EXECUTABLE}) + endif() + # Get version from the output. - execute_process(COMMAND ${HIP_HIPCC_EXECUTABLE} --version - OUTPUT_VARIABLE HIP_VERSION_RAW + execute_process(COMMAND ${_hipcc_executable} --version + OUTPUT_VARIABLE _hip_version_raw ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) # Parse parts. - if(HIP_VERSION_RAW MATCHES "HIP version: .*") + if(_hip_version_raw MATCHES "HIP version: .*") # Strip the HIP prefix and get list of individual version components. string(REGEX REPLACE ".*HIP version: ([.0-9]+).*" "\\1" - HIP_SEMANTIC_VERSION "${HIP_VERSION_RAW}") + HIP_SEMANTIC_VERSION "${_hip_version_raw}") string(REPLACE "." ";" HIP_VERSION_PARTS "${HIP_SEMANTIC_VERSION}") list(LENGTH HIP_VERSION_PARTS NUM_HIP_VERSION_PARTS) @@ -71,7 +77,13 @@ elseif(HIP_HIPCC_EXECUTABLE) # Construct full semantic version. set(HIP_VERSION "${HIP_VERSION_MAJOR}.${HIP_VERSION_MINOR}.${HIP_VERSION_PATCH}") - unset(HIP_VERSION_RAW) + unset(_hip_version_raw) + unset(_hipcc_executable) else() set(HIP_FOUND FALSE) endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(HIP + REQUIRED_VARS HIP_HIPCC_EXECUTABLE + VERSION_VAR HIP_VERSION) diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake index bcee440adcb..61ec88c879e 100644 --- a/build_files/cmake/config/blender_release.cmake +++ b/build_files/cmake/config/blender_release.cmake @@ -82,7 +82,7 @@ if(NOT APPLE) set(WITH_CYCLES_DEVICE_OPTIX ON CACHE BOOL "" FORCE) set(WITH_CYCLES_CUDA_BINARIES ON CACHE BOOL "" FORCE) set(WITH_CYCLES_CUBIN_COMPILER OFF CACHE BOOL "" FORCE) - set(WITH_CYCLES_HIP_BINARIES OFF CACHE BOOL "" FORCE) + set(WITH_CYCLES_HIP_BINARIES ON CACHE BOOL "" FORCE) set(WITH_CYCLES_DEVICE_ONEAPI ON CACHE BOOL "" FORCE) set(WITH_CYCLES_ONEAPI_BINARIES ON CACHE BOOL "" FORCE) endif() diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 20114191c52..33e817da449 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -174,7 +174,7 @@ if(SYSTEMSTUBS_LIBRARY) list(APPEND PLATFORM_LINKLIBS SystemStubs) endif() -string(APPEND PLATFORM_CFLAGS " -pipe -funsigned-char -fno-strict-aliasing") +string(APPEND PLATFORM_CFLAGS " -pipe -funsigned-char -fno-strict-aliasing -ffp-contract=off") set(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework Metal -framework QuartzCore" ) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 72de4c59203..a56363dbd43 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -803,8 +803,7 @@ if(CMAKE_COMPILER_IS_GNUCC) # Automatically turned on when building with "-march=native". This is # explicitly turned off here as it will make floating point math give a bit # different results. This will lead to automated test failures. So disable - # this until we support it. Seems to default to off in clang and the intel - # compiler. + # this until we support it. set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -ffp-contract=off") # `maybe-uninitialized` is unreliable in release builds, but fine in debug builds. @@ -892,7 +891,7 @@ if(CMAKE_COMPILER_IS_GNUCC) # CLang is the same as GCC for now. elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") - set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing") + set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -ffp-contract=off") if(WITH_LINKER_MOLD AND _IS_LINKER_DEFAULT) find_program(MOLD_BIN "mold") diff --git a/build_files/config/pipeline_config.yaml b/build_files/config/pipeline_config.yaml index 11a095e10ba..832a9b119e6 100644 --- a/build_files/config/pipeline_config.yaml +++ b/build_files/config/pipeline_config.yaml @@ -9,7 +9,7 @@ buildbot: cuda11: version: '11.4.1' hip: - version: '5.3.22480' + version: '5.5.30571' optix: version: '7.3.0' ocloc: diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 79356c1c67e..9d16b4983a7 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1683,16 +1683,16 @@ class CyclesPreferences(bpy.types.AddonPreferences): col.label(text=iface_("and NVIDIA driver version %s or newer") % driver_version, icon='BLANK1', translate=False) elif device_type == 'HIP': - if True: - col.label(text="HIP temporarily disabled due to compiler bugs", icon='BLANK1') - else: - import sys - if sys.platform[:3] == "win": - driver_version = "21.Q4" - col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1') - col.label(text=iface_("and AMD Radeon Pro %s driver or newer") % driver_version, - icon='BLANK1', translate=False) - elif sys.platform.startswith("linux"): + import sys + if sys.platform[:3] == "win": + driver_version = "21.Q4" + col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1') + col.label(text=iface_("and AMD Radeon Pro %s driver or newer") % driver_version, + icon='BLANK1', translate=False) + elif sys.platform.startswith("linux"): + if True: + col.label(text="HIP temporarily disabled due to compiler bugs", icon='BLANK1') + else: driver_version = "22.10" col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1') col.label(text=iface_("and AMD driver version %s or newer") % driver_version, icon='BLANK1', diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake index b10aeec8bdf..536639b3154 100644 --- a/intern/cycles/cmake/external_libs.cmake +++ b/intern/cycles/cmake/external_libs.cmake @@ -42,15 +42,19 @@ endif() ########################################################################### if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP) - set(WITH_CYCLES_HIP_BINARIES OFF) - message(STATUS "HIP temporarily disabled due to compiler bugs") + if(UNIX) + # Disabled until there is a HIP 5.5 release for Linux. + set(WITH_CYCLES_HIP_BINARIES OFF) + message(STATUS "HIP temporarily disabled due to compiler bugs") + else() + # Need at least HIP 5.5 to solve compiler bug affecting the kernel. + find_package(HIP 5.5.0) + set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES) - # find_package(HIP) - # set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES) - - # if(HIP_FOUND) - # message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})") - # endif() + if(HIP_FOUND) + message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})") + endif() + endif() endif() if(NOT WITH_HIP_DYNLOAD) diff --git a/intern/cycles/device/hip/device.cpp b/intern/cycles/device/hip/device.cpp index d3566347834..c853114cea7 100644 --- a/intern/cycles/device/hip/device.cpp +++ b/intern/cycles/device/hip/device.cpp @@ -137,7 +137,7 @@ void device_hip_info(vector &devices) info.num = num; info.has_nanovdb = true; - info.has_light_tree = false; + info.has_light_tree = true; info.denoisers = 0; info.has_gpu_queue = true; diff --git a/intern/cycles/device/oneapi/device_impl.cpp b/intern/cycles/device/oneapi/device_impl.cpp index 8fca166e665..5cb6a6222ef 100644 --- a/intern/cycles/device/oneapi/device_impl.cpp +++ b/intern/cycles/device/oneapi/device_impl.cpp @@ -866,9 +866,9 @@ char *OneapiDevice::device_capabilities() sycl::id<3> max_work_item_sizes = device.get_info>(); - WRITE_ATTR("max_work_item_sizes_dim0", ((size_t)max_work_item_sizes.get(0))) - WRITE_ATTR("max_work_item_sizes_dim1", ((size_t)max_work_item_sizes.get(1))) - WRITE_ATTR("max_work_item_sizes_dim2", ((size_t)max_work_item_sizes.get(2))) + WRITE_ATTR(max_work_item_sizes_dim0, ((size_t)max_work_item_sizes.get(0))) + WRITE_ATTR(max_work_item_sizes_dim1, ((size_t)max_work_item_sizes.get(1))) + WRITE_ATTR(max_work_item_sizes_dim2, ((size_t)max_work_item_sizes.get(2))) GET_NUM_ATTR(max_work_group_size) GET_NUM_ATTR(max_num_sub_groups) @@ -891,7 +891,7 @@ char *OneapiDevice::device_capabilities() GET_NUM_ATTR(native_vector_width_half) size_t max_clock_frequency = device.get_info(); - WRITE_ATTR("max_clock_frequency", max_clock_frequency) + WRITE_ATTR(max_clock_frequency, max_clock_frequency) GET_NUM_ATTR(address_bits) GET_NUM_ATTR(max_mem_alloc_size) @@ -900,7 +900,7 @@ char *OneapiDevice::device_capabilities() * supported so we always return false, even if device supports HW texture usage acceleration. */ bool image_support = false; - WRITE_ATTR("image_support", (size_t)image_support) + WRITE_ATTR(image_support, (size_t)image_support) GET_NUM_ATTR(max_parameter_size) GET_NUM_ATTR(mem_base_addr_align) diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 58c3d95deb5..4fa379e4b15 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -79,9 +79,8 @@ CCL_NAMESPACE_BEGIN #define __VISIBILITY_FLAG__ #define __VOLUME__ -/* TODO: solve internal compiler errors and enable light tree on HIP. */ /* TODO: solve internal compiler perf issue and enable light tree on Metal/AMD. */ -#if defined(__KERNEL_HIP__) || defined(__KERNEL_METAL_AMD__) +#if defined(__KERNEL_METAL_AMD__) # undef __LIGHT_TREE__ #endif diff --git a/intern/cycles/scene/CMakeLists.txt b/intern/cycles/scene/CMakeLists.txt index 759a25ab7cb..3fc972da75e 100644 --- a/intern/cycles/scene/CMakeLists.txt +++ b/intern/cycles/scene/CMakeLists.txt @@ -15,8 +15,12 @@ set(SRC camera.cpp colorspace.cpp constant_fold.cpp + devicescene.cpp film.cpp geometry.cpp + geometry_attributes.cpp + geometry_bvh.cpp + geometry_mesh.cpp hair.cpp image.cpp image_oiio.cpp @@ -55,6 +59,7 @@ set(SRC_HEADERS camera.h colorspace.h constant_fold.h + devicescene.h film.h geometry.h hair.h diff --git a/intern/cycles/scene/devicescene.cpp b/intern/cycles/scene/devicescene.cpp new file mode 100644 index 00000000000..8325c4855f5 --- /dev/null +++ b/intern/cycles/scene/devicescene.cpp @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "scene/devicescene.h" +#include "device/device.h" +#include "device/memory.h" + +CCL_NAMESPACE_BEGIN + +DeviceScene::DeviceScene(Device *device) + : bvh_nodes(device, "bvh_nodes", MEM_GLOBAL), + bvh_leaf_nodes(device, "bvh_leaf_nodes", MEM_GLOBAL), + object_node(device, "object_node", MEM_GLOBAL), + prim_type(device, "prim_type", MEM_GLOBAL), + prim_visibility(device, "prim_visibility", MEM_GLOBAL), + prim_index(device, "prim_index", MEM_GLOBAL), + prim_object(device, "prim_object", MEM_GLOBAL), + prim_time(device, "prim_time", MEM_GLOBAL), + tri_verts(device, "tri_verts", MEM_GLOBAL), + tri_shader(device, "tri_shader", MEM_GLOBAL), + tri_vnormal(device, "tri_vnormal", MEM_GLOBAL), + tri_vindex(device, "tri_vindex", MEM_GLOBAL), + tri_patch(device, "tri_patch", MEM_GLOBAL), + tri_patch_uv(device, "tri_patch_uv", MEM_GLOBAL), + curves(device, "curves", MEM_GLOBAL), + curve_keys(device, "curve_keys", MEM_GLOBAL), + curve_segments(device, "curve_segments", MEM_GLOBAL), + patches(device, "patches", MEM_GLOBAL), + points(device, "points", MEM_GLOBAL), + points_shader(device, "points_shader", MEM_GLOBAL), + objects(device, "objects", MEM_GLOBAL), + object_motion_pass(device, "object_motion_pass", MEM_GLOBAL), + object_motion(device, "object_motion", MEM_GLOBAL), + object_flag(device, "object_flag", MEM_GLOBAL), + object_volume_step(device, "object_volume_step", MEM_GLOBAL), + object_prim_offset(device, "object_prim_offset", MEM_GLOBAL), + camera_motion(device, "camera_motion", MEM_GLOBAL), + attributes_map(device, "attributes_map", MEM_GLOBAL), + attributes_float(device, "attributes_float", MEM_GLOBAL), + attributes_float2(device, "attributes_float2", MEM_GLOBAL), + attributes_float3(device, "attributes_float3", MEM_GLOBAL), + attributes_float4(device, "attributes_float4", MEM_GLOBAL), + attributes_uchar4(device, "attributes_uchar4", MEM_GLOBAL), + light_distribution(device, "light_distribution", MEM_GLOBAL), + lights(device, "lights", MEM_GLOBAL), + light_background_marginal_cdf(device, "light_background_marginal_cdf", MEM_GLOBAL), + light_background_conditional_cdf(device, "light_background_conditional_cdf", MEM_GLOBAL), + light_tree_nodes(device, "light_tree_nodes", MEM_GLOBAL), + light_tree_emitters(device, "light_tree_emitters", MEM_GLOBAL), + light_to_tree(device, "light_to_tree", MEM_GLOBAL), + object_to_tree(device, "object_to_tree", MEM_GLOBAL), + object_lookup_offset(device, "object_lookup_offset", MEM_GLOBAL), + triangle_to_tree(device, "triangle_to_tree", MEM_GLOBAL), + particles(device, "particles", MEM_GLOBAL), + svm_nodes(device, "svm_nodes", MEM_GLOBAL), + shaders(device, "shaders", MEM_GLOBAL), + lookup_table(device, "lookup_table", MEM_GLOBAL), + sample_pattern_lut(device, "sample_pattern_lut", MEM_GLOBAL), + ies_lights(device, "ies", MEM_GLOBAL) +{ + memset((void *)&data, 0, sizeof(data)); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/devicescene.h b/intern/cycles/scene/devicescene.h new file mode 100644 index 00000000000..250b3b86516 --- /dev/null +++ b/intern/cycles/scene/devicescene.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#ifndef __DEVICESCENE_H__ +#define __DEVICESCENE_H__ + +#include "device/device.h" +#include "device/memory.h" + +#include "util/types.h" +#include "util/vector.h" + +CCL_NAMESPACE_BEGIN + +class DeviceScene { + public: + /* BVH */ + device_vector bvh_nodes; + device_vector bvh_leaf_nodes; + device_vector object_node; + device_vector prim_type; + device_vector prim_visibility; + device_vector prim_index; + device_vector prim_object; + device_vector prim_time; + + /* mesh */ + device_vector tri_verts; + device_vector tri_shader; + device_vector tri_vnormal; + device_vector tri_vindex; + device_vector tri_patch; + device_vector tri_patch_uv; + + device_vector curves; + device_vector curve_keys; + device_vector curve_segments; + + device_vector patches; + + /* point-cloud */ + device_vector points; + device_vector points_shader; + + /* objects */ + device_vector objects; + device_vector object_motion_pass; + device_vector object_motion; + device_vector object_flag; + device_vector object_volume_step; + device_vector object_prim_offset; + + /* cameras */ + device_vector camera_motion; + + /* attributes */ + device_vector attributes_map; + device_vector attributes_float; + device_vector attributes_float2; + device_vector attributes_float3; + device_vector attributes_float4; + device_vector attributes_uchar4; + + /* lights */ + device_vector light_distribution; + device_vector lights; + device_vector light_background_marginal_cdf; + device_vector light_background_conditional_cdf; + + /* light tree */ + device_vector light_tree_nodes; + device_vector light_tree_emitters; + device_vector light_to_tree; + device_vector object_to_tree; + device_vector object_lookup_offset; + device_vector triangle_to_tree; + + /* particles */ + device_vector particles; + + /* shaders */ + device_vector svm_nodes; + device_vector shaders; + + /* lookup tables */ + device_vector lookup_table; + + /* integrator */ + device_vector sample_pattern_lut; + + /* IES lights */ + device_vector ies_lights; + + KernelData data; + + DeviceScene(Device *device); +}; + +CCL_NAMESPACE_END + +#endif /* __DEVICESCENE_H__ */ diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp index 58a9a97bf32..21d3b6a52a6 100644 --- a/intern/cycles/scene/geometry.cpp +++ b/intern/cycles/scene/geometry.cpp @@ -84,49 +84,6 @@ void Geometry::clear(bool preserve_shaders) tag_modified(); } -bool Geometry::need_attribute(Scene *scene, AttributeStandard std) -{ - if (std == ATTR_STD_NONE) - return false; - - if (scene->need_global_attribute(std)) - return true; - - foreach (Node *node, used_shaders) { - Shader *shader = static_cast(node); - if (shader->attributes.find(std)) - return true; - } - - return false; -} - -bool Geometry::need_attribute(Scene * /*scene*/, ustring name) -{ - if (name == ustring()) - return false; - - foreach (Node *node, used_shaders) { - Shader *shader = static_cast(node); - if (shader->attributes.find(name)) - return true; - } - - return false; -} - -AttributeRequestSet Geometry::needed_attributes() -{ - AttributeRequestSet result; - - foreach (Node *node, used_shaders) { - Shader *shader = static_cast(node); - result.add(shader->attributes); - } - - return result; -} - float Geometry::motion_time(int step) const { return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f; @@ -182,89 +139,11 @@ bool Geometry::has_true_displacement() const return false; } -void Geometry::compute_bvh(Device *device, - DeviceScene *dscene, - SceneParams *params, - Progress *progress, - size_t n, - size_t total) -{ - if (progress->get_cancel()) - return; - - compute_bounds(); - - const BVHLayout bvh_layout = BVHParams::best_bvh_layout( - params->bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features)); - if (need_build_bvh(bvh_layout)) { - string msg = "Updating Geometry BVH "; - if (name.empty()) - msg += string_printf("%u/%u", (uint)(n + 1), (uint)total); - else - msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total); - - Object object; - - /* Ensure all visibility bits are set at the geometry level BVH. In - * the object level BVH is where actual visibility is tested. */ - object.set_is_shadow_catcher(true); - object.set_visibility(~0); - - object.set_geometry(this); - - vector geometry; - geometry.push_back(this); - vector objects; - objects.push_back(&object); - - if (bvh && !need_update_rebuild) { - progress->set_status(msg, "Refitting BVH"); - - bvh->replace_geometry(geometry, objects); - - device->build_bvh(bvh, *progress, true); - } - else { - progress->set_status(msg, "Building BVH"); - - BVHParams bparams; - bparams.use_spatial_split = params->use_bvh_spatial_split; - bparams.use_compact_structure = params->use_bvh_compact_structure; - bparams.bvh_layout = bvh_layout; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && - params->use_bvh_unaligned_nodes; - bparams.num_motion_triangle_steps = params->num_bvh_time_steps; - bparams.num_motion_curve_steps = params->num_bvh_time_steps; - bparams.num_motion_point_steps = params->num_bvh_time_steps; - bparams.bvh_type = params->bvh_type; - bparams.curve_subdivisions = params->curve_subdivisions(); - - delete bvh; - bvh = BVH::create(bparams, geometry, objects, device); - MEM_GUARDED_CALL(progress, device->build_bvh, bvh, *progress, false); - } - } - - need_update_rebuild = false; - need_update_bvh_for_offset = false; -} - bool Geometry::has_motion_blur() const { return (use_motion_blur && attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)); } -bool Geometry::has_voxel_attributes() const -{ - foreach (const Attribute &attr, attributes.attributes) { - if (attr.element == ATTR_ELEMENT_VOXEL) { - return true; - } - } - - return false; -} - void Geometry::tag_update(Scene *scene, bool rebuild) { if (rebuild) { @@ -328,637 +207,62 @@ void GeometryManager::update_osl_globals(Device *device, Scene *scene) #endif } -/* Generate a normal attribute map entry from an attribute descriptor. */ -static void emit_attribute_map_entry(AttributeMap *attr_map, - size_t index, - uint64_t id, - TypeDesc type, - const AttributeDescriptor &desc) +static void update_device_flags_attribute(uint32_t &device_update_flags, + const AttributeSet &attributes) { - attr_map[index].id = id; - attr_map[index].element = desc.element; - attr_map[index].offset = as_uint(desc.offset); + foreach (const Attribute &attr, attributes.attributes) { + if (!attr.modified) { + continue; + } - if (type == TypeDesc::TypeFloat) - attr_map[index].type = NODE_ATTR_FLOAT; - else if (type == TypeDesc::TypeMatrix) - attr_map[index].type = NODE_ATTR_MATRIX; - else if (type == TypeFloat2) - attr_map[index].type = NODE_ATTR_FLOAT2; - else if (type == TypeFloat4) - attr_map[index].type = NODE_ATTR_FLOAT4; - else if (type == TypeRGBA) - attr_map[index].type = NODE_ATTR_RGBA; - else - attr_map[index].type = NODE_ATTR_FLOAT3; + AttrKernelDataType kernel_type = Attribute::kernel_type(attr); - attr_map[index].flags = desc.flags; -} - -/* Generate an attribute map end marker, optionally including a link to another map. - * Links are used to connect object attribute maps to mesh attribute maps. */ -static void emit_attribute_map_terminator(AttributeMap *attr_map, - size_t index, - bool chain, - uint chain_link) -{ - for (int j = 0; j < ATTR_PRIM_TYPES; j++) { - attr_map[index + j].id = ATTR_STD_NONE; - attr_map[index + j].element = chain; /* link is valid flag */ - attr_map[index + j].offset = chain ? chain_link + j : 0; /* link to the correct sub-entry */ - attr_map[index + j].type = 0; - attr_map[index + j].flags = 0; - } -} - -/* Generate all necessary attribute map entries from the attribute request. */ -static void emit_attribute_mapping( - AttributeMap *attr_map, size_t index, uint64_t id, AttributeRequest &req, Geometry *geom) -{ - emit_attribute_map_entry(attr_map, index, id, req.type, req.desc); - - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - if (mesh->get_num_subd_faces()) { - emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc); + switch (kernel_type) { + case AttrKernelDataType::FLOAT: { + device_update_flags |= ATTR_FLOAT_MODIFIED; + break; + } + case AttrKernelDataType::FLOAT2: { + device_update_flags |= ATTR_FLOAT2_MODIFIED; + break; + } + case AttrKernelDataType::FLOAT3: { + device_update_flags |= ATTR_FLOAT3_MODIFIED; + break; + } + case AttrKernelDataType::FLOAT4: { + device_update_flags |= ATTR_FLOAT4_MODIFIED; + break; + } + case AttrKernelDataType::UCHAR4: { + device_update_flags |= ATTR_UCHAR4_MODIFIED; + break; + } + case AttrKernelDataType::NUM: { + break; + } } } } -void GeometryManager::update_svm_attributes(Device *, - DeviceScene *dscene, - Scene *scene, - vector &geom_attributes, - vector &object_attributes) +static void update_attribute_realloc_flags(uint32_t &device_update_flags, + const AttributeSet &attributes) { - /* for SVM, the attributes_map table is used to lookup the offset of an - * attribute, based on a unique shader attribute id. */ - - /* compute array stride */ - size_t attr_map_size = 0; - - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - geom->attr_map_offset = attr_map_size; - -#ifdef WITH_OSL - size_t attr_count = 0; - foreach (AttributeRequest &req, geom_attributes[i].requests) { - if (req.std != ATTR_STD_NONE && - scene->shader_manager->get_attribute_id(req.std) != (uint64_t)req.std) - attr_count += 2; - else - attr_count += 1; - } -#else - const size_t attr_count = geom_attributes[i].size(); -#endif - - attr_map_size += (attr_count + 1) * ATTR_PRIM_TYPES; + if (attributes.modified(AttrKernelDataType::FLOAT)) { + device_update_flags |= ATTR_FLOAT_NEEDS_REALLOC; } - - for (size_t i = 0; i < scene->objects.size(); i++) { - Object *object = scene->objects[i]; - - /* only allocate a table for the object if it actually has attributes */ - if (object_attributes[i].size() == 0) { - object->attr_map_offset = 0; - } - else { - object->attr_map_offset = attr_map_size; - attr_map_size += (object_attributes[i].size() + 1) * ATTR_PRIM_TYPES; - } + if (attributes.modified(AttrKernelDataType::FLOAT2)) { + device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC; } - - if (attr_map_size == 0) - return; - - if (!dscene->attributes_map.need_realloc()) { - return; + if (attributes.modified(AttrKernelDataType::FLOAT3)) { + device_update_flags |= ATTR_FLOAT3_NEEDS_REALLOC; } - - /* create attribute map */ - AttributeMap *attr_map = dscene->attributes_map.alloc(attr_map_size); - memset(attr_map, 0, dscene->attributes_map.size() * sizeof(*attr_map)); - - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - AttributeRequestSet &attributes = geom_attributes[i]; - - /* set geometry attributes */ - size_t index = geom->attr_map_offset; - - foreach (AttributeRequest &req, attributes.requests) { - uint64_t id; - if (req.std == ATTR_STD_NONE) - id = scene->shader_manager->get_attribute_id(req.name); - else - id = scene->shader_manager->get_attribute_id(req.std); - - emit_attribute_mapping(attr_map, index, id, req, geom); - index += ATTR_PRIM_TYPES; - -#ifdef WITH_OSL - /* Some standard attributes are explicitly referenced via their standard ID, so add those - * again in case they were added under a different attribute ID. */ - if (req.std != ATTR_STD_NONE && id != (uint64_t)req.std) { - emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req, geom); - index += ATTR_PRIM_TYPES; - } -#endif - } - - emit_attribute_map_terminator(attr_map, index, false, 0); + if (attributes.modified(AttrKernelDataType::FLOAT4)) { + device_update_flags |= ATTR_FLOAT4_NEEDS_REALLOC; } - - for (size_t i = 0; i < scene->objects.size(); i++) { - Object *object = scene->objects[i]; - AttributeRequestSet &attributes = object_attributes[i]; - - /* set object attributes */ - if (attributes.size() > 0) { - size_t index = object->attr_map_offset; - - foreach (AttributeRequest &req, attributes.requests) { - uint64_t id; - if (req.std == ATTR_STD_NONE) - id = scene->shader_manager->get_attribute_id(req.name); - else - id = scene->shader_manager->get_attribute_id(req.std); - - emit_attribute_mapping(attr_map, index, id, req, object->geometry); - index += ATTR_PRIM_TYPES; - } - - emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset); - } + if (attributes.modified(AttrKernelDataType::UCHAR4)) { + device_update_flags |= ATTR_UCHAR4_NEEDS_REALLOC; } - - /* copy to device */ - dscene->attributes_map.copy_to_device(); -} - -static void update_attribute_element_size(Geometry *geom, - Attribute *mattr, - AttributePrimitive prim, - size_t *attr_float_size, - size_t *attr_float2_size, - size_t *attr_float3_size, - size_t *attr_float4_size, - size_t *attr_uchar4_size) -{ - if (mattr) { - size_t size = mattr->element_size(geom, prim); - - if (mattr->element == ATTR_ELEMENT_VOXEL) { - /* pass */ - } - else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { - *attr_uchar4_size += size; - } - else if (mattr->type == TypeDesc::TypeFloat) { - *attr_float_size += size; - } - else if (mattr->type == TypeFloat2) { - *attr_float2_size += size; - } - else if (mattr->type == TypeDesc::TypeMatrix) { - *attr_float4_size += size * 4; - } - else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { - *attr_float4_size += size; - } - else { - *attr_float3_size += size; - } - } -} - -void GeometryManager::update_attribute_element_offset(Geometry *geom, - device_vector &attr_float, - size_t &attr_float_offset, - device_vector &attr_float2, - size_t &attr_float2_offset, - device_vector &attr_float3, - size_t &attr_float3_offset, - device_vector &attr_float4, - size_t &attr_float4_offset, - device_vector &attr_uchar4, - size_t &attr_uchar4_offset, - Attribute *mattr, - AttributePrimitive prim, - TypeDesc &type, - AttributeDescriptor &desc) -{ - if (mattr) { - /* store element and type */ - desc.element = mattr->element; - desc.flags = mattr->flags; - type = mattr->type; - - /* store attribute data in arrays */ - size_t size = mattr->element_size(geom, prim); - - AttributeElement &element = desc.element; - int &offset = desc.offset; - - if (mattr->element == ATTR_ELEMENT_VOXEL) { - /* store slot in offset value */ - ImageHandle &handle = mattr->data_voxel(); - offset = handle.svm_slot(); - } - else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { - uchar4 *data = mattr->data_uchar4(); - offset = attr_uchar4_offset; - - assert(attr_uchar4.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_uchar4[offset + k] = data[k]; - } - attr_uchar4.tag_modified(); - } - attr_uchar4_offset += size; - } - else if (mattr->type == TypeDesc::TypeFloat) { - float *data = mattr->data_float(); - offset = attr_float_offset; - - assert(attr_float.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_float[offset + k] = data[k]; - } - attr_float.tag_modified(); - } - attr_float_offset += size; - } - else if (mattr->type == TypeFloat2) { - float2 *data = mattr->data_float2(); - offset = attr_float2_offset; - - assert(attr_float2.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_float2[offset + k] = data[k]; - } - attr_float2.tag_modified(); - } - attr_float2_offset += size; - } - else if (mattr->type == TypeDesc::TypeMatrix) { - Transform *tfm = mattr->data_transform(); - offset = attr_float4_offset; - - assert(attr_float4.size() >= offset + size * 3); - if (mattr->modified) { - for (size_t k = 0; k < size * 3; k++) { - attr_float4[offset + k] = (&tfm->x)[k]; - } - attr_float4.tag_modified(); - } - attr_float4_offset += size * 3; - } - else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { - float4 *data = mattr->data_float4(); - offset = attr_float4_offset; - - assert(attr_float4.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_float4[offset + k] = data[k]; - } - attr_float4.tag_modified(); - } - attr_float4_offset += size; - } - else { - float3 *data = mattr->data_float3(); - offset = attr_float3_offset; - - assert(attr_float3.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_float3[offset + k] = data[k]; - } - attr_float3.tag_modified(); - } - attr_float3_offset += size; - } - - /* mesh vertex/curve index is global, not per object, so we sneak - * a correction for that in here */ - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && - desc.flags & ATTR_SUBDIVIDED) { - /* Indices for subdivided attributes are retrieved - * from patch table so no need for correction here. */ - } - else if (element == ATTR_ELEMENT_VERTEX) - offset -= mesh->vert_offset; - else if (element == ATTR_ELEMENT_VERTEX_MOTION) - offset -= mesh->vert_offset; - else if (element == ATTR_ELEMENT_FACE) { - if (prim == ATTR_PRIM_GEOMETRY) - offset -= mesh->prim_offset; - else - offset -= mesh->face_offset; - } - else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) { - if (prim == ATTR_PRIM_GEOMETRY) - offset -= 3 * mesh->prim_offset; - else - offset -= mesh->corner_offset; - } - } - else if (geom->is_hair()) { - Hair *hair = static_cast(geom); - if (element == ATTR_ELEMENT_CURVE) - offset -= hair->prim_offset; - else if (element == ATTR_ELEMENT_CURVE_KEY) - offset -= hair->curve_key_offset; - else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION) - offset -= hair->curve_key_offset; - } - else if (geom->is_pointcloud()) { - if (element == ATTR_ELEMENT_VERTEX) - offset -= geom->prim_offset; - else if (element == ATTR_ELEMENT_VERTEX_MOTION) - offset -= geom->prim_offset; - } - } - else { - /* attribute not found */ - desc.element = ATTR_ELEMENT_NONE; - desc.offset = 0; - } -} - -void GeometryManager::device_update_attributes(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - progress.set_status("Updating Mesh", "Computing attributes"); - - /* gather per mesh requested attributes. as meshes may have multiple - * shaders assigned, this merges the requested attributes that have - * been set per shader by the shader manager */ - vector geom_attributes(scene->geometry.size()); - - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - - geom->index = i; - scene->need_global_attributes(geom_attributes[i]); - - foreach (Node *node, geom->get_used_shaders()) { - Shader *shader = static_cast(node); - geom_attributes[i].add(shader->attributes); - } - - if (geom->is_hair() && static_cast(geom)->need_shadow_transparency()) { - geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY); - } - } - - /* convert object attributes to use the same data structures as geometry ones */ - vector object_attributes(scene->objects.size()); - vector object_attribute_values; - - object_attribute_values.reserve(scene->objects.size()); - - for (size_t i = 0; i < scene->objects.size(); i++) { - Object *object = scene->objects[i]; - Geometry *geom = object->geometry; - size_t geom_idx = geom->index; - - assert(geom_idx < scene->geometry.size() && scene->geometry[geom_idx] == geom); - - object_attribute_values.push_back(AttributeSet(geom, ATTR_PRIM_GEOMETRY)); - - AttributeRequestSet &geom_requests = geom_attributes[geom_idx]; - AttributeRequestSet &attributes = object_attributes[i]; - AttributeSet &values = object_attribute_values[i]; - - for (size_t j = 0; j < object->attributes.size(); j++) { - ParamValue ¶m = object->attributes[j]; - - /* add attributes that are requested and not already handled by the mesh */ - if (geom_requests.find(param.name()) && !geom->attributes.find(param.name())) { - attributes.add(param.name()); - - Attribute *attr = values.add(param.name(), param.type(), ATTR_ELEMENT_OBJECT); - assert(param.datasize() == attr->buffer.size()); - memcpy(attr->buffer.data(), param.data(), param.datasize()); - } - } - } - - /* mesh attribute are stored in a single array per data type. here we fill - * those arrays, and set the offset and element type to create attribute - * maps next */ - - /* Pre-allocate attributes to avoid arrays re-allocation which would - * take 2x of overall attribute memory usage. - */ - size_t attr_float_size = 0; - size_t attr_float2_size = 0; - size_t attr_float3_size = 0; - size_t attr_float4_size = 0; - size_t attr_uchar4_size = 0; - - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - AttributeRequestSet &attributes = geom_attributes[i]; - foreach (AttributeRequest &req, attributes.requests) { - Attribute *attr = geom->attributes.find(req); - - update_attribute_element_size(geom, - attr, - ATTR_PRIM_GEOMETRY, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_float4_size, - &attr_uchar4_size); - - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - Attribute *subd_attr = mesh->subd_attributes.find(req); - - update_attribute_element_size(mesh, - subd_attr, - ATTR_PRIM_SUBD, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_float4_size, - &attr_uchar4_size); - } - } - } - - for (size_t i = 0; i < scene->objects.size(); i++) { - Object *object = scene->objects[i]; - - foreach (Attribute &attr, object_attribute_values[i].attributes) { - update_attribute_element_size(object->geometry, - &attr, - ATTR_PRIM_GEOMETRY, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_float4_size, - &attr_uchar4_size); - } - } - - dscene->attributes_float.alloc(attr_float_size); - dscene->attributes_float2.alloc(attr_float2_size); - dscene->attributes_float3.alloc(attr_float3_size); - dscene->attributes_float4.alloc(attr_float4_size); - dscene->attributes_uchar4.alloc(attr_uchar4_size); - - /* The order of those flags needs to match that of AttrKernelDataType. */ - const bool attributes_need_realloc[AttrKernelDataType::NUM] = { - dscene->attributes_float.need_realloc(), - dscene->attributes_float2.need_realloc(), - dscene->attributes_float3.need_realloc(), - dscene->attributes_float4.need_realloc(), - dscene->attributes_uchar4.need_realloc(), - }; - - size_t attr_float_offset = 0; - size_t attr_float2_offset = 0; - size_t attr_float3_offset = 0; - size_t attr_float4_offset = 0; - size_t attr_uchar4_offset = 0; - - /* Fill in attributes. */ - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - AttributeRequestSet &attributes = geom_attributes[i]; - - /* todo: we now store std and name attributes from requests even if - * they actually refer to the same mesh attributes, optimize */ - foreach (AttributeRequest &req, attributes.requests) { - Attribute *attr = geom->attributes.find(req); - - if (attr) { - /* force a copy if we need to reallocate all the data */ - attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; - } - - update_attribute_element_offset(geom, - dscene->attributes_float, - attr_float_offset, - dscene->attributes_float2, - attr_float2_offset, - dscene->attributes_float3, - attr_float3_offset, - dscene->attributes_float4, - attr_float4_offset, - dscene->attributes_uchar4, - attr_uchar4_offset, - attr, - ATTR_PRIM_GEOMETRY, - req.type, - req.desc); - - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - Attribute *subd_attr = mesh->subd_attributes.find(req); - - if (subd_attr) { - /* force a copy if we need to reallocate all the data */ - subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)]; - } - - update_attribute_element_offset(mesh, - dscene->attributes_float, - attr_float_offset, - dscene->attributes_float2, - attr_float2_offset, - dscene->attributes_float3, - attr_float3_offset, - dscene->attributes_float4, - attr_float4_offset, - dscene->attributes_uchar4, - attr_uchar4_offset, - subd_attr, - ATTR_PRIM_SUBD, - req.subd_type, - req.subd_desc); - } - - if (progress.get_cancel()) - return; - } - } - - for (size_t i = 0; i < scene->objects.size(); i++) { - Object *object = scene->objects[i]; - AttributeRequestSet &attributes = object_attributes[i]; - AttributeSet &values = object_attribute_values[i]; - - foreach (AttributeRequest &req, attributes.requests) { - Attribute *attr = values.find(req); - - if (attr) { - attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; - } - - update_attribute_element_offset(object->geometry, - dscene->attributes_float, - attr_float_offset, - dscene->attributes_float2, - attr_float2_offset, - dscene->attributes_float3, - attr_float3_offset, - dscene->attributes_float4, - attr_float4_offset, - dscene->attributes_uchar4, - attr_uchar4_offset, - attr, - ATTR_PRIM_GEOMETRY, - req.type, - req.desc); - - /* object attributes don't care about subdivision */ - req.subd_type = req.type; - req.subd_desc = req.desc; - - if (progress.get_cancel()) - return; - } - } - - /* create attribute lookup maps */ - if (scene->shader_manager->use_osl()) - update_osl_globals(device, scene); - - update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes); - - if (progress.get_cancel()) - return; - - /* copy to device */ - progress.set_status("Updating Mesh", "Copying Attributes to device"); - - dscene->attributes_float.copy_to_device_if_modified(); - dscene->attributes_float2.copy_to_device_if_modified(); - dscene->attributes_float3.copy_to_device_if_modified(); - dscene->attributes_float4.copy_to_device_if_modified(); - dscene->attributes_uchar4.copy_to_device_if_modified(); - - if (progress.get_cancel()) - return; - - /* After mesh attributes and patch tables have been copied to device memory, - * we need to update offsets in the objects. */ - scene->object_manager->device_update_geom_offsets(device, dscene, scene); } void GeometryManager::geom_calc_offset(Scene *scene, BVHLayout bvh_layout) @@ -1040,375 +344,6 @@ void GeometryManager::geom_calc_offset(Scene *scene, BVHLayout bvh_layout) } } -void GeometryManager::device_update_mesh(Device *, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - /* Count. */ - size_t vert_size = 0; - size_t tri_size = 0; - - size_t curve_key_size = 0; - size_t curve_size = 0; - size_t curve_segment_size = 0; - - size_t point_size = 0; - - size_t patch_size = 0; - - foreach (Geometry *geom, scene->geometry) { - if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { - Mesh *mesh = static_cast(geom); - - vert_size += mesh->verts.size(); - tri_size += mesh->num_triangles(); - - if (mesh->get_num_subd_faces()) { - Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1); - patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; - - /* patch tables are stored in same array so include them in patch_size */ - if (mesh->patch_table) { - mesh->patch_table_offset = patch_size; - patch_size += mesh->patch_table->total_size(); - } - } - } - else if (geom->is_hair()) { - Hair *hair = static_cast(geom); - - curve_key_size += hair->get_curve_keys().size(); - curve_size += hair->num_curves(); - curve_segment_size += hair->num_segments(); - } - else if (geom->is_pointcloud()) { - PointCloud *pointcloud = static_cast(geom); - point_size += pointcloud->num_points(); - } - } - - /* Fill in all the arrays. */ - if (tri_size != 0) { - /* normals */ - progress.set_status("Updating Mesh", "Computing normals"); - - packed_float3 *tri_verts = dscene->tri_verts.alloc(vert_size); - uint *tri_shader = dscene->tri_shader.alloc(tri_size); - packed_float3 *vnormal = dscene->tri_vnormal.alloc(vert_size); - packed_uint3 *tri_vindex = dscene->tri_vindex.alloc(tri_size); - uint *tri_patch = dscene->tri_patch.alloc(tri_size); - float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); - - const bool copy_all_data = dscene->tri_shader.need_realloc() || - dscene->tri_vindex.need_realloc() || - dscene->tri_vnormal.need_realloc() || - dscene->tri_patch.need_realloc() || - dscene->tri_patch_uv.need_realloc(); - - foreach (Geometry *geom, scene->geometry) { - if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { - Mesh *mesh = static_cast(geom); - - if (mesh->shader_is_modified() || mesh->smooth_is_modified() || - mesh->triangles_is_modified() || copy_all_data) { - mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]); - } - - if (mesh->verts_is_modified() || copy_all_data) { - mesh->pack_normals(&vnormal[mesh->vert_offset]); - } - - if (mesh->verts_is_modified() || mesh->triangles_is_modified() || - mesh->vert_patch_uv_is_modified() || copy_all_data) { - mesh->pack_verts(&tri_verts[mesh->vert_offset], - &tri_vindex[mesh->prim_offset], - &tri_patch[mesh->prim_offset], - &tri_patch_uv[mesh->vert_offset]); - } - - if (progress.get_cancel()) - return; - } - } - - /* vertex coordinates */ - progress.set_status("Updating Mesh", "Copying Mesh to device"); - - dscene->tri_verts.copy_to_device_if_modified(); - dscene->tri_shader.copy_to_device_if_modified(); - dscene->tri_vnormal.copy_to_device_if_modified(); - dscene->tri_vindex.copy_to_device_if_modified(); - dscene->tri_patch.copy_to_device_if_modified(); - dscene->tri_patch_uv.copy_to_device_if_modified(); - } - - if (curve_segment_size != 0) { - progress.set_status("Updating Mesh", "Copying Curves to device"); - - float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size); - KernelCurve *curves = dscene->curves.alloc(curve_size); - KernelCurveSegment *curve_segments = dscene->curve_segments.alloc(curve_segment_size); - - const bool copy_all_data = dscene->curve_keys.need_realloc() || - dscene->curves.need_realloc() || - dscene->curve_segments.need_realloc(); - - foreach (Geometry *geom, scene->geometry) { - if (geom->is_hair()) { - Hair *hair = static_cast(geom); - - bool curve_keys_co_modified = hair->curve_radius_is_modified() || - hair->curve_keys_is_modified(); - bool curve_data_modified = hair->curve_shader_is_modified() || - hair->curve_first_key_is_modified(); - - if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) { - continue; - } - - hair->pack_curves(scene, - &curve_keys[hair->curve_key_offset], - &curves[hair->prim_offset], - &curve_segments[hair->curve_segment_offset]); - if (progress.get_cancel()) - return; - } - } - - dscene->curve_keys.copy_to_device_if_modified(); - dscene->curves.copy_to_device_if_modified(); - dscene->curve_segments.copy_to_device_if_modified(); - } - - if (point_size != 0) { - progress.set_status("Updating Mesh", "Copying Point clouds to device"); - - float4 *points = dscene->points.alloc(point_size); - uint *points_shader = dscene->points_shader.alloc(point_size); - - foreach (Geometry *geom, scene->geometry) { - if (geom->is_pointcloud()) { - PointCloud *pointcloud = static_cast(geom); - pointcloud->pack( - scene, &points[pointcloud->prim_offset], &points_shader[pointcloud->prim_offset]); - if (progress.get_cancel()) - return; - } - } - - dscene->points.copy_to_device(); - dscene->points_shader.copy_to_device(); - } - - if (patch_size != 0 && dscene->patches.need_realloc()) { - progress.set_status("Updating Mesh", "Copying Patches to device"); - - uint *patch_data = dscene->patches.alloc(patch_size); - - foreach (Geometry *geom, scene->geometry) { - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - mesh->pack_patches(&patch_data[mesh->patch_offset]); - - if (mesh->patch_table) { - mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], - mesh->patch_table_offset); - } - - if (progress.get_cancel()) - return; - } - } - - dscene->patches.copy_to_device(); - } -} - -void GeometryManager::device_update_bvh(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - /* bvh build */ - progress.set_status("Updating Scene BVH", "Building"); - - BVHParams bparams; - bparams.top_level = true; - bparams.bvh_layout = BVHParams::best_bvh_layout( - scene->params.bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features)); - bparams.use_spatial_split = scene->params.use_bvh_spatial_split; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && - scene->params.use_bvh_unaligned_nodes; - bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps; - bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps; - bparams.num_motion_point_steps = scene->params.num_bvh_time_steps; - bparams.bvh_type = scene->params.bvh_type; - bparams.curve_subdivisions = scene->params.curve_subdivisions(); - - VLOG_INFO << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout."; - - const bool can_refit = scene->bvh != nullptr && - (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX || - bparams.bvh_layout == BVHLayout::BVH_LAYOUT_METAL); - - BVH *bvh = scene->bvh; - if (!scene->bvh) { - bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device); - } - - device->build_bvh(bvh, progress, can_refit); - - if (progress.get_cancel()) { - return; - } - - const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2); - - PackedBVH pack; - if (has_bvh2_layout) { - pack = std::move(static_cast(bvh)->pack); - } - else { - pack.root_index = -1; - } - - /* copy to device */ - progress.set_status("Updating Scene BVH", "Copying BVH to device"); - - /* When using BVH2, we always have to copy/update the data as its layout is dependent on the - * BVH's leaf nodes which may be different when the objects or vertices move. */ - - if (pack.nodes.size()) { - dscene->bvh_nodes.steal_data(pack.nodes); - dscene->bvh_nodes.copy_to_device(); - } - if (pack.leaf_nodes.size()) { - dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes); - dscene->bvh_leaf_nodes.copy_to_device(); - } - if (pack.object_node.size()) { - dscene->object_node.steal_data(pack.object_node); - dscene->object_node.copy_to_device(); - } - if (pack.prim_type.size()) { - dscene->prim_type.steal_data(pack.prim_type); - dscene->prim_type.copy_to_device(); - } - if (pack.prim_visibility.size()) { - dscene->prim_visibility.steal_data(pack.prim_visibility); - dscene->prim_visibility.copy_to_device(); - } - if (pack.prim_index.size()) { - dscene->prim_index.steal_data(pack.prim_index); - dscene->prim_index.copy_to_device(); - } - if (pack.prim_object.size()) { - dscene->prim_object.steal_data(pack.prim_object); - dscene->prim_object.copy_to_device(); - } - if (pack.prim_time.size()) { - dscene->prim_time.steal_data(pack.prim_time); - dscene->prim_time.copy_to_device(); - } - - dscene->data.bvh.root = pack.root_index; - dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); - dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions(); - /* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */ - dscene->data.device_bvh = 0; -} - -/* Set of flags used to help determining what data has been modified or needs reallocation, so we - * can decide which device data to free or update. */ -enum { - DEVICE_CURVE_DATA_MODIFIED = (1 << 0), - DEVICE_MESH_DATA_MODIFIED = (1 << 1), - DEVICE_POINT_DATA_MODIFIED = (1 << 2), - - ATTR_FLOAT_MODIFIED = (1 << 3), - ATTR_FLOAT2_MODIFIED = (1 << 4), - ATTR_FLOAT3_MODIFIED = (1 << 5), - ATTR_FLOAT4_MODIFIED = (1 << 6), - ATTR_UCHAR4_MODIFIED = (1 << 7), - - CURVE_DATA_NEED_REALLOC = (1 << 8), - MESH_DATA_NEED_REALLOC = (1 << 9), - POINT_DATA_NEED_REALLOC = (1 << 10), - - ATTR_FLOAT_NEEDS_REALLOC = (1 << 11), - ATTR_FLOAT2_NEEDS_REALLOC = (1 << 12), - ATTR_FLOAT3_NEEDS_REALLOC = (1 << 13), - ATTR_FLOAT4_NEEDS_REALLOC = (1 << 14), - - ATTR_UCHAR4_NEEDS_REALLOC = (1 << 15), - - ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC | - ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC | - ATTR_UCHAR4_NEEDS_REALLOC), - DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), - DEVICE_POINT_DATA_NEEDS_REALLOC = (POINT_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), - DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), -}; - -static void update_device_flags_attribute(uint32_t &device_update_flags, - const AttributeSet &attributes) -{ - foreach (const Attribute &attr, attributes.attributes) { - if (!attr.modified) { - continue; - } - - AttrKernelDataType kernel_type = Attribute::kernel_type(attr); - - switch (kernel_type) { - case AttrKernelDataType::FLOAT: { - device_update_flags |= ATTR_FLOAT_MODIFIED; - break; - } - case AttrKernelDataType::FLOAT2: { - device_update_flags |= ATTR_FLOAT2_MODIFIED; - break; - } - case AttrKernelDataType::FLOAT3: { - device_update_flags |= ATTR_FLOAT3_MODIFIED; - break; - } - case AttrKernelDataType::FLOAT4: { - device_update_flags |= ATTR_FLOAT4_MODIFIED; - break; - } - case AttrKernelDataType::UCHAR4: { - device_update_flags |= ATTR_UCHAR4_MODIFIED; - break; - } - case AttrKernelDataType::NUM: { - break; - } - } - } -} - -static void update_attribute_realloc_flags(uint32_t &device_update_flags, - const AttributeSet &attributes) -{ - if (attributes.modified(AttrKernelDataType::FLOAT)) { - device_update_flags |= ATTR_FLOAT_NEEDS_REALLOC; - } - if (attributes.modified(AttrKernelDataType::FLOAT2)) { - device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC; - } - if (attributes.modified(AttrKernelDataType::FLOAT3)) { - device_update_flags |= ATTR_FLOAT3_NEEDS_REALLOC; - } - if (attributes.modified(AttrKernelDataType::FLOAT4)) { - device_update_flags |= ATTR_FLOAT4_NEEDS_REALLOC; - } - if (attributes.modified(AttrKernelDataType::UCHAR4)) { - device_update_flags |= ATTR_UCHAR4_NEEDS_REALLOC; - } -} - void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress) { if (!need_update() && !need_flags_update) { diff --git a/intern/cycles/scene/geometry.h b/intern/cycles/scene/geometry.h index 8a1bdc33a6f..335e0859965 100644 --- a/intern/cycles/scene/geometry.h +++ b/intern/cycles/scene/geometry.h @@ -30,6 +30,38 @@ class Shader; class Volume; struct PackedBVH; +/* Set of flags used to help determining what data has been modified or needs reallocation, so we + * can decide which device data to free or update. */ +enum { + DEVICE_CURVE_DATA_MODIFIED = (1 << 0), + DEVICE_MESH_DATA_MODIFIED = (1 << 1), + DEVICE_POINT_DATA_MODIFIED = (1 << 2), + + ATTR_FLOAT_MODIFIED = (1 << 3), + ATTR_FLOAT2_MODIFIED = (1 << 4), + ATTR_FLOAT3_MODIFIED = (1 << 5), + ATTR_FLOAT4_MODIFIED = (1 << 6), + ATTR_UCHAR4_MODIFIED = (1 << 7), + + CURVE_DATA_NEED_REALLOC = (1 << 8), + MESH_DATA_NEED_REALLOC = (1 << 9), + POINT_DATA_NEED_REALLOC = (1 << 10), + + ATTR_FLOAT_NEEDS_REALLOC = (1 << 11), + ATTR_FLOAT2_NEEDS_REALLOC = (1 << 12), + ATTR_FLOAT3_NEEDS_REALLOC = (1 << 13), + ATTR_FLOAT4_NEEDS_REALLOC = (1 << 14), + + ATTR_UCHAR4_NEEDS_REALLOC = (1 << 15), + + ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC | + ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC | + ATTR_UCHAR4_NEEDS_REALLOC), + DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), + DEVICE_POINT_DATA_NEEDS_REALLOC = (POINT_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), + DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), +}; + /* Geometry * * Base class for geometric types like Mesh and Hair. */ diff --git a/intern/cycles/scene/geometry_attributes.cpp b/intern/cycles/scene/geometry_attributes.cpp new file mode 100644 index 00000000000..c8f2d4a6e28 --- /dev/null +++ b/intern/cycles/scene/geometry_attributes.cpp @@ -0,0 +1,722 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "bvh/bvh.h" +#include "bvh/bvh2.h" + +#include "device/device.h" + +#include "scene/attribute.h" +#include "scene/camera.h" +#include "scene/geometry.h" +#include "scene/hair.h" +#include "scene/light.h" +#include "scene/mesh.h" +#include "scene/object.h" +#include "scene/pointcloud.h" +#include "scene/scene.h" +#include "scene/shader.h" +#include "scene/shader_nodes.h" +#include "scene/stats.h" +#include "scene/volume.h" + +#include "subd/patch_table.h" +#include "subd/split.h" + +#include "kernel/osl/globals.h" + +#include "util/foreach.h" +#include "util/log.h" +#include "util/progress.h" +#include "util/task.h" + +CCL_NAMESPACE_BEGIN + +bool Geometry::need_attribute(Scene *scene, AttributeStandard std) +{ + if (std == ATTR_STD_NONE) + return false; + + if (scene->need_global_attribute(std)) + return true; + + foreach (Node *node, used_shaders) { + Shader *shader = static_cast(node); + if (shader->attributes.find(std)) + return true; + } + + return false; +} + +bool Geometry::need_attribute(Scene * /*scene*/, ustring name) +{ + if (name == ustring()) + return false; + + foreach (Node *node, used_shaders) { + Shader *shader = static_cast(node); + if (shader->attributes.find(name)) + return true; + } + + return false; +} + +AttributeRequestSet Geometry::needed_attributes() +{ + AttributeRequestSet result; + + foreach (Node *node, used_shaders) { + Shader *shader = static_cast(node); + result.add(shader->attributes); + } + + return result; +} + +bool Geometry::has_voxel_attributes() const +{ + foreach (const Attribute &attr, attributes.attributes) { + if (attr.element == ATTR_ELEMENT_VOXEL) { + return true; + } + } + + return false; +} + +/* Generate a normal attribute map entry from an attribute descriptor. */ +static void emit_attribute_map_entry(AttributeMap *attr_map, + size_t index, + uint64_t id, + TypeDesc type, + const AttributeDescriptor &desc) +{ + attr_map[index].id = id; + attr_map[index].element = desc.element; + attr_map[index].offset = as_uint(desc.offset); + + if (type == TypeDesc::TypeFloat) + attr_map[index].type = NODE_ATTR_FLOAT; + else if (type == TypeDesc::TypeMatrix) + attr_map[index].type = NODE_ATTR_MATRIX; + else if (type == TypeFloat2) + attr_map[index].type = NODE_ATTR_FLOAT2; + else if (type == TypeFloat4) + attr_map[index].type = NODE_ATTR_FLOAT4; + else if (type == TypeRGBA) + attr_map[index].type = NODE_ATTR_RGBA; + else + attr_map[index].type = NODE_ATTR_FLOAT3; + + attr_map[index].flags = desc.flags; +} + +/* Generate an attribute map end marker, optionally including a link to another map. + * Links are used to connect object attribute maps to mesh attribute maps. */ +static void emit_attribute_map_terminator(AttributeMap *attr_map, + size_t index, + bool chain, + uint chain_link) +{ + for (int j = 0; j < ATTR_PRIM_TYPES; j++) { + attr_map[index + j].id = ATTR_STD_NONE; + attr_map[index + j].element = chain; /* link is valid flag */ + attr_map[index + j].offset = chain ? chain_link + j : 0; /* link to the correct sub-entry */ + attr_map[index + j].type = 0; + attr_map[index + j].flags = 0; + } +} + +/* Generate all necessary attribute map entries from the attribute request. */ +static void emit_attribute_mapping( + AttributeMap *attr_map, size_t index, uint64_t id, AttributeRequest &req, Geometry *geom) +{ + emit_attribute_map_entry(attr_map, index, id, req.type, req.desc); + + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + if (mesh->get_num_subd_faces()) { + emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc); + } + } +} + +void GeometryManager::update_svm_attributes(Device *, + DeviceScene *dscene, + Scene *scene, + vector &geom_attributes, + vector &object_attributes) +{ + /* for SVM, the attributes_map table is used to lookup the offset of an + * attribute, based on a unique shader attribute id. */ + + /* compute array stride */ + size_t attr_map_size = 0; + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + geom->attr_map_offset = attr_map_size; + +#ifdef WITH_OSL + size_t attr_count = 0; + foreach (AttributeRequest &req, geom_attributes[i].requests) { + if (req.std != ATTR_STD_NONE && + scene->shader_manager->get_attribute_id(req.std) != (uint64_t)req.std) + attr_count += 2; + else + attr_count += 1; + } +#else + const size_t attr_count = geom_attributes[i].size(); +#endif + + attr_map_size += (attr_count + 1) * ATTR_PRIM_TYPES; + } + + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + + /* only allocate a table for the object if it actually has attributes */ + if (object_attributes[i].size() == 0) { + object->attr_map_offset = 0; + } + else { + object->attr_map_offset = attr_map_size; + attr_map_size += (object_attributes[i].size() + 1) * ATTR_PRIM_TYPES; + } + } + + if (attr_map_size == 0) + return; + + if (!dscene->attributes_map.need_realloc()) { + return; + } + + /* create attribute map */ + AttributeMap *attr_map = dscene->attributes_map.alloc(attr_map_size); + memset(attr_map, 0, dscene->attributes_map.size() * sizeof(*attr_map)); + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + AttributeRequestSet &attributes = geom_attributes[i]; + + /* set geometry attributes */ + size_t index = geom->attr_map_offset; + + foreach (AttributeRequest &req, attributes.requests) { + uint64_t id; + if (req.std == ATTR_STD_NONE) + id = scene->shader_manager->get_attribute_id(req.name); + else + id = scene->shader_manager->get_attribute_id(req.std); + + emit_attribute_mapping(attr_map, index, id, req, geom); + index += ATTR_PRIM_TYPES; + +#ifdef WITH_OSL + /* Some standard attributes are explicitly referenced via their standard ID, so add those + * again in case they were added under a different attribute ID. */ + if (req.std != ATTR_STD_NONE && id != (uint64_t)req.std) { + emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req, geom); + index += ATTR_PRIM_TYPES; + } +#endif + } + + emit_attribute_map_terminator(attr_map, index, false, 0); + } + + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + AttributeRequestSet &attributes = object_attributes[i]; + + /* set object attributes */ + if (attributes.size() > 0) { + size_t index = object->attr_map_offset; + + foreach (AttributeRequest &req, attributes.requests) { + uint64_t id; + if (req.std == ATTR_STD_NONE) + id = scene->shader_manager->get_attribute_id(req.name); + else + id = scene->shader_manager->get_attribute_id(req.std); + + emit_attribute_mapping(attr_map, index, id, req, object->geometry); + index += ATTR_PRIM_TYPES; + } + + emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset); + } + } + + /* copy to device */ + dscene->attributes_map.copy_to_device(); +} + +void GeometryManager::update_attribute_element_offset(Geometry *geom, + device_vector &attr_float, + size_t &attr_float_offset, + device_vector &attr_float2, + size_t &attr_float2_offset, + device_vector &attr_float3, + size_t &attr_float3_offset, + device_vector &attr_float4, + size_t &attr_float4_offset, + device_vector &attr_uchar4, + size_t &attr_uchar4_offset, + Attribute *mattr, + AttributePrimitive prim, + TypeDesc &type, + AttributeDescriptor &desc) +{ + if (mattr) { + /* store element and type */ + desc.element = mattr->element; + desc.flags = mattr->flags; + type = mattr->type; + + /* store attribute data in arrays */ + size_t size = mattr->element_size(geom, prim); + + AttributeElement &element = desc.element; + int &offset = desc.offset; + + if (mattr->element == ATTR_ELEMENT_VOXEL) { + /* store slot in offset value */ + ImageHandle &handle = mattr->data_voxel(); + offset = handle.svm_slot(); + } + else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { + uchar4 *data = mattr->data_uchar4(); + offset = attr_uchar4_offset; + + assert(attr_uchar4.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_uchar4[offset + k] = data[k]; + } + attr_uchar4.tag_modified(); + } + attr_uchar4_offset += size; + } + else if (mattr->type == TypeDesc::TypeFloat) { + float *data = mattr->data_float(); + offset = attr_float_offset; + + assert(attr_float.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float[offset + k] = data[k]; + } + attr_float.tag_modified(); + } + attr_float_offset += size; + } + else if (mattr->type == TypeFloat2) { + float2 *data = mattr->data_float2(); + offset = attr_float2_offset; + + assert(attr_float2.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float2[offset + k] = data[k]; + } + attr_float2.tag_modified(); + } + attr_float2_offset += size; + } + else if (mattr->type == TypeDesc::TypeMatrix) { + Transform *tfm = mattr->data_transform(); + offset = attr_float4_offset; + + assert(attr_float4.size() >= offset + size * 3); + if (mattr->modified) { + for (size_t k = 0; k < size * 3; k++) { + attr_float4[offset + k] = (&tfm->x)[k]; + } + attr_float4.tag_modified(); + } + attr_float4_offset += size * 3; + } + else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { + float4 *data = mattr->data_float4(); + offset = attr_float4_offset; + + assert(attr_float4.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float4[offset + k] = data[k]; + } + attr_float4.tag_modified(); + } + attr_float4_offset += size; + } + else { + float3 *data = mattr->data_float3(); + offset = attr_float3_offset; + + assert(attr_float3.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float3[offset + k] = data[k]; + } + attr_float3.tag_modified(); + } + attr_float3_offset += size; + } + + /* mesh vertex/curve index is global, not per object, so we sneak + * a correction for that in here */ + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && + desc.flags & ATTR_SUBDIVIDED) { + /* Indices for subdivided attributes are retrieved + * from patch table so no need for correction here. */ + } + else if (element == ATTR_ELEMENT_VERTEX) + offset -= mesh->vert_offset; + else if (element == ATTR_ELEMENT_VERTEX_MOTION) + offset -= mesh->vert_offset; + else if (element == ATTR_ELEMENT_FACE) { + if (prim == ATTR_PRIM_GEOMETRY) + offset -= mesh->prim_offset; + else + offset -= mesh->face_offset; + } + else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) { + if (prim == ATTR_PRIM_GEOMETRY) + offset -= 3 * mesh->prim_offset; + else + offset -= mesh->corner_offset; + } + } + else if (geom->is_hair()) { + Hair *hair = static_cast(geom); + if (element == ATTR_ELEMENT_CURVE) + offset -= hair->prim_offset; + else if (element == ATTR_ELEMENT_CURVE_KEY) + offset -= hair->curve_key_offset; + else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION) + offset -= hair->curve_key_offset; + } + else if (geom->is_pointcloud()) { + if (element == ATTR_ELEMENT_VERTEX) + offset -= geom->prim_offset; + else if (element == ATTR_ELEMENT_VERTEX_MOTION) + offset -= geom->prim_offset; + } + } + else { + /* attribute not found */ + desc.element = ATTR_ELEMENT_NONE; + desc.offset = 0; + } +} + +static void update_attribute_element_size(Geometry *geom, + Attribute *mattr, + AttributePrimitive prim, + size_t *attr_float_size, + size_t *attr_float2_size, + size_t *attr_float3_size, + size_t *attr_float4_size, + size_t *attr_uchar4_size) +{ + if (mattr) { + size_t size = mattr->element_size(geom, prim); + + if (mattr->element == ATTR_ELEMENT_VOXEL) { + /* pass */ + } + else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { + *attr_uchar4_size += size; + } + else if (mattr->type == TypeDesc::TypeFloat) { + *attr_float_size += size; + } + else if (mattr->type == TypeFloat2) { + *attr_float2_size += size; + } + else if (mattr->type == TypeDesc::TypeMatrix) { + *attr_float4_size += size * 4; + } + else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { + *attr_float4_size += size; + } + else { + *attr_float3_size += size; + } + } +} + +void GeometryManager::device_update_attributes(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + progress.set_status("Updating Mesh", "Computing attributes"); + + /* gather per mesh requested attributes. as meshes may have multiple + * shaders assigned, this merges the requested attributes that have + * been set per shader by the shader manager */ + vector geom_attributes(scene->geometry.size()); + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + + geom->index = i; + scene->need_global_attributes(geom_attributes[i]); + + foreach (Node *node, geom->get_used_shaders()) { + Shader *shader = static_cast(node); + geom_attributes[i].add(shader->attributes); + } + + if (geom->is_hair() && static_cast(geom)->need_shadow_transparency()) { + geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY); + } + } + + /* convert object attributes to use the same data structures as geometry ones */ + vector object_attributes(scene->objects.size()); + vector object_attribute_values; + + object_attribute_values.reserve(scene->objects.size()); + + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + Geometry *geom = object->geometry; + size_t geom_idx = geom->index; + + assert(geom_idx < scene->geometry.size() && scene->geometry[geom_idx] == geom); + + object_attribute_values.push_back(AttributeSet(geom, ATTR_PRIM_GEOMETRY)); + + AttributeRequestSet &geom_requests = geom_attributes[geom_idx]; + AttributeRequestSet &attributes = object_attributes[i]; + AttributeSet &values = object_attribute_values[i]; + + for (size_t j = 0; j < object->attributes.size(); j++) { + ParamValue ¶m = object->attributes[j]; + + /* add attributes that are requested and not already handled by the mesh */ + if (geom_requests.find(param.name()) && !geom->attributes.find(param.name())) { + attributes.add(param.name()); + + Attribute *attr = values.add(param.name(), param.type(), ATTR_ELEMENT_OBJECT); + assert(param.datasize() == attr->buffer.size()); + memcpy(attr->buffer.data(), param.data(), param.datasize()); + } + } + } + + /* mesh attribute are stored in a single array per data type. here we fill + * those arrays, and set the offset and element type to create attribute + * maps next */ + + /* Pre-allocate attributes to avoid arrays re-allocation which would + * take 2x of overall attribute memory usage. + */ + size_t attr_float_size = 0; + size_t attr_float2_size = 0; + size_t attr_float3_size = 0; + size_t attr_float4_size = 0; + size_t attr_uchar4_size = 0; + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + AttributeRequestSet &attributes = geom_attributes[i]; + foreach (AttributeRequest &req, attributes.requests) { + Attribute *attr = geom->attributes.find(req); + + update_attribute_element_size(geom, + attr, + ATTR_PRIM_GEOMETRY, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_float4_size, + &attr_uchar4_size); + + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + Attribute *subd_attr = mesh->subd_attributes.find(req); + + update_attribute_element_size(mesh, + subd_attr, + ATTR_PRIM_SUBD, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_float4_size, + &attr_uchar4_size); + } + } + } + + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + + foreach (Attribute &attr, object_attribute_values[i].attributes) { + update_attribute_element_size(object->geometry, + &attr, + ATTR_PRIM_GEOMETRY, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_float4_size, + &attr_uchar4_size); + } + } + + dscene->attributes_float.alloc(attr_float_size); + dscene->attributes_float2.alloc(attr_float2_size); + dscene->attributes_float3.alloc(attr_float3_size); + dscene->attributes_float4.alloc(attr_float4_size); + dscene->attributes_uchar4.alloc(attr_uchar4_size); + + /* The order of those flags needs to match that of AttrKernelDataType. */ + const bool attributes_need_realloc[AttrKernelDataType::NUM] = { + dscene->attributes_float.need_realloc(), + dscene->attributes_float2.need_realloc(), + dscene->attributes_float3.need_realloc(), + dscene->attributes_float4.need_realloc(), + dscene->attributes_uchar4.need_realloc(), + }; + + size_t attr_float_offset = 0; + size_t attr_float2_offset = 0; + size_t attr_float3_offset = 0; + size_t attr_float4_offset = 0; + size_t attr_uchar4_offset = 0; + + /* Fill in attributes. */ + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + AttributeRequestSet &attributes = geom_attributes[i]; + + /* todo: we now store std and name attributes from requests even if + * they actually refer to the same mesh attributes, optimize */ + foreach (AttributeRequest &req, attributes.requests) { + Attribute *attr = geom->attributes.find(req); + + if (attr) { + /* force a copy if we need to reallocate all the data */ + attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; + } + + update_attribute_element_offset(geom, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_float4, + attr_float4_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + attr, + ATTR_PRIM_GEOMETRY, + req.type, + req.desc); + + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + Attribute *subd_attr = mesh->subd_attributes.find(req); + + if (subd_attr) { + /* force a copy if we need to reallocate all the data */ + subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)]; + } + + update_attribute_element_offset(mesh, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_float4, + attr_float4_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + subd_attr, + ATTR_PRIM_SUBD, + req.subd_type, + req.subd_desc); + } + + if (progress.get_cancel()) + return; + } + } + + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + AttributeRequestSet &attributes = object_attributes[i]; + AttributeSet &values = object_attribute_values[i]; + + foreach (AttributeRequest &req, attributes.requests) { + Attribute *attr = values.find(req); + + if (attr) { + attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; + } + + update_attribute_element_offset(object->geometry, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_float4, + attr_float4_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + attr, + ATTR_PRIM_GEOMETRY, + req.type, + req.desc); + + /* object attributes don't care about subdivision */ + req.subd_type = req.type; + req.subd_desc = req.desc; + + if (progress.get_cancel()) + return; + } + } + + /* create attribute lookup maps */ + if (scene->shader_manager->use_osl()) + update_osl_globals(device, scene); + + update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes); + + if (progress.get_cancel()) + return; + + /* copy to device */ + progress.set_status("Updating Mesh", "Copying Attributes to device"); + + dscene->attributes_float.copy_to_device_if_modified(); + dscene->attributes_float2.copy_to_device_if_modified(); + dscene->attributes_float3.copy_to_device_if_modified(); + dscene->attributes_float4.copy_to_device_if_modified(); + dscene->attributes_uchar4.copy_to_device_if_modified(); + + if (progress.get_cancel()) + return; + + /* After mesh attributes and patch tables have been copied to device memory, + * we need to update offsets in the objects. */ + scene->object_manager->device_update_geom_offsets(device, dscene, scene); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/geometry_bvh.cpp b/intern/cycles/scene/geometry_bvh.cpp new file mode 100644 index 00000000000..9785d1a867a --- /dev/null +++ b/intern/cycles/scene/geometry_bvh.cpp @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "bvh/bvh.h" +#include "bvh/bvh2.h" + +#include "device/device.h" + +#include "scene/attribute.h" +#include "scene/camera.h" +#include "scene/geometry.h" +#include "scene/hair.h" +#include "scene/light.h" +#include "scene/mesh.h" +#include "scene/object.h" +#include "scene/pointcloud.h" +#include "scene/scene.h" +#include "scene/shader.h" +#include "scene/shader_nodes.h" +#include "scene/stats.h" +#include "scene/volume.h" + +#include "subd/patch_table.h" +#include "subd/split.h" + +#include "kernel/osl/globals.h" + +#include "util/foreach.h" +#include "util/log.h" +#include "util/progress.h" +#include "util/task.h" + +CCL_NAMESPACE_BEGIN + +void Geometry::compute_bvh(Device *device, + DeviceScene *dscene, + SceneParams *params, + Progress *progress, + size_t n, + size_t total) +{ + if (progress->get_cancel()) + return; + + compute_bounds(); + + const BVHLayout bvh_layout = BVHParams::best_bvh_layout( + params->bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features)); + if (need_build_bvh(bvh_layout)) { + string msg = "Updating Geometry BVH "; + if (name.empty()) + msg += string_printf("%u/%u", (uint)(n + 1), (uint)total); + else + msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total); + + Object object; + + /* Ensure all visibility bits are set at the geometry level BVH. In + * the object level BVH is where actual visibility is tested. */ + object.set_is_shadow_catcher(true); + object.set_visibility(~0); + + object.set_geometry(this); + + vector geometry; + geometry.push_back(this); + vector objects; + objects.push_back(&object); + + if (bvh && !need_update_rebuild) { + progress->set_status(msg, "Refitting BVH"); + + bvh->replace_geometry(geometry, objects); + + device->build_bvh(bvh, *progress, true); + } + else { + progress->set_status(msg, "Building BVH"); + + BVHParams bparams; + bparams.use_spatial_split = params->use_bvh_spatial_split; + bparams.use_compact_structure = params->use_bvh_compact_structure; + bparams.bvh_layout = bvh_layout; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + params->use_bvh_unaligned_nodes; + bparams.num_motion_triangle_steps = params->num_bvh_time_steps; + bparams.num_motion_curve_steps = params->num_bvh_time_steps; + bparams.num_motion_point_steps = params->num_bvh_time_steps; + bparams.bvh_type = params->bvh_type; + bparams.curve_subdivisions = params->curve_subdivisions(); + + delete bvh; + bvh = BVH::create(bparams, geometry, objects, device); + MEM_GUARDED_CALL(progress, device->build_bvh, bvh, *progress, false); + } + } + + need_update_rebuild = false; + need_update_bvh_for_offset = false; +} + +void GeometryManager::device_update_bvh(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + /* bvh build */ + progress.set_status("Updating Scene BVH", "Building"); + + BVHParams bparams; + bparams.top_level = true; + bparams.bvh_layout = BVHParams::best_bvh_layout( + scene->params.bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features)); + bparams.use_spatial_split = scene->params.use_bvh_spatial_split; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + scene->params.use_bvh_unaligned_nodes; + bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps; + bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps; + bparams.num_motion_point_steps = scene->params.num_bvh_time_steps; + bparams.bvh_type = scene->params.bvh_type; + bparams.curve_subdivisions = scene->params.curve_subdivisions(); + + VLOG_INFO << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout."; + + const bool can_refit = scene->bvh != nullptr && + (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX || + bparams.bvh_layout == BVHLayout::BVH_LAYOUT_METAL); + + BVH *bvh = scene->bvh; + if (!scene->bvh) { + bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device); + } + + device->build_bvh(bvh, progress, can_refit); + + if (progress.get_cancel()) { + return; + } + + const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2); + + PackedBVH pack; + if (has_bvh2_layout) { + pack = std::move(static_cast(bvh)->pack); + } + else { + pack.root_index = -1; + } + + /* copy to device */ + progress.set_status("Updating Scene BVH", "Copying BVH to device"); + + /* When using BVH2, we always have to copy/update the data as its layout is dependent on the + * BVH's leaf nodes which may be different when the objects or vertices move. */ + + if (pack.nodes.size()) { + dscene->bvh_nodes.steal_data(pack.nodes); + dscene->bvh_nodes.copy_to_device(); + } + if (pack.leaf_nodes.size()) { + dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes); + dscene->bvh_leaf_nodes.copy_to_device(); + } + if (pack.object_node.size()) { + dscene->object_node.steal_data(pack.object_node); + dscene->object_node.copy_to_device(); + } + if (pack.prim_type.size()) { + dscene->prim_type.steal_data(pack.prim_type); + dscene->prim_type.copy_to_device(); + } + if (pack.prim_visibility.size()) { + dscene->prim_visibility.steal_data(pack.prim_visibility); + dscene->prim_visibility.copy_to_device(); + } + if (pack.prim_index.size()) { + dscene->prim_index.steal_data(pack.prim_index); + dscene->prim_index.copy_to_device(); + } + if (pack.prim_object.size()) { + dscene->prim_object.steal_data(pack.prim_object); + dscene->prim_object.copy_to_device(); + } + if (pack.prim_time.size()) { + dscene->prim_time.steal_data(pack.prim_time); + dscene->prim_time.copy_to_device(); + } + + dscene->data.bvh.root = pack.root_index; + dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); + dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions(); + /* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */ + dscene->data.device_bvh = 0; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/geometry_mesh.cpp b/intern/cycles/scene/geometry_mesh.cpp new file mode 100644 index 00000000000..954a79f9de7 --- /dev/null +++ b/intern/cycles/scene/geometry_mesh.cpp @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "bvh/bvh.h" +#include "bvh/bvh2.h" + +#include "device/device.h" + +#include "scene/attribute.h" +#include "scene/camera.h" +#include "scene/geometry.h" +#include "scene/hair.h" +#include "scene/light.h" +#include "scene/mesh.h" +#include "scene/object.h" +#include "scene/osl.h" +#include "scene/pointcloud.h" +#include "scene/scene.h" +#include "scene/shader.h" +#include "scene/shader_nodes.h" +#include "scene/stats.h" +#include "scene/volume.h" + +#include "subd/patch_table.h" +#include "subd/split.h" + +#ifdef WITH_OSL +# include "kernel/osl/globals.h" +#endif + +#include "util/foreach.h" +#include "util/log.h" +#include "util/progress.h" +#include "util/task.h" + +CCL_NAMESPACE_BEGIN + +void GeometryManager::device_update_mesh(Device *, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + /* Count. */ + size_t vert_size = 0; + size_t tri_size = 0; + + size_t curve_key_size = 0; + size_t curve_size = 0; + size_t curve_segment_size = 0; + + size_t point_size = 0; + + size_t patch_size = 0; + + foreach (Geometry *geom, scene->geometry) { + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { + Mesh *mesh = static_cast(geom); + + vert_size += mesh->verts.size(); + tri_size += mesh->num_triangles(); + + if (mesh->get_num_subd_faces()) { + Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1); + patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; + + /* patch tables are stored in same array so include them in patch_size */ + if (mesh->patch_table) { + mesh->patch_table_offset = patch_size; + patch_size += mesh->patch_table->total_size(); + } + } + } + else if (geom->is_hair()) { + Hair *hair = static_cast(geom); + + curve_key_size += hair->get_curve_keys().size(); + curve_size += hair->num_curves(); + curve_segment_size += hair->num_segments(); + } + else if (geom->is_pointcloud()) { + PointCloud *pointcloud = static_cast(geom); + point_size += pointcloud->num_points(); + } + } + + /* Fill in all the arrays. */ + if (tri_size != 0) { + /* normals */ + progress.set_status("Updating Mesh", "Computing normals"); + + packed_float3 *tri_verts = dscene->tri_verts.alloc(vert_size); + uint *tri_shader = dscene->tri_shader.alloc(tri_size); + packed_float3 *vnormal = dscene->tri_vnormal.alloc(vert_size); + packed_uint3 *tri_vindex = dscene->tri_vindex.alloc(tri_size); + uint *tri_patch = dscene->tri_patch.alloc(tri_size); + float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); + + const bool copy_all_data = dscene->tri_shader.need_realloc() || + dscene->tri_vindex.need_realloc() || + dscene->tri_vnormal.need_realloc() || + dscene->tri_patch.need_realloc() || + dscene->tri_patch_uv.need_realloc(); + + foreach (Geometry *geom, scene->geometry) { + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { + Mesh *mesh = static_cast(geom); + + if (mesh->shader_is_modified() || mesh->smooth_is_modified() || + mesh->triangles_is_modified() || copy_all_data) { + mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]); + } + + if (mesh->verts_is_modified() || copy_all_data) { + mesh->pack_normals(&vnormal[mesh->vert_offset]); + } + + if (mesh->verts_is_modified() || mesh->triangles_is_modified() || + mesh->vert_patch_uv_is_modified() || copy_all_data) { + mesh->pack_verts(&tri_verts[mesh->vert_offset], + &tri_vindex[mesh->prim_offset], + &tri_patch[mesh->prim_offset], + &tri_patch_uv[mesh->vert_offset]); + } + + if (progress.get_cancel()) + return; + } + } + + /* vertex coordinates */ + progress.set_status("Updating Mesh", "Copying Mesh to device"); + + dscene->tri_verts.copy_to_device_if_modified(); + dscene->tri_shader.copy_to_device_if_modified(); + dscene->tri_vnormal.copy_to_device_if_modified(); + dscene->tri_vindex.copy_to_device_if_modified(); + dscene->tri_patch.copy_to_device_if_modified(); + dscene->tri_patch_uv.copy_to_device_if_modified(); + } + + if (curve_segment_size != 0) { + progress.set_status("Updating Mesh", "Copying Curves to device"); + + float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size); + KernelCurve *curves = dscene->curves.alloc(curve_size); + KernelCurveSegment *curve_segments = dscene->curve_segments.alloc(curve_segment_size); + + const bool copy_all_data = dscene->curve_keys.need_realloc() || + dscene->curves.need_realloc() || + dscene->curve_segments.need_realloc(); + + foreach (Geometry *geom, scene->geometry) { + if (geom->is_hair()) { + Hair *hair = static_cast(geom); + + bool curve_keys_co_modified = hair->curve_radius_is_modified() || + hair->curve_keys_is_modified(); + bool curve_data_modified = hair->curve_shader_is_modified() || + hair->curve_first_key_is_modified(); + + if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) { + continue; + } + + hair->pack_curves(scene, + &curve_keys[hair->curve_key_offset], + &curves[hair->prim_offset], + &curve_segments[hair->curve_segment_offset]); + if (progress.get_cancel()) + return; + } + } + + dscene->curve_keys.copy_to_device_if_modified(); + dscene->curves.copy_to_device_if_modified(); + dscene->curve_segments.copy_to_device_if_modified(); + } + + if (point_size != 0) { + progress.set_status("Updating Mesh", "Copying Point clouds to device"); + + float4 *points = dscene->points.alloc(point_size); + uint *points_shader = dscene->points_shader.alloc(point_size); + + foreach (Geometry *geom, scene->geometry) { + if (geom->is_pointcloud()) { + PointCloud *pointcloud = static_cast(geom); + pointcloud->pack( + scene, &points[pointcloud->prim_offset], &points_shader[pointcloud->prim_offset]); + if (progress.get_cancel()) + return; + } + } + + dscene->points.copy_to_device(); + dscene->points_shader.copy_to_device(); + } + + if (patch_size != 0 && dscene->patches.need_realloc()) { + progress.set_status("Updating Mesh", "Copying Patches to device"); + + uint *patch_data = dscene->patches.alloc(patch_size); + + foreach (Geometry *geom, scene->geometry) { + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + mesh->pack_patches(&patch_data[mesh->patch_offset]); + + if (mesh->patch_table) { + mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], + mesh->patch_table_offset); + } + + if (progress.get_cancel()) + return; + } + } + + dscene->patches.copy_to_device(); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp index ee94e2bd724..2b68d1bd9a6 100644 --- a/intern/cycles/scene/scene.cpp +++ b/intern/cycles/scene/scene.cpp @@ -24,6 +24,7 @@ #include "scene/svm.h" #include "scene/tables.h" #include "scene/volume.h" +#include "scene/devicescene.h" #include "session/session.h" #include "util/foreach.h" @@ -33,59 +34,7 @@ CCL_NAMESPACE_BEGIN -DeviceScene::DeviceScene(Device *device) - : bvh_nodes(device, "bvh_nodes", MEM_GLOBAL), - bvh_leaf_nodes(device, "bvh_leaf_nodes", MEM_GLOBAL), - object_node(device, "object_node", MEM_GLOBAL), - prim_type(device, "prim_type", MEM_GLOBAL), - prim_visibility(device, "prim_visibility", MEM_GLOBAL), - prim_index(device, "prim_index", MEM_GLOBAL), - prim_object(device, "prim_object", MEM_GLOBAL), - prim_time(device, "prim_time", MEM_GLOBAL), - tri_verts(device, "tri_verts", MEM_GLOBAL), - tri_shader(device, "tri_shader", MEM_GLOBAL), - tri_vnormal(device, "tri_vnormal", MEM_GLOBAL), - tri_vindex(device, "tri_vindex", MEM_GLOBAL), - tri_patch(device, "tri_patch", MEM_GLOBAL), - tri_patch_uv(device, "tri_patch_uv", MEM_GLOBAL), - curves(device, "curves", MEM_GLOBAL), - curve_keys(device, "curve_keys", MEM_GLOBAL), - curve_segments(device, "curve_segments", MEM_GLOBAL), - patches(device, "patches", MEM_GLOBAL), - points(device, "points", MEM_GLOBAL), - points_shader(device, "points_shader", MEM_GLOBAL), - objects(device, "objects", MEM_GLOBAL), - object_motion_pass(device, "object_motion_pass", MEM_GLOBAL), - object_motion(device, "object_motion", MEM_GLOBAL), - object_flag(device, "object_flag", MEM_GLOBAL), - object_volume_step(device, "object_volume_step", MEM_GLOBAL), - object_prim_offset(device, "object_prim_offset", MEM_GLOBAL), - camera_motion(device, "camera_motion", MEM_GLOBAL), - attributes_map(device, "attributes_map", MEM_GLOBAL), - attributes_float(device, "attributes_float", MEM_GLOBAL), - attributes_float2(device, "attributes_float2", MEM_GLOBAL), - attributes_float3(device, "attributes_float3", MEM_GLOBAL), - attributes_float4(device, "attributes_float4", MEM_GLOBAL), - attributes_uchar4(device, "attributes_uchar4", MEM_GLOBAL), - light_distribution(device, "light_distribution", MEM_GLOBAL), - lights(device, "lights", MEM_GLOBAL), - light_background_marginal_cdf(device, "light_background_marginal_cdf", MEM_GLOBAL), - light_background_conditional_cdf(device, "light_background_conditional_cdf", MEM_GLOBAL), - light_tree_nodes(device, "light_tree_nodes", MEM_GLOBAL), - light_tree_emitters(device, "light_tree_emitters", MEM_GLOBAL), - light_to_tree(device, "light_to_tree", MEM_GLOBAL), - object_to_tree(device, "object_to_tree", MEM_GLOBAL), - object_lookup_offset(device, "object_lookup_offset", MEM_GLOBAL), - triangle_to_tree(device, "triangle_to_tree", MEM_GLOBAL), - particles(device, "particles", MEM_GLOBAL), - svm_nodes(device, "svm_nodes", MEM_GLOBAL), - shaders(device, "shaders", MEM_GLOBAL), - lookup_table(device, "lookup_table", MEM_GLOBAL), - sample_pattern_lut(device, "sample_pattern_lut", MEM_GLOBAL), - ies_lights(device, "ies", MEM_GLOBAL) -{ - memset((void *)&data, 0, sizeof(data)); -} + Scene::Scene(const SceneParams ¶ms_, Device *device) : name("Scene"), diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h index 8a522d88ac1..742d4db79f3 100644 --- a/intern/cycles/scene/scene.h +++ b/intern/cycles/scene/scene.h @@ -6,20 +6,16 @@ #include "bvh/params.h" +#include "scene/devicescene.h" #include "scene/film.h" #include "scene/image.h" #include "scene/shader.h" -#include "device/device.h" -#include "device/memory.h" - #include "util/param.h" #include "util/string.h" #include "util/system.h" #include "util/texture.h" #include "util/thread.h" -#include "util/types.h" -#include "util/vector.h" CCL_NAMESPACE_BEGIN @@ -54,92 +50,6 @@ class RenderStats; class SceneUpdateStats; class Volume; -/* Scene Device Data */ - -class DeviceScene { - public: - /* BVH */ - device_vector bvh_nodes; - device_vector bvh_leaf_nodes; - device_vector object_node; - device_vector prim_type; - device_vector prim_visibility; - device_vector prim_index; - device_vector prim_object; - device_vector prim_time; - - /* mesh */ - device_vector tri_verts; - device_vector tri_shader; - device_vector tri_vnormal; - device_vector tri_vindex; - device_vector tri_patch; - device_vector tri_patch_uv; - - device_vector curves; - device_vector curve_keys; - device_vector curve_segments; - - device_vector patches; - - /* point-cloud */ - device_vector points; - device_vector points_shader; - - /* objects */ - device_vector objects; - device_vector object_motion_pass; - device_vector object_motion; - device_vector object_flag; - device_vector object_volume_step; - device_vector object_prim_offset; - - /* cameras */ - device_vector camera_motion; - - /* attributes */ - device_vector attributes_map; - device_vector attributes_float; - device_vector attributes_float2; - device_vector attributes_float3; - device_vector attributes_float4; - device_vector attributes_uchar4; - - /* lights */ - device_vector light_distribution; - device_vector lights; - device_vector light_background_marginal_cdf; - device_vector light_background_conditional_cdf; - - /* light tree */ - device_vector light_tree_nodes; - device_vector light_tree_emitters; - device_vector light_to_tree; - device_vector object_to_tree; - device_vector object_lookup_offset; - device_vector triangle_to_tree; - - /* particles */ - device_vector particles; - - /* shaders */ - device_vector svm_nodes; - device_vector shaders; - - /* lookup tables */ - device_vector lookup_table; - - /* integrator */ - device_vector sample_pattern_lut; - - /* IES lights */ - device_vector ies_lights; - - KernelData data; - - DeviceScene(Device *device); -}; - /* Scene Parameters */ class SceneParams { diff --git a/intern/ghost/GHOST_Path-api.hh b/intern/ghost/GHOST_Path-api.hh index 3bc9ca14165..82dbff04ad2 100644 --- a/intern/ghost/GHOST_Path-api.hh +++ b/intern/ghost/GHOST_Path-api.hh @@ -61,7 +61,7 @@ extern const char *GHOST_getBinaryDir(void); /** * Add the file to the operating system most recently used files */ -extern void GHOST_addToSystemRecentFiles(const char *filename); +extern void GHOST_addToSystemRecentFiles(const char *filepath); #ifdef __cplusplus } diff --git a/intern/ghost/intern/GHOST_IXrGraphicsBinding.hh b/intern/ghost/intern/GHOST_IXrGraphicsBinding.hh index ee92f90ca5d..d7cd28270e0 100644 --- a/intern/ghost/intern/GHOST_IXrGraphicsBinding.hh +++ b/intern/ghost/intern/GHOST_IXrGraphicsBinding.hh @@ -57,4 +57,4 @@ class GHOST_IXrGraphicsBinding { }; std::unique_ptr GHOST_XrGraphicsBindingCreateFromType( - GHOST_TXrGraphicsBinding type, GHOST_Context &ghost_ctx); + GHOST_TXrGraphicsBinding type, GHOST_Context &context); diff --git a/intern/ghost/intern/GHOST_SystemWayland.cc b/intern/ghost/intern/GHOST_SystemWayland.cc index 4806dc2e5c8..a90bc4e0d68 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cc +++ b/intern/ghost/intern/GHOST_SystemWayland.cc @@ -5586,8 +5586,6 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background) # endif display_destroy_and_free_all(); throw std::runtime_error("Wayland: unable to find libdecor!"); - - use_libdecor = true; } } else { @@ -5610,7 +5608,7 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background) (void)background; #endif { - GWL_XDG_Decor_System &decor = *display_->xdg_decor; + const GWL_XDG_Decor_System &decor = *display_->xdg_decor; if (!decor.shell) { display_destroy_and_free_all(); throw std::runtime_error("Wayland: unable to access xdg_shell!"); @@ -6071,10 +6069,8 @@ static GHOST_TSuccess getCursorPositionClientRelative_impl( /* As the cursor is restored at the warped location, * apply warping when requesting the cursor location. */ GHOST_Rect wrap_bounds{}; - if (win->getCursorGrabModeIsWarp()) { - if (win->getCursorGrabBounds(wrap_bounds) == GHOST_kFailure) { - win->getClientBounds(wrap_bounds); - } + if (win->getCursorGrabBounds(wrap_bounds) == GHOST_kFailure) { + win->getClientBounds(wrap_bounds); } int xy_wrap[2] = { seat_state_pointer->xy[0], @@ -6680,10 +6676,9 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_custom_set(uint8_t *bitmap, static constexpr uint32_t transparent = 0x00000000; uint8_t datab = 0, maskb = 0; - uint32_t *pixel; for (int y = 0; y < sizey; ++y) { - pixel = &static_cast(cursor->custom_data)[y * sizex]; + uint32_t *pixel = &static_cast(cursor->custom_data)[y * sizex]; for (int x = 0; x < sizex; ++x) { if ((x % 8) == 0) { datab = *bitmap++; diff --git a/intern/ghost/intern/GHOST_SystemWayland.hh b/intern/ghost/intern/GHOST_SystemWayland.hh index faaaa03f46f..0b5984b026d 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.hh +++ b/intern/ghost/intern/GHOST_SystemWayland.hh @@ -37,15 +37,15 @@ bool ghost_wl_output_own(const struct wl_output *wl_output); void ghost_wl_output_tag(struct wl_output *wl_output); struct GWL_Output *ghost_wl_output_user_data(struct wl_output *wl_output); -bool ghost_wl_surface_own(const struct wl_surface *surface); -void ghost_wl_surface_tag(struct wl_surface *surface); -GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *surface); +bool ghost_wl_surface_own(const struct wl_surface *wl_surface); +void ghost_wl_surface_tag(struct wl_surface *wl_surface); +GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *wl_surface); -bool ghost_wl_surface_own_cursor_pointer(const struct wl_surface *surface); -void ghost_wl_surface_tag_cursor_pointer(struct wl_surface *surface); +bool ghost_wl_surface_own_cursor_pointer(const struct wl_surface *wl_surface); +void ghost_wl_surface_tag_cursor_pointer(struct wl_surface *wl_surface); -bool ghost_wl_surface_own_cursor_tablet(const struct wl_surface *surface); -void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *surface); +bool ghost_wl_surface_own_cursor_tablet(const struct wl_surface *wl_surface); +void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *wl_surface); /* Scaling to: translates from WAYLAND into GHOST (viewport local) coordinates. * Scaling from: performs the reverse translation. diff --git a/intern/ghost/intern/GHOST_SystemX11.cc b/intern/ghost/intern/GHOST_SystemX11.cc index d5a33b028be..c204cf78c6c 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cc +++ b/intern/ghost/intern/GHOST_SystemX11.cc @@ -85,7 +85,7 @@ static uchar bit_is_on(const uchar *ptr, int bit) static GHOST_TKey ghost_key_from_keysym(const KeySym key); static GHOST_TKey ghost_key_from_keycode(const XkbDescPtr xkb_descr, const KeyCode keycode); -static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key, +static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key_sym, const XkbDescPtr xkb_descr, const KeyCode keycode); @@ -1776,11 +1776,11 @@ bool GHOST_SystemX11::generateWindowExposeEvents() return anyProcessed; } -static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym keysym, +static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key_sym, XkbDescPtr xkb_descr, const KeyCode keycode) { - GHOST_TKey type = ghost_key_from_keysym(keysym); + GHOST_TKey type = ghost_key_from_keysym(key_sym); if (type == GHOST_kKeyUnknown) { if (xkb_descr) { type = ghost_key_from_keycode(xkb_descr, keycode); diff --git a/intern/ghost/intern/GHOST_SystemX11.hh b/intern/ghost/intern/GHOST_SystemX11.hh index 4314063f2ba..4e8dc4d610a 100644 --- a/intern/ghost/intern/GHOST_SystemX11.hh +++ b/intern/ghost/intern/GHOST_SystemX11.hh @@ -31,7 +31,7 @@ #endif /* generic error handlers */ -int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent); +int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *event); int GHOST_X11_ApplicationIOErrorHandler(Display *display); #define GHOST_X11_ERROR_HANDLERS_OVERRIDE(var) \ diff --git a/intern/ghost/intern/GHOST_Window.hh b/intern/ghost/intern/GHOST_Window.hh index d9d65832dfe..c079e71cc21 100644 --- a/intern/ghost/intern/GHOST_Window.hh +++ b/intern/ghost/intern/GHOST_Window.hh @@ -155,7 +155,7 @@ class GHOST_Window : public GHOST_IWindow { GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) const override; void getCursorGrabState(GHOST_TGrabCursorMode &mode, - GHOST_TAxisFlag &axis_flag, + GHOST_TAxisFlag &wrap_axis, GHOST_Rect &bounds, bool &use_software_cursor) override; /** diff --git a/intern/ghost/intern/GHOST_XrAction.hh b/intern/ghost/intern/GHOST_XrAction.hh index 0b1e9760026..41afce9fada 100644 --- a/intern/ghost/intern/GHOST_XrAction.hh +++ b/intern/ghost/intern/GHOST_XrAction.hh @@ -89,11 +89,13 @@ class GHOST_XrAction { const XrTime &predicted_display_time); void applyHapticFeedback(XrSession session, const char *action_name, - const char *subaction_path, + const char *subaction_path_str, const int64_t &duration, const float &frequency, const float &litude); - void stopHapticFeedback(XrSession session, const char *action_name, const char *subaction_path); + void stopHapticFeedback(XrSession session, + const char *action_name, + const char *subaction_path_str); void *getCustomdata(); void getBindings(std::map> &r_bindings) const; diff --git a/release/datafiles/icons/ops.gpencil.sculpt_average.dat b/release/datafiles/icons/ops.gpencil.sculpt_average.dat new file mode 100644 index 00000000000..f082d7ed114 Binary files /dev/null and b/release/datafiles/icons/ops.gpencil.sculpt_average.dat differ diff --git a/release/datafiles/icons/ops.gpencil.sculpt_blur.dat b/release/datafiles/icons/ops.gpencil.sculpt_blur.dat new file mode 100644 index 00000000000..2128de71dff Binary files /dev/null and b/release/datafiles/icons/ops.gpencil.sculpt_blur.dat differ diff --git a/release/datafiles/icons/ops.gpencil.sculpt_smear.dat b/release/datafiles/icons/ops.gpencil.sculpt_smear.dat new file mode 100644 index 00000000000..36958641266 Binary files /dev/null and b/release/datafiles/icons/ops.gpencil.sculpt_smear.dat differ diff --git a/scripts/modules/bl_keymap_utils/keymap_hierarchy.py b/scripts/modules/bl_keymap_utils/keymap_hierarchy.py index 6215bb9fa9e..21d80a1ed71 100644 --- a/scripts/modules/bl_keymap_utils/keymap_hierarchy.py +++ b/scripts/modules/bl_keymap_utils/keymap_hierarchy.py @@ -204,6 +204,9 @@ _km_hierarchy = [ ('Grease Pencil Stroke Sculpt (Clone)', 'EMPTY', 'WINDOW', []), ('Grease Pencil Stroke Weight Mode', 'EMPTY', 'WINDOW', []), ('Grease Pencil Stroke Weight (Draw)', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Weight (Blur)', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Weight (Average)', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Weight (Smear)', 'EMPTY', 'WINDOW', []), ('Grease Pencil Stroke Vertex Mode', 'EMPTY', 'WINDOW', []), ('Grease Pencil Stroke Vertex (Draw)', 'EMPTY', 'WINDOW', []), ('Grease Pencil Stroke Vertex (Blur)', 'EMPTY', 'WINDOW', []), diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index eda3789e92d..fb2c549ecaf 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -4178,6 +4178,9 @@ def km_grease_pencil_stroke_weight_mode(params): # Brush size ("wm.radial_control", {"type": 'F', "value": 'PRESS'}, {"properties": [("data_path_primary", 'tool_settings.gpencil_weight_paint.brush.size')]}), + # Brush weight + ("wm.radial_control", {"type": 'F', "value": 'PRESS', "ctrl": True}, + {"properties": [("data_path_primary", 'tool_settings.gpencil_weight_paint.brush.weight')]}), # Increase/Decrease brush size ("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True}, {"properties": [("scalar", 0.9)]}), @@ -4197,6 +4200,10 @@ def km_grease_pencil_stroke_weight_mode(params): op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}), # Context menu *_template_items_context_panel("VIEW3D_PT_gpencil_weight_context_menu", params.context_menu_event), + # Toggle Add/Subtract for weight draw tool + ("gpencil.weight_toggle_direction", {"type": 'D', "value": 'PRESS'}, None), + # Weight sample + ("gpencil.weight_sample", {"type": params.action_mouse, "value": 'PRESS', "ctrl": True}, None), ]) if params.select_mouse == 'LEFTMOUSE': @@ -4220,6 +4227,59 @@ def km_grease_pencil_stroke_weight_draw(_params): # Draw ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": [("wait_for_input", False)]}), + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": [("wait_for_input", False)]}), + ]) + + return keymap + + +def km_grease_pencil_stroke_weight_blur(_params): + items = [] + keymap = ( + "Grease Pencil Stroke Weight (Blur)", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": items}, + ) + + items.extend([ + # Blur + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": [("wait_for_input", False)]}), + ]) + + return keymap + + +def km_grease_pencil_stroke_weight_average(_params): + items = [] + keymap = ( + "Grease Pencil Stroke Weight (Average)", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": items}, + ) + + items.extend([ + # Average + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": [("wait_for_input", False)]}), + ]) + + return keymap + + +def km_grease_pencil_stroke_weight_smear(_params): + items = [] + keymap = ( + "Grease Pencil Stroke Weight (Smear)", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": items}, + ) + + items.extend([ + # Smear + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": [("wait_for_input", False)]}), ]) return keymap @@ -8115,6 +8175,9 @@ def generate_keymaps(params=None): km_grease_pencil_stroke_sculpt_clone(params), km_grease_pencil_stroke_weight_mode(params), km_grease_pencil_stroke_weight_draw(params), + km_grease_pencil_stroke_weight_blur(params), + km_grease_pencil_stroke_weight_average(params), + km_grease_pencil_stroke_weight_smear(params), km_grease_pencil_stroke_vertex_mode(params), km_grease_pencil_stroke_vertex_draw(params), km_grease_pencil_stroke_vertex_blur(params), diff --git a/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py index e6fabb886a9..1c6ac26c7e9 100644 --- a/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +++ b/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py @@ -2777,6 +2777,56 @@ def km_grease_pencil_stroke_weight_draw(_params): {"items": items}, ) + items.extend([ + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": [("wait_for_input", False)]}), + ]) + + return keymap + + +def km_grease_pencil_stroke_weight_blur(_params): + items = [] + keymap = ( + "Grease Pencil Stroke Weight (Blur)", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": items}, + ) + + items.extend([ + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": [("wait_for_input", False)]}), + ]) + + return keymap + + +def km_grease_pencil_stroke_weight_average(_params): + items = [] + keymap = ( + "Grease Pencil Stroke Weight (Average)", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": items}, + ) + + items.extend([ + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": [("wait_for_input", False)]}), + ]) + + return keymap + + +def km_grease_pencil_stroke_weight_smear(_params): + items = [] + keymap = ( + "Grease Pencil Stroke Weight (Smear)", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": items}, + ) + items.extend([ ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": [("wait_for_input", False)]}), @@ -4195,6 +4245,9 @@ def generate_keymaps_impl(params=None): km_grease_pencil_stroke_sculpt_clone(params), km_grease_pencil_stroke_weight_mode(params), km_grease_pencil_stroke_weight_draw(params), + km_grease_pencil_stroke_weight_blur(params), + km_grease_pencil_stroke_weight_average(params), + km_grease_pencil_stroke_weight_smear(params), km_grease_pencil_stroke_vertex_mode(params), km_grease_pencil_stroke_vertex_draw(params), km_grease_pencil_stroke_vertex_blur(params), diff --git a/scripts/startup/bl_ui/node_add_menu_geometry.py b/scripts/startup/bl_ui/node_add_menu_geometry.py index e5a3a85af2d..d673f6941b2 100644 --- a/scripts/startup/bl_ui/node_add_menu_geometry.py +++ b/scripts/startup/bl_ui/node_add_menu_geometry.py @@ -220,6 +220,7 @@ class NODE_MT_geometry_node_GEO_GEOMETRY_SAMPLE(Menu): def draw(self, _context): layout = self.layout node_add_menu.add_node_type(layout, "GeometryNodeProximity") + node_add_menu.add_node_type(layout, "GeometryNodeIndexOfNearest") node_add_menu.add_node_type(layout, "GeometryNodeRaycast") node_add_menu.add_node_type(layout, "GeometryNodeSampleIndex") node_add_menu.add_node_type(layout, "GeometryNodeSampleNearest") @@ -528,7 +529,6 @@ class NODE_MT_category_GEO_UTILITIES_FIELD(Menu): node_add_menu.add_node_type(layout, "GeometryNodeAccumulateField") node_add_menu.add_node_type(layout, "GeometryNodeFieldAtIndex") node_add_menu.add_node_type(layout, "GeometryNodeFieldOnDomain") - node_add_menu.add_node_type(layout, "GeometryNodeIndexOfNearest") node_add_menu.draw_assets_for_catalog(layout, self.bl_label) diff --git a/scripts/startup/bl_ui/properties_data_curve.py b/scripts/startup/bl_ui/properties_data_curve.py index a46e849b775..3f93210ea8f 100644 --- a/scripts/startup/bl_ui/properties_data_curve.py +++ b/scripts/startup/bl_ui/properties_data_curve.py @@ -371,10 +371,18 @@ class DATA_PT_font(CurveButtonsPanelText, Panel): row.prop(char, "use_small_caps", toggle=True) else: row = layout.row(align=True) - row.operator("font.style_toggle", text="Bold", icon='BOLD' , depress = text.is_select_bold).style = 'BOLD' - row.operator("font.style_toggle", text="Italic", icon='ITALIC' , depress = text.is_select_italic).style = 'ITALIC' - row.operator("font.style_toggle", text="Underline", icon='UNDERLINE' , depress = text.is_select_underline).style = 'UNDERLINE' - row.operator("font.style_toggle", text="Small Caps", icon='SMALL_CAPS' , depress = text.is_select_smallcaps).style = 'SMALL_CAPS' + row.operator( + "font.style_toggle", text="Bold", icon='BOLD', depress=text.is_select_bold, + ).style = 'BOLD' + row.operator( + "font.style_toggle", text="Italic", icon='ITALIC', depress=text.is_select_italic, + ).style = 'ITALIC' + row.operator( + "font.style_toggle", text="Underline", icon='UNDERLINE', depress=text.is_select_underline, + ).style = 'UNDERLINE' + row.operator( + "font.style_toggle", text="Small Caps", icon='SMALL_CAPS', depress=text.is_select_smallcaps, + ).style = 'SMALL_CAPS' class DATA_PT_font_transform(CurveButtonsPanelText, Panel): diff --git a/scripts/startup/bl_ui/properties_paint_common.py b/scripts/startup/bl_ui/properties_paint_common.py index e99b5466f2b..982e09d7a57 100644 --- a/scripts/startup/bl_ui/properties_paint_common.py +++ b/scripts/startup/bl_ui/properties_paint_common.py @@ -1415,7 +1415,11 @@ def brush_basic_gpencil_weight_settings(layout, _context, brush, *, compact=Fals row.prop(brush, "strength", slider=True) row.prop(brush, "use_pressure_strength", text="") - layout.prop(brush, "weight", slider=True) + if brush.gpencil_weight_tool in {'WEIGHT'}: + layout.prop(brush, "weight", slider=True) + + gp_settings = brush.gpencil_settings + layout.prop(gp_settings, "direction", expand=True, text="" if compact else "Direction") def brush_basic_gpencil_vertex_settings(layout, _context, brush, *, compact=False): diff --git a/scripts/startup/bl_ui/space_filebrowser.py b/scripts/startup/bl_ui/space_filebrowser.py index e52d380f67e..df13bb26e0c 100644 --- a/scripts/startup/bl_ui/space_filebrowser.py +++ b/scripts/startup/bl_ui/space_filebrowser.py @@ -706,6 +706,15 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel): bl_label = "Asset Metadata" bl_options = {'HIDE_HEADER'} + @staticmethod + def metadata_prop(layout, asset_data, propname): + """ + Only display properties that are either set or can be modified (i.e. the + asset is in the current file). Empty, non-editable fields are not really useful. + """ + if getattr(asset_data, propname) or not asset_data.is_property_readonly(propname): + layout.prop(asset_data, propname) + def draw(self, context): layout = self.layout wm = context.window_manager @@ -745,10 +754,11 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel): row.prop(wm, "asset_path_dummy", text="Source", icon='CURRENT_FILE' if is_local_asset else 'NONE') row.operator("asset.open_containing_blend_file", text="", icon='TOOL_SETTINGS') - layout.prop(asset_file_handle.asset_data, "description") - layout.prop(asset_file_handle.asset_data, "license") - layout.prop(asset_file_handle.asset_data, "copyright") - layout.prop(asset_file_handle.asset_data, "author") + asset_data = asset_file_handle.asset_data + self.metadata_prop(layout, asset_data, "description") + self.metadata_prop(layout, asset_data, "license") + self.metadata_prop(layout, asset_data, "copyright") + self.metadata_prop(layout, asset_data, "author") class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel): diff --git a/scripts/startup/bl_ui/space_node.py b/scripts/startup/bl_ui/space_node.py index 564c53ca815..4b40d203c6d 100644 --- a/scripts/startup/bl_ui/space_node.py +++ b/scripts/startup/bl_ui/space_node.py @@ -903,7 +903,10 @@ class NodeTreeInterfacePanel(Panel): props = property_row.operator_menu_enum( "node.tree_socket_change_subtype", "socket_subtype", - text=active_socket.bl_subtype_label if active_socket.bl_subtype_label else active_socket.bl_idname + text=( + active_socket.bl_subtype_label if active_socket.bl_subtype_label else + active_socket.bl_idname + ), ) layout.use_property_split = True diff --git a/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/scripts/startup/bl_ui/space_toolsystem_toolbar.py index e341f39261a..dcc0d4e7efe 100644 --- a/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -68,6 +68,7 @@ def generate_from_enum_ex( dict( idname=idname_prefix + name, label=name, + description=enum.description, icon=icon, cursor=cursor, data_block=idname, diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 74c7bd84112..81c1fe5f159 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -8,6 +8,7 @@ from bpy.types import ( from bl_ui.properties_paint_common import ( UnifiedPaintPanel, brush_basic_texpaint_settings, + brush_basic_gpencil_weight_settings, ) from bl_ui.properties_grease_pencil_common import ( AnnotationDataPanel, @@ -414,11 +415,13 @@ class _draw_tool_settings_context_mode: paint = context.tool_settings.gpencil_weight_paint brush = paint.brush - from bl_ui.properties_paint_common import ( - brush_basic_gpencil_weight_settings, - ) + layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True) + brush_basic_gpencil_weight_settings(layout, context, brush, compact=True) + layout.popover("VIEW3D_PT_tools_grease_pencil_weight_options", text="Options") + layout.popover("VIEW3D_PT_tools_grease_pencil_brush_weight_falloff", text="Falloff") + return True @staticmethod @@ -7662,12 +7665,10 @@ class VIEW3D_PT_gpencil_weight_context_menu(Panel): tool_settings = context.tool_settings settings = tool_settings.gpencil_weight_paint brush = settings.brush - layout = self.layout - layout.prop(brush, "size", slider=True) - layout.prop(brush, "strength") - layout.prop(brush, "weight") + # Weight settings + brush_basic_gpencil_weight_settings(layout, context, brush) # Layers draw_gpencil_layer_active(context, layout) diff --git a/scripts/startup/bl_ui/space_view3d_toolbar.py b/scripts/startup/bl_ui/space_view3d_toolbar.py index fa8d7b928ba..5a9dcf85e42 100644 --- a/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -2021,6 +2021,9 @@ class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel, Gr bl_label = "Brush Settings" def draw(self, context): + if self.is_popover: + return + layout = self.layout layout.use_property_split = True layout.use_property_decorate = False @@ -2029,15 +2032,15 @@ class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel, Gr settings = tool_settings.gpencil_weight_paint brush = settings.brush - if not self.is_popover: - from bl_ui.properties_paint_common import ( - brush_basic_gpencil_weight_settings, - ) - brush_basic_gpencil_weight_settings(layout, context, brush) + from bl_ui.properties_paint_common import ( + brush_basic_gpencil_weight_settings, + ) + brush_basic_gpencil_weight_settings(layout, context, brush) class VIEW3D_PT_tools_grease_pencil_brush_weight_falloff(GreasePencilBrushFalloff, Panel, View3DPaintPanel): bl_context = ".greasepencil_weight" + bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_weight_paint_settings' bl_label = "Falloff" bl_options = {'DEFAULT_CLOSED'} @@ -2049,6 +2052,20 @@ class VIEW3D_PT_tools_grease_pencil_brush_weight_falloff(GreasePencilBrushFallof return (brush and brush.curve) +class VIEW3D_PT_tools_grease_pencil_weight_options(Panel, View3DPanel, GreasePencilWeightPanel): + bl_label = "Options" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + tool_settings = context.scene.tool_settings + + col = layout.column() + col.prop(tool_settings, "use_auto_normalize", text="Auto Normalize") + + # Grease Pencil vertex painting tools class GreasePencilVertexPanel: bl_context = ".greasepencil_vertex" @@ -2425,6 +2442,7 @@ classes = ( VIEW3D_PT_tools_grease_pencil_sculpt_appearance, VIEW3D_PT_tools_grease_pencil_weight_paint_select, VIEW3D_PT_tools_grease_pencil_weight_paint_settings, + VIEW3D_PT_tools_grease_pencil_weight_options, VIEW3D_PT_tools_grease_pencil_weight_appearance, VIEW3D_PT_tools_grease_pencil_vertex_paint_select, VIEW3D_PT_tools_grease_pencil_vertex_paint_settings, diff --git a/source/blender/asset_system/intern/asset_catalog.cc b/source/blender/asset_system/intern/asset_catalog.cc index 6fd01ab14f7..b3e476cda3f 100644 --- a/source/blender/asset_system/intern/asset_catalog.cc +++ b/source/blender/asset_system/intern/asset_catalog.cc @@ -260,6 +260,7 @@ void AssetCatalogService::update_catalog_path(const CatalogID catalog_id, } cat->path = new_path; cat->simple_name_refresh(); + this->tag_has_unsaved_changes(cat); /* TODO(Sybren): go over all assets that are assigned to this catalog, defined in the current * blend file, and update the catalog simple name stored there. */ diff --git a/source/blender/blenkernel/BKE_curves.h b/source/blender/blenkernel/BKE_curves.h index 83a0ba201f8..1cd74cffe0b 100644 --- a/source/blender/blenkernel/BKE_curves.h +++ b/source/blender/blenkernel/BKE_curves.h @@ -28,7 +28,7 @@ bool BKE_curves_attribute_required(const struct Curves *curves, const char *name /* Depsgraph */ -struct Curves *BKE_curves_copy_for_eval(struct Curves *curves_src, bool reference); +struct Curves *BKE_curves_copy_for_eval(struct Curves *curves_src); void BKE_curves_data_update(struct Depsgraph *depsgraph, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index cb8b6e665af..889988cc7d9 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -152,8 +152,6 @@ enum { LIB_ID_COPY_CACHES = 1 << 18, /** Don't copy `id->adt`, used by ID data-block localization routines. */ LIB_ID_COPY_NO_ANIMDATA = 1 << 19, - /** Mesh: Reference CD data layers instead of doing real copy - USE WITH CAUTION! */ - LIB_ID_COPY_CD_REFERENCE = 1 << 20, /** Do not copy id->override_library, used by ID data-block override routines. */ LIB_ID_COPY_NO_LIB_OVERRIDE = 1 << 21, /** When copying local sub-data (like constraints or modifiers), do not set their "library diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 6e909a63b5b..578904dbcc2 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -158,15 +158,15 @@ void BKE_mesh_ensure_skin_customdata(struct Mesh *me); /** Add poly offsets to describe faces to a new mesh. */ void BKE_mesh_poly_offsets_ensure_alloc(struct Mesh *mesh); -struct Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int loops_len, int polys_len); +struct Mesh *BKE_mesh_new_nomain(int verts_num, int edges_num, int polys_num, int loops_num); struct Mesh *BKE_mesh_new_nomain_from_template( - const struct Mesh *me_src, int verts_len, int edges_len, int loops_len, int polys_len); + const struct Mesh *me_src, int verts_num, int edges_num, int polys_num, int loops_num); struct Mesh *BKE_mesh_new_nomain_from_template_ex(const struct Mesh *me_src, - int verts_len, - int edges_len, - int tessface_len, - int loops_len, - int polys_len, + int verts_num, + int edges_num, + int tessface_num, + int polys_num, + int loops_num, struct CustomData_MeshMasks mask); void BKE_mesh_eval_delete(struct Mesh *mesh_eval); @@ -175,7 +175,7 @@ void BKE_mesh_eval_delete(struct Mesh *mesh_eval); * Performs copy for use during evaluation, * optional referencing original arrays to reduce memory. */ -struct Mesh *BKE_mesh_copy_for_eval(const struct Mesh *source, bool reference); +struct Mesh *BKE_mesh_copy_for_eval(const struct Mesh *source); /** * These functions construct a new Mesh, diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 47bc58a2ec7..8553f2fd0fe 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -298,6 +298,12 @@ typedef struct bNodeType { void (*freefunc_api)(struct PointerRNA *ptr); void (*copyfunc_api)(struct PointerRNA *ptr, const struct bNode *src_node); + /** + * An additional poll test for deciding whether nodes should be an option in search menus. + * Potentially more strict poll than #poll(), but doesn't have to check the same things. + */ + bool (*add_ui_poll)(const struct bContext *C); + /** * Can this node type be added to a node tree? * \param r_disabled_hint: Hint to display in the UI when the poll fails. diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h index 6eadac4cced..51ab0ab397e 100644 --- a/source/blender/blenkernel/BKE_pointcloud.h +++ b/source/blender/blenkernel/BKE_pointcloud.h @@ -70,8 +70,7 @@ void *BKE_pointcloud_add(struct Main *bmain, const char *name); void *BKE_pointcloud_add_default(struct Main *bmain, const char *name); struct PointCloud *BKE_pointcloud_new_nomain(int totpoint); void BKE_pointcloud_nomain_to_pointcloud(struct PointCloud *pointcloud_src, - struct PointCloud *pointcloud_dst, - bool take_ownership); + struct PointCloud *pointcloud_dst); struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob); @@ -79,7 +78,7 @@ bool BKE_pointcloud_attribute_required(const struct PointCloud *pointcloud, cons /* Dependency Graph */ -struct PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool reference); +struct PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src); void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_vfont.h b/source/blender/blenkernel/BKE_vfont.h index 73d24bfa155..f410a0a25b0 100644 --- a/source/blender/blenkernel/BKE_vfont.h +++ b/source/blender/blenkernel/BKE_vfont.h @@ -53,8 +53,9 @@ typedef struct EditFont { int selstart, selend; /** - * Combined styles (#CharInfo.flag) for selected string. A flag will be - * set only if ALL characters in the selected string have it. + * Combined styles from #CharInfo.flag for the selected range selected + * (only including values from #CU_CHINFO_STYLE_ALL). + * A flag will be set only if ALL characters in the selected string have it. */ int select_char_info_flag; diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h index 42af44a299e..7c4e6a69d43 100644 --- a/source/blender/blenkernel/BKE_volume.h +++ b/source/blender/blenkernel/BKE_volume.h @@ -130,7 +130,7 @@ void BKE_volume_grid_transform_matrix_set(const struct Volume *volume, * file path. Grids are shared with the source data-block, not copied. */ struct Volume *BKE_volume_new_for_eval(const struct Volume *volume_src); -struct Volume *BKE_volume_copy_for_eval(struct Volume *volume_src, bool reference); +struct Volume *BKE_volume_copy_for_eval(struct Volume *volume_src); struct VolumeGrid *BKE_volume_grid_add(struct Volume *volume, const char *name, diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 89802d9cb71..023d062b9dd 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -380,7 +380,7 @@ static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer) BKE_mesh_ensure_default_orig_index_customdata(mesh); } else { - mesh = BKE_mesh_copy_for_eval(me, true); + mesh = BKE_mesh_copy_for_eval(me); } orco = get_orco_coords(ob, em, layer, &free); @@ -654,7 +654,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, if (ob->modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) { if (mesh_final == nullptr) { - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); ASSERT_IS_VALID_MESH(mesh_final); } MutableAttributeAccessor attributes = mesh_final->attributes_for_write(); @@ -685,7 +685,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, if (mti->type == eModifierTypeType_OnlyDeform && !sculpt_dyntopo) { blender::bke::ScopedModifierTimer modifier_timer{*md}; if (!mesh_final) { - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); ASSERT_IS_VALID_MESH(mesh_final); } BKE_modifier_deform_verts(md, @@ -703,12 +703,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, * places that wish to use the original mesh but with deformed * coordinates (like vertex paint). */ if (r_deform) { - if (mesh_final) { - mesh_deform = BKE_mesh_copy_for_eval(mesh_final, false); - } - else { - mesh_deform = BKE_mesh_copy_for_eval(mesh_input, false); - } + mesh_deform = BKE_mesh_copy_for_eval(mesh_final ? mesh_final : mesh_input); } } @@ -779,7 +774,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, if (mti->type == eModifierTypeType_OnlyDeform) { if (!mesh_final) { - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); ASSERT_IS_VALID_MESH(mesh_final); } BKE_modifier_deform_verts(md, @@ -798,7 +793,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, } } else { - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); ASSERT_IS_VALID_MESH(mesh_final); check_for_needs_mapping = true; } @@ -966,7 +961,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, mesh_final = mesh_input; } else { - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); } } @@ -1011,7 +1006,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* Not yet finalized by any instance, do it now * Isolate since computing normals is multithreaded and we are holding a lock. */ blender::threading::isolate_task([&] { - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); mesh_calc_modifier_final_normals( mesh_input, &final_datamask, sculpt_dyntopo, mesh_final); mesh_calc_finalize(mesh_input, mesh_final); @@ -1026,7 +1021,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, else if (!mesh_has_modifier_final_normals(mesh_input, &final_datamask, runtime->mesh_eval)) { /* Modifier stack was (re-)evaluated with a request for additional normals * different than the instanced mesh, can't instance anymore now. */ - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); mesh_calc_modifier_final_normals(mesh_input, &final_datamask, sculpt_dyntopo, mesh_final); mesh_calc_finalize(mesh_input, mesh_final); } @@ -1255,7 +1250,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, /* apply vertex coordinates or build a DerivedMesh as necessary */ if (mesh_final) { if (deformed_verts) { - Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final, false); + Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final); if (mesh_final != mesh_cage) { BKE_id_free(nullptr, mesh_final); } @@ -1264,7 +1259,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } else if (mesh_final == mesh_cage) { /* 'me' may be changed by this modifier, so we need to copy it. */ - mesh_final = BKE_mesh_copy_for_eval(mesh_final, false); + mesh_final = BKE_mesh_copy_for_eval(mesh_final); } } else { @@ -1337,7 +1332,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (r_cage && i == cageIndex) { if (mesh_final && deformed_verts) { - mesh_cage = BKE_mesh_copy_for_eval(mesh_final, false); + mesh_cage = BKE_mesh_copy_for_eval(mesh_final); BKE_mesh_vert_coords_apply(mesh_cage, deformed_verts); } else if (mesh_final) { @@ -1373,7 +1368,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (mesh_final) { if (deformed_verts) { if (mesh_final == mesh_cage) { - mesh_final = BKE_mesh_copy_for_eval(mesh_final, false); + mesh_final = BKE_mesh_copy_for_eval(mesh_final); } BKE_mesh_vert_coords_apply(mesh_final, deformed_verts); } diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc index 01652c7e2c3..7159c7a6633 100644 --- a/source/blender/blenkernel/intern/brush.cc +++ b/source/blender/blenkernel/intern/brush.cc @@ -1276,14 +1276,57 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) break; } - case GP_BRUSH_PRESET_DRAW_WEIGHT: { + case GP_BRUSH_PRESET_WEIGHT_DRAW: { brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_WEIGHT; brush->gpencil_weight_tool = GPWEIGHT_TOOL_DRAW; brush->size = 25.0f; brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->draw_strength = 0.8f; + brush->alpha = 0.3f; + brush->gpencil_settings->draw_strength = 0.3f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; + + break; + } + case GP_BRUSH_PRESET_WEIGHT_BLUR: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR; + brush->gpencil_weight_tool = GPWEIGHT_TOOL_BLUR; + + brush->size = 50.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->alpha = 0.3f; + brush->gpencil_settings->draw_strength = 0.3f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; + + break; + } + case GP_BRUSH_PRESET_WEIGHT_AVERAGE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR; + brush->gpencil_weight_tool = GPWEIGHT_TOOL_AVERAGE; + + brush->size = 50.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->alpha = 0.3f; + brush->gpencil_settings->draw_strength = 0.3f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; + + break; + } + case GP_BRUSH_PRESET_WEIGHT_SMEAR: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR; + brush->gpencil_weight_tool = GPWEIGHT_TOOL_SMEAR; + + brush->size = 50.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->alpha = 0.3f; + brush->gpencil_settings->draw_strength = 0.3f; brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; @@ -1569,13 +1612,32 @@ void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool Paint *weightpaint = &ts->gp_weightpaint->paint; Brush *brush_prev = weightpaint->brush; Brush *brush, *deft_weight; - /* Vertex Draw brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Draw Weight", OB_MODE_WEIGHT_GPENCIL, &r_new); + + /* Weight Draw brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Weight Draw", OB_MODE_WEIGHT_GPENCIL, &r_new); if ((reset) || (r_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_DRAW_WEIGHT); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_DRAW); } deft_weight = brush; /* save default brush. */ + /* Weight Blur brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Weight Blur", OB_MODE_WEIGHT_GPENCIL, &r_new); + if ((reset) || (r_new)) { + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_BLUR); + } + + /* Weight Average brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Weight Average", OB_MODE_WEIGHT_GPENCIL, &r_new); + if ((reset) || (r_new)) { + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_AVERAGE); + } + + /* Weight Smear brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Weight Smear", OB_MODE_WEIGHT_GPENCIL, &r_new); + if ((reset) || (r_new)) { + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_SMEAR); + } + /* Set default brush. */ if (reset || brush_prev == nullptr) { BKE_paint_brush_set(weightpaint, deft_weight); diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 530445c806c..e0a1e98f164 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -399,7 +399,7 @@ bool BKE_cachefile_filepath_get(const Main *bmain, const int frame = (int)BKE_cachefile_time_offset(cache_file, (double)ctime, fps); char ext[32]; - BLI_path_frame_strip(r_filepath, ext); + BLI_path_frame_strip(r_filepath, ext, sizeof(ext)); BLI_path_frame(r_filepath, frame, frame_len); BLI_path_extension_ensure(r_filepath, FILE_MAX, ext); diff --git a/source/blender/blenkernel/intern/cloth.cc b/source/blender/blenkernel/intern/cloth.cc index 1c27b8b2989..7e9aea008c4 100644 --- a/source/blender/blenkernel/intern/cloth.cc +++ b/source/blender/blenkernel/intern/cloth.cc @@ -1176,7 +1176,7 @@ static void cloth_update_verts(Object *ob, ClothModifierData *clmd, Mesh *mesh) static Mesh *cloth_make_rest_mesh(ClothModifierData *clmd, Mesh *mesh) { using namespace blender; - Mesh *new_mesh = BKE_mesh_copy_for_eval(mesh, false); + Mesh *new_mesh = BKE_mesh_copy_for_eval(mesh); ClothVertex *verts = clmd->clothObject->verts; MutableSpan positions = mesh->vert_positions_for_write(); diff --git a/source/blender/blenkernel/intern/crazyspace.cc b/source/blender/blenkernel/intern/crazyspace.cc index 0dc5004cf2a..7202066b563 100644 --- a/source/blender/blenkernel/intern/crazyspace.cc +++ b/source/blender/blenkernel/intern/crazyspace.cc @@ -389,7 +389,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, if (defmats == nullptr) { /* NOTE: Evaluated object is re-set to its original un-deformed state. */ Mesh *me = static_cast(object_eval.data); - me_eval = BKE_mesh_copy_for_eval(me, true); + me_eval = BKE_mesh_copy_for_eval(me); crazyspace_init_verts_and_matrices(me_eval, &defmats, &deformedVerts); } @@ -470,7 +470,7 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, } if (mesh_eval == nullptr) { - mesh_eval = BKE_mesh_copy_for_eval(mesh, true); + mesh_eval = BKE_mesh_copy_for_eval(mesh); } mti->deformVerts(md, &mectx, mesh_eval, deformedVerts, mesh_eval->totvert); diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index 45bbca42871..484ed7e71a0 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -691,7 +691,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, } Mesh *mesh = BKE_mesh_new_nomain( - offsets.vert.last(), offsets.edge.last(), offsets.loop.last(), offsets.poly.last()); + offsets.vert.last(), offsets.edge.last(), offsets.poly.last(), offsets.loop.last()); mesh->flag |= ME_AUTOSMOOTH; mesh->smoothresh = DEG2RADF(180.0f); MutableSpan positions = mesh->vert_positions_for_write(); diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index 59866c40e05..b8af50dc1f5 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -220,16 +220,10 @@ bool BKE_curves_attribute_required(const Curves * /*curves*/, const char *name) return STREQ(name, ATTR_POSITION); } -Curves *BKE_curves_copy_for_eval(Curves *curves_src, bool reference) +Curves *BKE_curves_copy_for_eval(Curves *curves_src) { - int flags = LIB_ID_COPY_LOCALIZE; - - if (reference) { - flags |= LIB_ID_COPY_CD_REFERENCE; - } - - Curves *result = (Curves *)BKE_id_copy_ex(nullptr, &curves_src->id, nullptr, flags); - return result; + return reinterpret_cast( + BKE_id_copy_ex(nullptr, &curves_src->id, nullptr, LIB_ID_COPY_LOCALIZE)); } static void curves_evaluate_modifiers(struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/intern/dynamicpaint.cc b/source/blender/blenkernel/intern/dynamicpaint.cc index 41c2645da5b..3b107c04118 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.cc +++ b/source/blender/blenkernel/intern/dynamicpaint.cc @@ -1904,7 +1904,7 @@ static void dynamic_paint_apply_surface_wave_cb(void *__restrict userdata, */ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh) { - Mesh *result = BKE_mesh_copy_for_eval(mesh, false); + Mesh *result = BKE_mesh_copy_for_eval(mesh); if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING) && pmd->type == MOD_DYNAMICPAINT_TYPE_CANVAS) { @@ -2049,7 +2049,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * if (runtime_data->brush_mesh != nullptr) { BKE_id_free(nullptr, runtime_data->brush_mesh); } - runtime_data->brush_mesh = BKE_mesh_copy_for_eval(result, false); + runtime_data->brush_mesh = BKE_mesh_copy_for_eval(result); } return result; @@ -2070,7 +2070,7 @@ static void canvas_copyMesh(DynamicPaintCanvasSettings *canvas, Mesh *mesh) BKE_id_free(nullptr, runtime->canvas_mesh); } - runtime->canvas_mesh = BKE_mesh_copy_for_eval(mesh, false); + runtime->canvas_mesh = BKE_mesh_copy_for_eval(mesh); } /* @@ -3796,7 +3796,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph, SUBFRAME_RECURSION, BKE_scene_ctime_get(scene), eModifierType_DynamicPaint); - mesh_p = BKE_mesh_copy_for_eval(dynamicPaint_brush_mesh_get(brush), false); + mesh_p = BKE_mesh_copy_for_eval(dynamicPaint_brush_mesh_get(brush)); numOfVerts_p = mesh_p->totvert; float(*positions_p)[3] = BKE_mesh_vert_positions_for_write(mesh_p); @@ -4282,7 +4282,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph, Bounds3D mesh_bb = {{0}}; VolumeGrid *grid = bData->grid; - mesh = BKE_mesh_copy_for_eval(brush_mesh, false); + mesh = BKE_mesh_copy_for_eval(brush_mesh); float(*positions)[3] = BKE_mesh_vert_positions_for_write(mesh); const blender::Span vert_normals = mesh->vert_normals(); const blender::Span corner_verts = mesh->corner_verts(); diff --git a/source/blender/blenkernel/intern/fluid.cc b/source/blender/blenkernel/intern/fluid.cc index 88105132d83..a45bf709b31 100644 --- a/source/blender/blenkernel/intern/fluid.cc +++ b/source/blender/blenkernel/intern/fluid.cc @@ -1003,7 +1003,7 @@ static void obstacles_from_mesh(Object *coll_ob, float *vert_vel = nullptr; bool has_velocity = false; - Mesh *me = BKE_mesh_copy_for_eval(fes->mesh, false); + Mesh *me = BKE_mesh_copy_for_eval(fes->mesh); float(*positions)[3] = BKE_mesh_vert_positions_for_write(me); int min[3], max[3], res[3]; @@ -2062,7 +2062,7 @@ static void emit_from_mesh( /* Copy mesh for thread safety as we modify it. * Main issue is its VertArray being modified, then replaced and freed. */ - Mesh *me = BKE_mesh_copy_for_eval(ffs->mesh, false); + Mesh *me = BKE_mesh_copy_for_eval(ffs->mesh); float(*positions)[3] = BKE_mesh_vert_positions_for_write(me); const blender::Span corner_verts = me->corner_verts(); @@ -3229,7 +3229,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, return nullptr; } - me = BKE_mesh_new_nomain(num_verts, 0, num_faces * 3, num_faces); + me = BKE_mesh_new_nomain(num_verts, 0, num_faces, num_faces * 3); if (!me) { return nullptr; } @@ -3364,10 +3364,10 @@ static Mesh *create_smoke_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Obje /* Just copy existing mesh if there is no content or if the adaptive domain is not being used. */ if (fds->total_cells <= 1 || (fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0) { - return BKE_mesh_copy_for_eval(orgmesh, false); + return BKE_mesh_copy_for_eval(orgmesh); } - result = BKE_mesh_new_nomain(num_verts, 0, num_faces * 4, num_faces); + result = BKE_mesh_new_nomain(num_verts, 0, num_faces, num_faces * 4); float(*positions)[3] = BKE_mesh_vert_positions_for_write(result); blender::MutableSpan poly_offsets = result->poly_offsets_for_write(); blender::MutableSpan corner_verts = result->corner_verts_for_write(); @@ -3590,7 +3590,7 @@ static void fluid_modifier_processFlow(FluidModifierData *fmd, if (fmd->flow->mesh) { BKE_id_free(nullptr, fmd->flow->mesh); } - fmd->flow->mesh = BKE_mesh_copy_for_eval(me, false); + fmd->flow->mesh = BKE_mesh_copy_for_eval(me); } if (scene_framenr > fmd->time) { @@ -3617,7 +3617,7 @@ static void fluid_modifier_processEffector(FluidModifierData *fmd, if (fmd->effector->mesh) { BKE_id_free(nullptr, fmd->effector->mesh); } - fmd->effector->mesh = BKE_mesh_copy_for_eval(me, false); + fmd->effector->mesh = BKE_mesh_copy_for_eval(me); } if (scene_framenr > fmd->time) { @@ -4125,7 +4125,7 @@ Mesh *BKE_fluid_modifier_do( } if (!result) { - result = BKE_mesh_copy_for_eval(me, false); + result = BKE_mesh_copy_for_eval(me); } else { BKE_mesh_copy_parameters_for_eval(result, me); diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc index eb185d979a8..62f8e50a3b7 100644 --- a/source/blender/blenkernel/intern/geometry_component_curves.cc +++ b/source/blender/blenkernel/intern/geometry_component_curves.cc @@ -33,7 +33,7 @@ GeometryComponent *CurveComponent::copy() const { CurveComponent *new_component = new CurveComponent(); if (curves_ != nullptr) { - new_component->curves_ = BKE_curves_copy_for_eval(curves_, false); + new_component->curves_ = BKE_curves_copy_for_eval(curves_); new_component->ownership_ = GeometryOwnershipType::Owned; } return new_component; @@ -87,7 +87,7 @@ Curves *CurveComponent::get_for_write() { BLI_assert(this->is_mutable()); if (ownership_ == GeometryOwnershipType::ReadOnly) { - curves_ = BKE_curves_copy_for_eval(curves_, false); + curves_ = BKE_curves_copy_for_eval(curves_); ownership_ = GeometryOwnershipType::Owned; } return curves_; @@ -107,7 +107,7 @@ void CurveComponent::ensure_owns_direct_data() { BLI_assert(this->is_mutable()); if (ownership_ != GeometryOwnershipType::Owned) { - curves_ = BKE_curves_copy_for_eval(curves_, false); + curves_ = BKE_curves_copy_for_eval(curves_); ownership_ = GeometryOwnershipType::Owned; } } diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 0f70d9ac48a..62bc979eb6e 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -36,7 +36,7 @@ GeometryComponent *MeshComponent::copy() const { MeshComponent *new_component = new MeshComponent(); if (mesh_ != nullptr) { - new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false); + new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_); new_component->ownership_ = GeometryOwnershipType::Owned; } return new_component; @@ -83,7 +83,7 @@ Mesh *MeshComponent::get_for_write() { BLI_assert(this->is_mutable()); if (ownership_ == GeometryOwnershipType::ReadOnly) { - mesh_ = BKE_mesh_copy_for_eval(mesh_, false); + mesh_ = BKE_mesh_copy_for_eval(mesh_); ownership_ = GeometryOwnershipType::Owned; } return mesh_; @@ -103,7 +103,7 @@ void MeshComponent::ensure_owns_direct_data() { BLI_assert(this->is_mutable()); if (ownership_ != GeometryOwnershipType::Owned) { - mesh_ = BKE_mesh_copy_for_eval(mesh_, false); + mesh_ = BKE_mesh_copy_for_eval(mesh_); ownership_ = GeometryOwnershipType::Owned; } } diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc index 267daad48d7..0e43a83ed31 100644 --- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -23,7 +23,7 @@ GeometryComponent *PointCloudComponent::copy() const { PointCloudComponent *new_component = new PointCloudComponent(); if (pointcloud_ != nullptr) { - new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); + new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_); new_component->ownership_ = GeometryOwnershipType::Owned; } return new_component; @@ -70,7 +70,7 @@ PointCloud *PointCloudComponent::get_for_write() { BLI_assert(this->is_mutable()); if (ownership_ == GeometryOwnershipType::ReadOnly) { - pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); + pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_); ownership_ = GeometryOwnershipType::Owned; } return pointcloud_; @@ -90,7 +90,7 @@ void PointCloudComponent::ensure_owns_direct_data() { BLI_assert(this->is_mutable()); if (ownership_ != GeometryOwnershipType::Owned) { - pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); + pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_); ownership_ = GeometryOwnershipType::Owned; } } diff --git a/source/blender/blenkernel/intern/geometry_component_volume.cc b/source/blender/blenkernel/intern/geometry_component_volume.cc index 405521675cc..9fdffdeb473 100644 --- a/source/blender/blenkernel/intern/geometry_component_volume.cc +++ b/source/blender/blenkernel/intern/geometry_component_volume.cc @@ -21,7 +21,7 @@ GeometryComponent *VolumeComponent::copy() const { VolumeComponent *new_component = new VolumeComponent(); if (volume_ != nullptr) { - new_component->volume_ = BKE_volume_copy_for_eval(volume_, false); + new_component->volume_ = BKE_volume_copy_for_eval(volume_); new_component->ownership_ = GeometryOwnershipType::Owned; } return new_component; @@ -68,7 +68,7 @@ Volume *VolumeComponent::get_for_write() { BLI_assert(this->is_mutable()); if (ownership_ == GeometryOwnershipType::ReadOnly) { - volume_ = BKE_volume_copy_for_eval(volume_, false); + volume_ = BKE_volume_copy_for_eval(volume_); ownership_ = GeometryOwnershipType::Owned; } return volume_; @@ -83,7 +83,7 @@ void VolumeComponent::ensure_owns_direct_data() { BLI_assert(this->is_mutable()); if (ownership_ != GeometryOwnershipType::Owned) { - volume_ = BKE_volume_copy_for_eval(volume_, false); + volume_ = BKE_volume_copy_for_eval(volume_); ownership_ = GeometryOwnershipType::Owned; } } diff --git a/source/blender/blenkernel/intern/mball_tessellate.cc b/source/blender/blenkernel/intern/mball_tessellate.cc index 8c936cead41..96cb2cc7e52 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.cc +++ b/source/blender/blenkernel/intern/mball_tessellate.cc @@ -1451,18 +1451,17 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) freepolygonize(&process); - Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name + 2); + int corners_num = 0; + for (uint i = 0; i < process.curindex; i++) { + const int *indices = process.indices[i]; + const int count = indices[2] != indices[3] ? 4 : 3; + corners_num += count; + } - mesh->totvert = int(process.co.size()); - CustomData_add_layer_named( - &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh->totvert, "position"); + Mesh *mesh = BKE_mesh_new_nomain(int(process.co.size()), 0, int(process.curindex), corners_num); mesh->vert_positions_for_write().copy_from(process.co); - - mesh->totpoly = int(process.curindex); - BKE_mesh_poly_offsets_ensure_alloc(mesh); blender::MutableSpan poly_offsets = mesh->poly_offsets_for_write(); - int *corner_verts = static_cast(CustomData_add_layer_named( - &mesh->ldata, CD_PROP_INT32, CD_CONSTRUCT, mesh->totpoly * 4, ".corner_vert")); + blender::MutableSpan corner_verts = mesh->corner_verts_for_write(); int loop_offset = 0; for (int i = 0; i < mesh->totpoly; i++) { @@ -1490,9 +1489,6 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) sizeof(float[3]) * size_t(mesh->totvert)); BKE_mesh_vert_normals_clear_dirty(mesh); - mesh->totloop = loop_offset; - poly_offsets.last() = loop_offset; - BKE_mesh_calc_edges(mesh, false, false); return mesh; diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 538a4806bed..f7c032e2867 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1032,23 +1032,19 @@ static void mesh_ensure_cdlayers_primary(Mesh &mesh) } } -Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int loops_len, int polys_len) +Mesh *BKE_mesh_new_nomain(const int verts_num, + const int edges_num, + const int polys_num, + const int loops_num) { - Mesh *mesh = (Mesh *)BKE_libblock_alloc( - nullptr, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE); + Mesh *mesh = static_cast(BKE_libblock_alloc( + nullptr, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE)); BKE_libblock_init_empty(&mesh->id); - /* Don't use #CustomData_reset because we don't want to touch custom-data. */ - copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1); - copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1); - copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1); - copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1); - copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1); - - mesh->totvert = verts_len; - mesh->totedge = edges_len; - mesh->totloop = loops_len; - mesh->totpoly = polys_len; + mesh->totvert = verts_num; + mesh->totedge = edges_num; + mesh->totpoly = polys_num; + mesh->totloop = loops_num; mesh_ensure_cdlayers_primary(*mesh); BKE_mesh_poly_offsets_ensure_alloc(mesh); @@ -1112,35 +1108,35 @@ void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src) } Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, - int verts_len, - int edges_len, - int tessface_len, - int loops_len, - int polys_len, - CustomData_MeshMasks mask) + const int verts_num, + const int edges_num, + const int tessface_num, + const int polys_num, + const int loops_num, + const CustomData_MeshMasks mask) { /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */ - const bool do_tessface = (tessface_len || ((me_src->totface != 0) && (me_src->totpoly == 0))); + const bool do_tessface = (tessface_num || ((me_src->totface != 0) && (me_src->totpoly == 0))); Mesh *me_dst = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); me_dst->mselect = (MSelect *)MEM_dupallocN(me_src->mselect); - me_dst->totvert = verts_len; - me_dst->totedge = edges_len; - me_dst->totface = tessface_len; - me_dst->totloop = loops_len; - me_dst->totpoly = polys_len; + me_dst->totvert = verts_num; + me_dst->totedge = edges_num; + me_dst->totpoly = polys_num; + me_dst->totloop = loops_num; + me_dst->totface = tessface_num; BKE_mesh_copy_parameters_for_eval(me_dst, me_src); - CustomData_copy_layout(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len); - CustomData_copy_layout(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len); - CustomData_copy_layout(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len); - CustomData_copy_layout(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len); + CustomData_copy_layout(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_num); + CustomData_copy_layout(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_num); + CustomData_copy_layout(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_num); + CustomData_copy_layout(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_num); if (do_tessface) { CustomData_copy_layout( - &me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len); + &me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_num); } else { mesh_tessface_clear_intern(me_dst, false); @@ -1160,11 +1156,14 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, return me_dst; } -Mesh *BKE_mesh_new_nomain_from_template( - const Mesh *me_src, int verts_len, int edges_len, int loops_len, int polys_len) +Mesh *BKE_mesh_new_nomain_from_template(const Mesh *me_src, + const int verts_num, + const int edges_num, + const int polys_num, + const int loops_num) { return BKE_mesh_new_nomain_from_template_ex( - me_src, verts_len, edges_len, 0, loops_len, polys_len, CD_MASK_EVERYTHING); + me_src, verts_num, edges_num, 0, polys_num, loops_num, CD_MASK_EVERYTHING); } void BKE_mesh_eval_delete(struct Mesh *mesh_eval) @@ -1176,16 +1175,10 @@ void BKE_mesh_eval_delete(struct Mesh *mesh_eval) MEM_freeN(mesh_eval); } -Mesh *BKE_mesh_copy_for_eval(const Mesh *source, bool reference) +Mesh *BKE_mesh_copy_for_eval(const Mesh *source) { - int flags = LIB_ID_COPY_LOCALIZE; - - if (reference) { - flags |= LIB_ID_COPY_CD_REFERENCE; - } - - Mesh *result = (Mesh *)BKE_id_copy_ex(nullptr, &source->id, nullptr, flags); - return result; + return reinterpret_cast( + BKE_id_copy_ex(nullptr, &source->id, nullptr, LIB_ID_COPY_LOCALIZE)); } BMesh *BKE_mesh_to_bmesh_ex(const Mesh *me, diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index cd7d7d88982..c00ba6d5008 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -700,7 +700,7 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim) } /* Will calculate edges later. */ Mesh *result = BKE_mesh_new_nomain_from_template( - mim.meshes[0], out_totvert, 0, out_totloop, out_totpoly); + mim.meshes[0], out_totvert, 0, out_totpoly, out_totloop); merge_vertex_loop_poly_customdata_layers(result, mim); /* Set the vertex coordinate values and other data. */ diff --git a/source/blender/blenkernel/intern/mesh_calc_edges.cc b/source/blender/blenkernel/intern/mesh_calc_edges.cc index ddb587ea993..203f41863bd 100644 --- a/source/blender/blenkernel/intern/mesh_calc_edges.cc +++ b/source/blender/blenkernel/intern/mesh_calc_edges.cc @@ -151,14 +151,13 @@ static void serialize_and_initialize_deduplicated_edges(MutableSpan edg }); } -static void update_edge_indices_in_poly_loops(Mesh *mesh, - Span edge_maps, - uint32_t parallel_mask) +static void update_edge_indices_in_poly_loops(const OffsetIndices polys, + const Span corner_verts, + const Span edge_maps, + const uint32_t parallel_mask, + MutableSpan corner_edges) { - const OffsetIndices polys = mesh->polys(); - const Span corner_verts = mesh->corner_verts(); - MutableSpan corner_edges = mesh->corner_edges_for_write(); - threading::parallel_for(IndexRange(mesh->totpoly), 100, [&](IndexRange range) { + threading::parallel_for(polys.index_range(), 100, [&](IndexRange range) { for (const int poly_index : range) { const IndexRange poly = polys[poly_index]; int prev_corner = poly.last(); @@ -239,7 +238,11 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select MutableSpan new_edges{ static_cast(MEM_calloc_arrayN(new_totedge, sizeof(int2), __func__)), new_totedge}; calc_edges::serialize_and_initialize_deduplicated_edges(edge_maps, new_edges); - calc_edges::update_edge_indices_in_poly_loops(mesh, edge_maps, parallel_mask); + calc_edges::update_edge_indices_in_poly_loops(mesh->polys(), + mesh->corner_verts(), + edge_maps, + parallel_mask, + mesh->corner_edges_for_write()); /* Free old CustomData and assign new one. */ CustomData_free(&mesh->edata, mesh->totedge); diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index c1decc6b9cb..40dbc03586f 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -62,98 +62,8 @@ using blender::MutableSpan; using blender::Span; using blender::StringRefNull; -/* Define for cases when you want extra validation of mesh - * after certain modifications. - */ -// #undef VALIDATE_MESH - -#ifdef VALIDATE_MESH -# define ASSERT_IS_VALID_MESH(mesh) \ - (BLI_assert((mesh == nullptr) || (BKE_mesh_is_valid(mesh) == true))) -#else -# define ASSERT_IS_VALID_MESH(mesh) -#endif - static CLG_LogRef LOG = {"bke.mesh_convert"}; -static void poly_edgehash_insert(EdgeHash *ehash, const Span poly_verts) -{ - int i = poly_verts.size(); - - int next = 0; /* first loop */ - int poly_corner = (i - 1); /* last loop */ - - while (i-- != 0) { - BLI_edgehash_reinsert(ehash, poly_verts[poly_corner], poly_verts[next], nullptr); - - poly_corner = next; - next++; - } -} - -/** - * Specialized function to use when we _know_ existing edges don't overlap with poly edges. - */ -static void make_edges_mdata_extend(Mesh &mesh) -{ - int totedge = mesh.totedge; - - const blender::OffsetIndices polys = mesh.polys(); - const Span corner_verts = mesh.corner_verts(); - MutableSpan corner_edges = mesh.corner_edges_for_write(); - - const int eh_reserve = max_ii(totedge, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(mesh.totpoly)); - EdgeHash *eh = BLI_edgehash_new_ex(__func__, eh_reserve); - - for (const int i : polys.index_range()) { - poly_edgehash_insert(eh, corner_verts.slice(polys[i])); - } - - const int totedge_new = BLI_edgehash_len(eh); - -#ifdef DEBUG - /* ensure that there's no overlap! */ - if (totedge_new) { - for (const blender::int2 &edge : mesh.edges()) { - BLI_assert(BLI_edgehash_haskey(eh, edge[0], edge[1]) == false); - } - } -#endif - - if (totedge_new) { - /* The only layer should be edges, so no other layers need to be initialized. */ - BLI_assert(mesh.edata.totlayer == 1); - CustomData_realloc(&mesh.edata, totedge, totedge + totedge_new); - mesh.totedge += totedge_new; - MutableSpan edges = mesh.edges_for_write(); - blender::int2 *edge = &edges[totedge]; - - EdgeHashIterator *ehi; - uint e_index = totedge; - for (ehi = BLI_edgehashIterator_new(eh); BLI_edgehashIterator_isDone(ehi) == false; - BLI_edgehashIterator_step(ehi), ++edge, e_index++) { - BLI_edgehashIterator_getKey(ehi, &(*edge)[0], &(*edge)[1]); - BLI_edgehashIterator_setValue(ehi, POINTER_FROM_UINT(e_index)); - } - BLI_edgehashIterator_free(ehi); - - for (const int i : polys.index_range()) { - const IndexRange poly = polys[i]; - int corner = poly.start(); - int corner_prev = poly.start() + (poly.size() - 1); - int j; - for (j = 0; j < poly.size(); j++, corner++) { - /* lookup hashed edge index */ - corner_edges[corner_prev] = POINTER_AS_UINT( - BLI_edgehash_lookup(eh, corner_verts[corner_prev], corner_verts[corner])); - corner_prev = corner; - } - } - } - - BLI_edgehash_free(eh, nullptr); -} - static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispbase) { using namespace blender::bke; @@ -203,7 +113,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba return BKE_mesh_new_nomain(0, 0, 0, 0); } - Mesh *mesh = BKE_mesh_new_nomain(totvert, totedge, totloop, totpoly); + Mesh *mesh = BKE_mesh_new_nomain(totvert, totedge, totpoly, totloop); MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan edges = mesh->edges_for_write(); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); @@ -393,7 +303,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba } if (totpoly) { - make_edges_mdata_extend(*mesh); + BKE_mesh_calc_edges(mesh, true, false); } material_indices.finish(); @@ -783,7 +693,7 @@ static const Curves *get_evaluated_curves_from_object(const Object *object) static Mesh *mesh_new_from_evaluated_curve_type_object(const Object *evaluated_object) { if (const Mesh *mesh = BKE_object_get_evaluated_mesh(evaluated_object)) { - return BKE_mesh_copy_for_eval(mesh, false); + return BKE_mesh_copy_for_eval(mesh); } if (const Curves *curves = get_evaluated_curves_from_object(evaluated_object)) { const blender::bke::AnonymousAttributePropagationInfo propagation_info; @@ -842,7 +752,7 @@ static Mesh *mesh_new_from_mball_object(Object *object) return (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); } - return BKE_mesh_copy_for_eval(mesh_eval, false); + return BKE_mesh_copy_for_eval(mesh_eval); } static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh) diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 151bcf67b79..116e3db14bf 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -2197,7 +2197,10 @@ void BKE_mesh_legacy_attribute_strings_to_flags(Mesh *mesh) CustomData_clear_layer_flag( vdata, CD_PROP_BYTE_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER); + CustomData_clear_layer_flag( + ldata, CD_PROP_BYTE_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER); CustomData_clear_layer_flag(ldata, CD_PROP_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER); + CustomData_clear_layer_flag(vdata, CD_PROP_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER); if (const char *name = mesh->active_color_attribute) { int i; diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index d2169960c97..7ad5b5d2907 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -191,7 +191,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, const int src_loops_num = mesh->totloop; Mesh *result = BKE_mesh_new_nomain_from_template( - mesh, src_verts_num * 2, src_edges_num * 2, src_loops_num * 2, src_polys.size() * 2); + mesh, src_verts_num * 2, src_edges_num * 2, src_polys.size() * 2, src_loops_num * 2); /* Copy custom-data to original geometry. */ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, src_verts_num); diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index aa0aecb676f..be66df2e7e0 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -117,7 +117,7 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh, } /* Construct the new output mesh */ - Mesh *mesh = BKE_mesh_new_nomain(qrd.out_totverts, 0, qrd.out_totfaces * 4, qrd.out_totfaces); + Mesh *mesh = BKE_mesh_new_nomain(qrd.out_totverts, 0, qrd.out_totfaces, qrd.out_totfaces * 4); BKE_mesh_copy_parameters(mesh, input_mesh); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); MutableSpan corner_verts = mesh->corner_verts_for_write(); @@ -222,7 +222,7 @@ static Mesh *remesh_voxel_volume_to_mesh(const openvdb::FloatGrid::Ptr level_set *level_set_grid, vertices, tris, quads, isovalue, adaptivity, relax_disoriented_triangles); Mesh *mesh = BKE_mesh_new_nomain( - vertices.size(), 0, quads.size() * 4 + tris.size() * 3, quads.size() + tris.size()); + vertices.size(), 0, quads.size() + tris.size(), quads.size() * 4 + tris.size() * 3); MutableSpan vert_positions = mesh->vert_positions_for_write(); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); MutableSpan mesh_corner_verts = mesh->corner_verts_for_write(); @@ -317,8 +317,7 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source) const OffsetIndices target_polys = target->polys(); const Span target_corner_verts = target->corner_verts(); - const VArray src_face_sets = - * src_attributes.lookup(".sculpt_face_set", ATTR_DOMAIN_FACE); + const VArray src_face_sets = *src_attributes.lookup(".sculpt_face_set", ATTR_DOMAIN_FACE); if (!src_face_sets) { return; } diff --git a/source/blender/blenkernel/intern/multires.cc b/source/blender/blenkernel/intern/multires.cc index fde8f8b842f..0cd8cf5079c 100644 --- a/source/blender/blenkernel/intern/multires.cc +++ b/source/blender/blenkernel/intern/multires.cc @@ -241,7 +241,7 @@ Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph, Mesh *result = mti->modifyMesh(&mmd->modifier, &modifier_ctx, deformed_mesh); if (result == deformed_mesh) { - result = BKE_mesh_copy_for_eval(deformed_mesh, true); + result = BKE_mesh_copy_for_eval(deformed_mesh); } return result; } diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index c342c82176a..f06d560955c 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -249,9 +249,7 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint) return pointcloud; } -void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src, - PointCloud *pointcloud_dst, - bool take_ownership) +void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src, PointCloud *pointcloud_dst) { BLI_assert(pointcloud_src->id.tag & LIB_TAG_NO_MAIN); @@ -260,9 +258,7 @@ void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src, const int totpoint = pointcloud_dst->totpoint = pointcloud_src->totpoint; CustomData_copy(&pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, totpoint); - if (take_ownership) { - BKE_id_free(nullptr, pointcloud_src); - } + BKE_id_free(nullptr, pointcloud_src); } bool PointCloud::bounds_min_max(blender::float3 &min, blender::float3 &max) const @@ -322,16 +318,10 @@ bool BKE_pointcloud_attribute_required(const PointCloud * /*pointcloud*/, const /* Dependency Graph */ -PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool reference) +PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src) { - int flags = LIB_ID_COPY_LOCALIZE; - - if (reference) { - flags |= LIB_ID_COPY_CD_REFERENCE; - } - - PointCloud *result = (PointCloud *)BKE_id_copy_ex(nullptr, &pointcloud_src->id, nullptr, flags); - return result; + return reinterpret_cast( + BKE_id_copy_ex(nullptr, &pointcloud_src->id, nullptr, LIB_ID_COPY_LOCALIZE)); } static void pointcloud_evaluate_modifiers(struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc index 9c7893d6de9..fa4a08a178d 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.cc +++ b/source/blender/blenkernel/intern/subdiv_mesh.cc @@ -532,7 +532,7 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex SubdivMeshContext *subdiv_context = static_cast(foreach_context->user_data); subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template_ex( - subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_loops, num_polygons, mask); + subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_polygons, num_loops, mask); subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context); subdiv_mesh_prepare_accumulator(subdiv_context, num_vertices); subdiv_context->subdiv_mesh->runtime->subsurf_face_dot_tags.clear(); diff --git a/source/blender/blenkernel/intern/vfont.c b/source/blender/blenkernel/intern/vfont.c index f7a3b18b438..20b772d6c78 100644 --- a/source/blender/blenkernel/intern/vfont.c +++ b/source/blender/blenkernel/intern/vfont.c @@ -1143,8 +1143,7 @@ static bool vfont_to_curve(Object *ob, if (ef && ef->selboxes) { /* Set combined style flags for the selected string. Start with all styles then * remove one if ANY characters do not have it. Break out if we've removed them all. */ - ef->select_char_info_flag = CU_CHINFO_BOLD | CU_CHINFO_ITALIC | CU_CHINFO_UNDERLINE | - CU_CHINFO_SMALLCAPS; + ef->select_char_info_flag = CU_CHINFO_STYLE_ALL; for (int k = selstart; k <= selend && ef->select_char_info_flag; k++) { info = &custrinfo[k]; ef->select_char_info_flag &= info->flag; diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index 9eb26eb4c59..68ec2b7957a 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -768,7 +768,7 @@ static void volume_filepath_get(const Main *bmain, const Volume *volume, char r_ int path_frame, path_digits; if (volume->is_sequence && BLI_path_frame_get(r_filepath, &path_frame, &path_digits)) { char ext[32]; - BLI_path_frame_strip(r_filepath, ext); + BLI_path_frame_strip(r_filepath, ext, sizeof(ext)); BLI_path_frame(r_filepath, volume->runtime.frame, path_digits); BLI_path_extension_ensure(r_filepath, FILE_MAX, ext); } @@ -1523,17 +1523,10 @@ Volume *BKE_volume_new_for_eval(const Volume *volume_src) return volume_dst; } -Volume *BKE_volume_copy_for_eval(Volume *volume_src, bool reference) +Volume *BKE_volume_copy_for_eval(Volume *volume_src) { - int flags = LIB_ID_COPY_LOCALIZE; - - if (reference) { - flags |= LIB_ID_COPY_CD_REFERENCE; - } - - Volume *result = (Volume *)BKE_id_copy_ex(nullptr, &volume_src->id, nullptr, flags); - - return result; + return reinterpret_cast( + BKE_id_copy_ex(nullptr, &volume_src->id, nullptr, LIB_ID_COPY_LOCALIZE)); } #ifdef WITH_OPENVDB diff --git a/source/blender/blenkernel/intern/volume_to_mesh.cc b/source/blender/blenkernel/intern/volume_to_mesh.cc index f2a7d9472a9..1836ad843b8 100644 --- a/source/blender/blenkernel/intern/volume_to_mesh.cc +++ b/source/blender/blenkernel/intern/volume_to_mesh.cc @@ -165,7 +165,7 @@ Mesh *volume_to_mesh(const openvdb::GridBase &grid, const int tot_loops = 3 * mesh_data.tris.size() + 4 * mesh_data.quads.size(); const int tot_polys = mesh_data.tris.size() + mesh_data.quads.size(); - Mesh *mesh = BKE_mesh_new_nomain(mesh_data.verts.size(), 0, tot_loops, tot_polys); + Mesh *mesh = BKE_mesh_new_nomain(mesh_data.verts.size(), 0, tot_polys, tot_loops); fill_mesh_from_openvdb_data(mesh_data.verts, mesh_data.tris, diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index e0c4bda6747..a4f1eef647c 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -118,7 +118,7 @@ ENUM_OPERATORS(eFileAttributes, FILE_ATTR_HARDLINK); * \{ */ typedef enum FileExternalOperation { - FILE_EXTERNAL_OPERATION_OPEN = 0, + FILE_EXTERNAL_OPERATION_OPEN = 1, FILE_EXTERNAL_OPERATION_FOLDER_OPEN, /* Following are Windows-only: */ FILE_EXTERNAL_OPERATION_EDIT, diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 37458402bd2..4e3564eaa0a 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -60,6 +60,12 @@ void BLI_split_dir_part(const char *string, char *dir, size_t dirlen); * Copies the leaf filename part of string into `file`, max length `filelen`. */ void BLI_split_file_part(const char *string, char *file, size_t filelen); +/** + * Returns a pointer to the last extension (e.g. the position of the last period). + * Returns a pointer to the nil byte when no extension is found. + */ +const char *BLI_path_extension_or_end(const char *filepath) + ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL; /** * Returns a pointer to the last extension (e.g. the position of the last period). * Returns NULL if there is no extension. @@ -416,7 +422,7 @@ bool BLI_path_frame_get(const char *path, int *r_frame, int *r_digits_len) ATTR_ * So: `/some/path_123.jpeg` * Becomes: `/some/path_###` with `r_ext` set to `.jpeg`. */ -void BLI_path_frame_strip(char *path, char *r_ext) ATTR_NONNULL(); +void BLI_path_frame_strip(char *path, char *r_ext, size_t ext_maxlen) ATTR_NONNULL(); /** * Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range */ diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 70cb1c7083e..d6648e9011d 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -59,9 +59,9 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort int i; bool found_digit = false; const char *const lslash = BLI_path_slash_rfind(string); - const char *const extension = BLI_path_extension(lslash ? lslash : string); + const char *const extension = BLI_path_extension_or_end(lslash ? lslash : string); const uint lslash_len = lslash != NULL ? (int)(lslash - string) : 0; - const uint name_end = extension != NULL ? (int)((extension - string)) : strlen(string); + const uint name_end = (uint)(extension - string); for (i = name_end - 1; i >= (int)lslash_len; i--) { if (isdigit(string[i])) { @@ -587,17 +587,30 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char #ifdef DEBUG_STRSIZE memset(string, 0xff, sizeof(*string) * maxlen); #endif - const size_t string_len = strlen(string); const size_t suffix_len = strlen(suffix); const size_t sep_len = strlen(sep); - const char *const extension = BLI_path_extension(string); - const size_t string_end = extension != NULL ? (int)((extension - string)) : string_len; - char extension_copy[FILE_MAX]; + char *extension = (char *)BLI_path_extension_or_end(string); + const size_t extension_len = strlen(extension); + const size_t string_end = extension - string; + const size_t string_len = string_end + extension_len; if (string_len + sep_len + suffix_len >= maxlen) { return false; } - BLI_strncpy(extension_copy, string + string_end, sizeof(extension)); - BLI_sprintf(string + string_end, "%s%s%s", sep, suffix, extension_copy); + + if (extension_len) { + memmove(extension + (sep_len + suffix_len), extension, extension_len); + } + char *c = string + string_end; + if (sep_len) { + memcpy(c, sep, sep_len); + c += sep_len; + } + if (suffix_len) { + memcpy(c, suffix, suffix_len); + c += suffix_len; + } + c += extension_len; + *c = '\0'; return true; } @@ -750,9 +763,8 @@ bool BLI_path_frame_get(const char *path, int *r_frame, int *r_digits_len) *r_digits_len = 0; const char *file = BLI_path_basename(path); - const char *file_ext = BLI_path_extension(file); - const int file_len = strlen(file); - const char *c = file_ext ? file_ext : file + file_len; + const char *file_ext = BLI_path_extension_or_end(file); + const char *c = file_ext; /* Find start of number (if there is one). */ int digits_len = 0; @@ -771,7 +783,7 @@ bool BLI_path_frame_get(const char *path, int *r_frame, int *r_digits_len) return true; } -void BLI_path_frame_strip(char *path, char *r_ext) +void BLI_path_frame_strip(char *path, char *r_ext, const size_t ext_maxlen) { *r_ext = '\0'; if (*path == '\0') { @@ -779,10 +791,8 @@ void BLI_path_frame_strip(char *path, char *r_ext) } char *file = (char *)BLI_path_basename(path); - char *file_ext = (char *)BLI_path_extension(file); - const int file_len = strlen(file); - char *c = file_ext ? file_ext : file + file_len; - char *suffix = c; + char *file_ext = (char *)BLI_path_extension_or_end(file); + char *c = file_ext; /* Find start of number (if there is one). */ int digits_len = 0; @@ -791,10 +801,9 @@ void BLI_path_frame_strip(char *path, char *r_ext) } c++; - int suffix_length = file_len - (suffix - file); - memcpy(r_ext, suffix, suffix_length + 1); + BLI_strncpy(r_ext, file_ext, ext_maxlen); - /* replace the number with the suffix and terminate the string */ + /* Replace the number with the suffix and terminate the string. */ while (digits_len--) { *c++ = '#'; } @@ -1264,11 +1273,7 @@ bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) #ifdef DEBUG_STRSIZE memset(path, 0xff, sizeof(*path) * maxlen); #endif - char *path_ext = (char *)BLI_path_extension(path); - if (path_ext == NULL) { - path_ext = path + strlen(path); - } - + char *path_ext = (char *)BLI_path_extension_or_end(path); const size_t ext_len = strlen(ext); if ((path_ext - path) + ext_len >= maxlen) { return false; @@ -1293,9 +1298,10 @@ bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext) #ifdef DEBUG_STRSIZE memset(path, 0xff, sizeof(*path) * maxlen); #endif - /* First check the extension is already there. */ - char *path_ext = (char *)BLI_path_extension(path); - if (path_ext && STREQ(path_ext, ext)) { + /* First check the extension is already there. + * If `path_ext` is the end of the string this is simply checking if `ext` is also empty. */ + const char *path_ext = BLI_path_extension_or_end(path); + if (STREQ(path_ext, ext)) { return true; } @@ -1369,16 +1375,17 @@ void BLI_split_file_part(const char *string, char *file, const size_t filelen) BLI_split_dirfile(string, NULL, file, 0, filelen); } -const char *BLI_path_extension(const char *filepath) +const char *BLI_path_extension_or_end(const char *filepath) { /* NOTE(@ideasman42): Skip the extension when there are no preceding non-extension characters in * the file name. This ignores extensions at the beginning of a string or directly after a slash. - * Only using trailing extension characters has the advantage that stripping the extenion + * Only using trailing extension characters has the advantage that stripping the extension * never leads to a blank string (which can't be used as a file path). * Matches Python's `os.path.splitext`. */ const char *ext = NULL; bool has_non_ext = false; - for (const char *c = filepath; *c; c++) { + const char *c = filepath; + for (; *c; c++) { switch (*c) { case '.': { if (has_non_ext) { @@ -1398,7 +1405,17 @@ const char *BLI_path_extension(const char *filepath) } } } - return ext; + if (ext) { + return ext; + } + BLI_assert(*c == '\0'); + return c; +} + +const char *BLI_path_extension(const char *filepath) +{ + const char *ext = BLI_path_extension_or_end(filepath); + return *ext ? ext : NULL; } size_t BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file) diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc index db032ef0be7..85907889616 100644 --- a/source/blender/blenlib/tests/BLI_path_util_test.cc +++ b/source/blender/blenlib/tests/BLI_path_util_test.cc @@ -42,7 +42,7 @@ static char *str_replace_char_strdup(const char *str, char src, char dst) /** \name Tests for: #BLI_path_normalize * \{ */ -#define NORMALIZE_WITH_BASEDIR(input, input_base, output) \ +#define NORMALIZE_WITH_BASEDIR(input, input_base, output_expect) \ { \ char path[FILE_MAX] = input; \ const char *input_base_test = input_base; \ @@ -57,11 +57,11 @@ static char *str_replace_char_strdup(const char *str, char src, char dst) free((void *)input_base_test); \ } \ } \ - EXPECT_STREQ(output, path); \ + EXPECT_STREQ(path, output_expect); \ } \ ((void)0) -#define NORMALIZE(input, output) NORMALIZE_WITH_BASEDIR(input, nullptr, output) +#define NORMALIZE(input, output_expect) NORMALIZE_WITH_BASEDIR(input, nullptr, output_expect) /* #BLI_path_normalize: "/./" -> "/" */ TEST(path_util, Clean_Dot) @@ -102,7 +102,7 @@ TEST(path_util, Clean_Parent) /** \name Tests for: #BLI_path_parent_dir * \{ */ -#define PARENT_DIR(input, output) \ +#define PARENT_DIR(input, output_expect) \ { \ char path[FILE_MAX] = input; \ if (SEP == '\\') { \ @@ -112,7 +112,7 @@ TEST(path_util, Clean_Parent) if (SEP == '\\') { \ BLI_str_replace_char(path, '\\', '/'); \ } \ - EXPECT_STREQ(output, path); \ + EXPECT_STREQ(path, output_expect); \ } \ ((void)0) @@ -177,7 +177,7 @@ TEST(path_util, ParentDir_Complex) } \ else { \ EXPECT_TRUE(ret); \ - EXPECT_EQ(strlen(expect), len_output); \ + EXPECT_EQ(len_output, strlen(expect)); \ path[index_output + len_output] = '\0'; \ EXPECT_STREQ(&path[index_output], expect); \ } \ @@ -515,42 +515,42 @@ TEST(path_util, Frame) char path[FILE_MAX] = ""; ret = BLI_path_frame(path, 123, 1); EXPECT_TRUE(ret); - EXPECT_STREQ("123", path); + EXPECT_STREQ(path, "123"); } { char path[FILE_MAX] = ""; ret = BLI_path_frame(path, 123, 12); EXPECT_TRUE(ret); - EXPECT_STREQ("000000000123", path); + EXPECT_STREQ(path, "000000000123"); } { char path[FILE_MAX] = "test_"; ret = BLI_path_frame(path, 123, 1); EXPECT_TRUE(ret); - EXPECT_STREQ("test_123", path); + EXPECT_STREQ(path, "test_123"); } { char path[FILE_MAX] = "test_"; ret = BLI_path_frame(path, 1, 12); EXPECT_TRUE(ret); - EXPECT_STREQ("test_000000000001", path); + EXPECT_STREQ(path, "test_000000000001"); } { char path[FILE_MAX] = "test_############"; ret = BLI_path_frame(path, 1, 0); EXPECT_TRUE(ret); - EXPECT_STREQ("test_000000000001", path); + EXPECT_STREQ(path, "test_000000000001"); } { char path[FILE_MAX] = "test_#_#_middle"; ret = BLI_path_frame(path, 123, 0); EXPECT_TRUE(ret); - EXPECT_STREQ("test_#_123_middle", path); + EXPECT_STREQ(path, "test_#_123_middle"); } /* intentionally fail */ @@ -558,14 +558,14 @@ TEST(path_util, Frame) char path[FILE_MAX] = ""; ret = BLI_path_frame(path, 123, 0); EXPECT_FALSE(ret); - EXPECT_STREQ("", path); + EXPECT_STREQ(path, ""); } { char path[FILE_MAX] = "test_middle"; ret = BLI_path_frame(path, 123, 0); EXPECT_FALSE(ret); - EXPECT_STREQ("test_middle", path); + EXPECT_STREQ(path, "test_middle"); } /* negative frame numbers */ @@ -573,13 +573,13 @@ TEST(path_util, Frame) char path[FILE_MAX] = "test_####"; ret = BLI_path_frame(path, -1, 4); EXPECT_TRUE(ret); - EXPECT_STREQ("test_-0001", path); + EXPECT_STREQ(path, "test_-0001"); } { char path[FILE_MAX] = "test_####"; ret = BLI_path_frame(path, -100, 4); EXPECT_TRUE(ret); - EXPECT_STREQ("test_-0100", path); + EXPECT_STREQ(path, "test_-0100"); } } @@ -595,52 +595,52 @@ TEST(path_util, SplitDirfile) const char *path = ""; char dir[FILE_MAX], file[FILE_MAX]; BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - EXPECT_STREQ("", dir); - EXPECT_STREQ("", file); + EXPECT_STREQ(dir, ""); + EXPECT_STREQ(file, ""); } { const char *path = "/"; char dir[FILE_MAX], file[FILE_MAX]; BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - EXPECT_STREQ("/", dir); - EXPECT_STREQ("", file); + EXPECT_STREQ(dir, "/"); + EXPECT_STREQ(file, ""); } { const char *path = "fileonly"; char dir[FILE_MAX], file[FILE_MAX]; BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - EXPECT_STREQ("", dir); - EXPECT_STREQ("fileonly", file); + EXPECT_STREQ(dir, ""); + EXPECT_STREQ(file, "fileonly"); } { const char *path = "dironly/"; char dir[FILE_MAX], file[FILE_MAX]; BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - EXPECT_STREQ("dironly/", dir); - EXPECT_STREQ("", file); + EXPECT_STREQ(dir, "dironly/"); + EXPECT_STREQ(file, ""); } { const char *path = "/a/b"; char dir[FILE_MAX], file[FILE_MAX]; BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - EXPECT_STREQ("/a/", dir); - EXPECT_STREQ("b", file); + EXPECT_STREQ(dir, "/a/"); + EXPECT_STREQ(file, "b"); } { const char *path = "/dirtoobig/filetoobig"; char dir[5], file[5]; BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - EXPECT_STREQ("/dir", dir); - EXPECT_STREQ("file", file); + EXPECT_STREQ(dir, "/dir"); + EXPECT_STREQ(file, "file"); BLI_split_dirfile(path, dir, file, 1, 1); - EXPECT_STREQ("", dir); - EXPECT_STREQ("", file); + EXPECT_STREQ(dir, ""); + EXPECT_STREQ(file, ""); } } @@ -655,13 +655,13 @@ TEST(path_util, SplitDirfile) char path[FILE_MAX]; \ char ext[FILE_MAX]; \ BLI_strncpy(path, (input_path), FILE_MAX); \ - BLI_path_frame_strip(path, ext); \ + BLI_path_frame_strip(path, ext, sizeof(ext)); \ EXPECT_STREQ(path, expect_path); \ EXPECT_STREQ(ext, expect_ext); \ } \ ((void)0) -TEST(path_util, PathFrameStrip) +TEST(path_util, FrameStrip) { PATH_FRAME_STRIP("", "", ""); PATH_FRAME_STRIP("nonum.abc", "nonum", ".abc"); @@ -678,29 +678,29 @@ TEST(path_util, PathFrameStrip) /** \name Tests for: #BLI_path_extension * \{ */ -TEST(path_util, PathExtension) +TEST(path_util, Extension) { - EXPECT_EQ(nullptr, BLI_path_extension("some.def/file")); - EXPECT_EQ(nullptr, BLI_path_extension("Text")); - EXPECT_EQ(nullptr, BLI_path_extension("Text…001")); - EXPECT_EQ(nullptr, BLI_path_extension(".hidden")); - EXPECT_EQ(nullptr, BLI_path_extension(".hidden/")); - EXPECT_EQ(nullptr, BLI_path_extension("/.hidden")); - EXPECT_EQ(nullptr, BLI_path_extension("dir/.hidden")); - EXPECT_EQ(nullptr, BLI_path_extension("/dir/.hidden")); + EXPECT_EQ(BLI_path_extension("some.def/file"), nullptr); + EXPECT_EQ(BLI_path_extension("Text"), nullptr); + EXPECT_EQ(BLI_path_extension("Text…001"), nullptr); + EXPECT_EQ(BLI_path_extension(".hidden"), nullptr); + EXPECT_EQ(BLI_path_extension(".hidden/"), nullptr); + EXPECT_EQ(BLI_path_extension("/.hidden"), nullptr); + EXPECT_EQ(BLI_path_extension("dir/.hidden"), nullptr); + EXPECT_EQ(BLI_path_extension("/dir/.hidden"), nullptr); - EXPECT_EQ(nullptr, BLI_path_extension(".")); - EXPECT_EQ(nullptr, BLI_path_extension("..")); - EXPECT_EQ(nullptr, BLI_path_extension("...")); - EXPECT_STREQ(".", BLI_path_extension("...a.")); - EXPECT_STREQ(".", BLI_path_extension("...a..")); - EXPECT_EQ(nullptr, BLI_path_extension("...a../")); + EXPECT_EQ(BLI_path_extension("."), nullptr); + EXPECT_EQ(BLI_path_extension(".."), nullptr); + EXPECT_EQ(BLI_path_extension("..."), nullptr); + EXPECT_STREQ(BLI_path_extension("...a."), "."); + EXPECT_STREQ(BLI_path_extension("...a.."), "."); + EXPECT_EQ(BLI_path_extension("...a../"), nullptr); - EXPECT_STREQ(".", BLI_path_extension("some/file.")); - EXPECT_STREQ(".gz", BLI_path_extension("some/file.tar.gz")); - EXPECT_STREQ(".abc", BLI_path_extension("some.def/file.abc")); - EXPECT_STREQ(".abc", BLI_path_extension("C:\\some.def\\file.abc")); - EXPECT_STREQ(".001", BLI_path_extension("Text.001")); + EXPECT_STREQ(BLI_path_extension("some/file."), "."); + EXPECT_STREQ(BLI_path_extension("some/file.tar.gz"), ".gz"); + EXPECT_STREQ(BLI_path_extension("some.def/file.abc"), ".abc"); + EXPECT_STREQ(BLI_path_extension("C:\\some.def\\file.abc"), ".abc"); + EXPECT_STREQ(BLI_path_extension("Text.001"), ".001"); } /** \} */ @@ -721,7 +721,7 @@ TEST(path_util, PathExtension) } \ ((void)0) -TEST(path_util, PathExtensionCheck) +TEST(path_util, ExtensionCheck) { PATH_EXTENSION_CHECK("a/b/c.exe", ".exe", ".exe"); PATH_EXTENSION_CHECK("correct/path/to/file.h", ".h", ".h"); @@ -752,26 +752,31 @@ TEST(path_util, PathExtensionCheck) /** \name Tests for: #BLI_path_extension_replace * \{ */ -#define PATH_EXTENSION_REPLACE(input_path, input_ext, expect_result, expect_path) \ +#define PATH_EXTENSION_REPLACE_WITH_MAXLEN( \ + input_path, input_ext, expect_result, expect_path, maxlen) \ { \ + BLI_assert(maxlen <= FILE_MAX); \ char path[FILE_MAX]; \ - BLI_strncpy(path, input_path, FILE_MAX); \ - const bool ret = BLI_path_extension_replace(path, sizeof(path), input_ext); \ + BLI_strncpy(path, input_path, sizeof(path)); \ + const bool ret = BLI_path_extension_replace(path, maxlen, input_ext); \ if (expect_result) { \ EXPECT_TRUE(ret); \ } \ else { \ EXPECT_FALSE(ret); \ } \ - EXPECT_STREQ(expect_path, path); \ + EXPECT_STREQ(path, expect_path); \ } \ ((void)0) -TEST(path_util, PathExtensionReplace) +#define PATH_EXTENSION_REPLACE(input_path, input_ext, expect_result, expect_path) \ + PATH_EXTENSION_REPLACE_WITH_MAXLEN(input_path, input_ext, expect_result, expect_path, FILE_MAX) + +TEST(path_util, ExtensionReplace) { PATH_EXTENSION_REPLACE("test", ".txt", true, "test.txt"); PATH_EXTENSION_REPLACE("test.", ".txt", true, "test.txt"); - /* Unlike #BLI_path_extension_ensure, exceeds '.' are not stripped. */ + /* Unlike #BLI_path_extension_ensure, excess '.' are not stripped. */ PATH_EXTENSION_REPLACE("test..", ".txt", true, "test..txt"); PATH_EXTENSION_REPLACE("test.txt", ".txt", true, "test.txt"); @@ -780,15 +785,37 @@ TEST(path_util, PathExtensionReplace) PATH_EXTENSION_REPLACE("test", "_txt", true, "test_txt"); PATH_EXTENSION_REPLACE("test.ext", "_txt", true, "test_txt"); + PATH_EXTENSION_REPLACE("test", "", true, "test"); + + /* Same as #BLI_path_extension_strip. */ + PATH_EXTENSION_REPLACE("test.txt", "", true, "test"); + + /* Empty strings. */ PATH_EXTENSION_REPLACE("test", "", true, "test"); PATH_EXTENSION_REPLACE("", "_txt", true, "_txt"); + PATH_EXTENSION_REPLACE("", "", true, ""); /* Ensure leading '.' isn't treated as an extension. */ PATH_EXTENSION_REPLACE(".hidden", ".hidden", true, ".hidden.hidden"); PATH_EXTENSION_REPLACE("..hidden", ".hidden", true, "..hidden.hidden"); PATH_EXTENSION_REPLACE("._.hidden", ".hidden", true, "._.hidden"); } + +TEST(path_util, ExtensionReplace_Overflow) +{ + /* Small values. */ + PATH_EXTENSION_REPLACE_WITH_MAXLEN("test", ".txt", false, "test", 0); + PATH_EXTENSION_REPLACE_WITH_MAXLEN("test", ".txt", false, "test", 1); + /* One under fails, and exactly enough space succeeds. */ + PATH_EXTENSION_REPLACE_WITH_MAXLEN("test", ".txt", false, "test", 8); + PATH_EXTENSION_REPLACE_WITH_MAXLEN("test", ".txt", true, "test.txt", 9); + + PATH_EXTENSION_REPLACE_WITH_MAXLEN("test.xx", ".txt", false, "test.xx", 8); + PATH_EXTENSION_REPLACE_WITH_MAXLEN("test.xx", ".txt", true, "test.txt", 9); +} + #undef PATH_EXTENSION_REPLACE +#undef PATH_EXTENSION_REPLACE_WITH_MAXLEN /** \} */ @@ -796,22 +823,27 @@ TEST(path_util, PathExtensionReplace) /** \name Tests for: #BLI_path_extension_ensure * \{ */ -#define PATH_EXTENSION_ENSURE(input_path, input_ext, expect_result, expect_path) \ +#define PATH_EXTENSION_ENSURE_WITH_MAXLEN( \ + input_path, input_ext, expect_result, expect_path, maxlen) \ { \ + BLI_assert(maxlen <= FILE_MAX); \ char path[FILE_MAX]; \ - BLI_strncpy(path, input_path, FILE_MAX); \ - const bool ret = BLI_path_extension_ensure(path, sizeof(path), input_ext); \ + BLI_strncpy(path, input_path, sizeof(path)); \ + const bool ret = BLI_path_extension_ensure(path, maxlen, input_ext); \ if (expect_result) { \ EXPECT_TRUE(ret); \ } \ else { \ EXPECT_FALSE(ret); \ } \ - EXPECT_STREQ(expect_path, path); \ + EXPECT_STREQ(path, expect_path); \ } \ ((void)0) -TEST(path_util, PathExtensionEnsure) +#define PATH_EXTENSION_ENSURE(input_path, input_ext, expect_result, expect_path) \ + PATH_EXTENSION_ENSURE_WITH_MAXLEN(input_path, input_ext, expect_result, expect_path, FILE_MAX) + +TEST(path_util, ExtensionEnsure) { PATH_EXTENSION_ENSURE("test", ".txt", true, "test.txt"); PATH_EXTENSION_ENSURE("test.", ".txt", true, "test.txt"); @@ -823,15 +855,32 @@ TEST(path_util, PathExtensionEnsure) PATH_EXTENSION_ENSURE("test", "_txt", true, "test_txt"); PATH_EXTENSION_ENSURE("test.ext", "_txt", true, "test.ext_txt"); + /* An empty string does nothing (unlike replace which strips). */ + PATH_EXTENSION_ENSURE("test.txt", "", true, "test.txt"); + + /* Empty strings. */ PATH_EXTENSION_ENSURE("test", "", true, "test"); PATH_EXTENSION_ENSURE("", "_txt", true, "_txt"); + PATH_EXTENSION_ENSURE("", "", true, ""); /* Ensure leading '.' isn't treated as an extension. */ PATH_EXTENSION_ENSURE(".hidden", ".hidden", true, ".hidden.hidden"); PATH_EXTENSION_ENSURE("..hidden", ".hidden", true, "..hidden.hidden"); PATH_EXTENSION_ENSURE("._.hidden", ".hidden", true, "._.hidden"); } + +TEST(path_util, ExtensionEnsure_Overflow) +{ + /* Small values. */ + PATH_EXTENSION_ENSURE_WITH_MAXLEN("test", ".txt", false, "test", 0); + PATH_EXTENSION_ENSURE_WITH_MAXLEN("test", ".txt", false, "test", 1); + /* One under fails, and exactly enough space succeeds. */ + PATH_EXTENSION_ENSURE_WITH_MAXLEN("test", ".txt", false, "test", 8); + PATH_EXTENSION_ENSURE_WITH_MAXLEN("test", ".txt", true, "test.txt", 9); +} + #undef PATH_EXTENSION_ENSURE +#undef PATH_EXTENSION_ENSURE_WITH_MAXLEN /** \} */ @@ -851,7 +900,7 @@ TEST(path_util, PathExtensionEnsure) } \ ((void)0) -TEST(path_util, PathFrameCheckChars) +TEST(path_util, FrameCheckChars) { PATH_FRAME_CHECK_CHARS("a#", true); PATH_FRAME_CHECK_CHARS("aaaaa#", true); @@ -892,7 +941,7 @@ TEST(path_util, PathFrameCheckChars) } \ ((void)0) -TEST(path_util, PathFrameRange) +TEST(path_util, FrameRange) { int dummy = -1; PATH_FRAME_RANGE("#", 1, 2, dummy, "1-2"); @@ -930,7 +979,7 @@ TEST(path_util, PathFrameRange) } \ ((void)0) -TEST(path_util, PathFrameGet) +TEST(path_util, FrameGet) { PATH_FRAME_GET("001.avi", 1, 3, true); PATH_FRAME_GET("0000299.ext", 299, 7, true); @@ -954,14 +1003,14 @@ TEST(path_util, PathFrameGet) char tail[FILE_MAX]; \ ushort numdigits = 0; \ const int result = BLI_path_sequence_decode(path, head, tail, &numdigits); \ - EXPECT_EQ(expect_result, result); \ - EXPECT_STREQ(expect_head, head); \ - EXPECT_STREQ(expect_tail, tail); \ - EXPECT_EQ(expect_numdigits, numdigits); \ + EXPECT_EQ(result, expect_result); \ + EXPECT_STREQ(head, expect_head); \ + EXPECT_STREQ(tail, expect_tail); \ + EXPECT_EQ(numdigits, expect_numdigits); \ } \ (void)0; -TEST(path_util, PathSequenceDecode) +TEST(path_util, SequenceDecode) { /* Basic use. */ PATH_SEQ_DECODE("file_123.txt", 123, "file_", ".txt", 3); @@ -987,12 +1036,12 @@ TEST(path_util, PathSequenceDecode) { \ char path[FILE_MAX] = path_literal; \ const bool result = BLI_path_suffix(path, path_literal_max, suffix, sep); \ - EXPECT_EQ(expect_result, result); \ - EXPECT_STREQ(expect_path, path); \ + EXPECT_EQ(result, expect_result); \ + EXPECT_STREQ(path, expect_path); \ } \ (void)0; -TEST(path_util, PathSuffix) +TEST(path_util, Suffix) { /* Extension. */ PATH_SUFFIX("file.txt", FILE_MAX, "_", "123", true, "file_123.txt"); @@ -1010,6 +1059,11 @@ TEST(path_util, PathSuffix) PATH_SUFFIX("", FILE_MAX, "_", "123", true, "_123"); /* Empty input/output. */ PATH_SUFFIX("", FILE_MAX, "", "", true, ""); + + /* Long suffix. */ + PATH_SUFFIX("file.txt", FILE_MAX, "_", "1234567890", true, "file_1234567890.txt"); + /* Long extension. */ + PATH_SUFFIX("file.txt1234567890", FILE_MAX, "_", "123", true, "file_123.txt1234567890"); } #undef PATH_SUFFIX @@ -1020,7 +1074,7 @@ TEST(path_util, PathSuffix) /** \name Tests for: #BLI_path_rel * \{ */ -#define PATH_REL(abs_path, ref_path, rel_path) \ +#define PATH_REL(abs_path, ref_path, rel_path_expect) \ { \ char path[FILE_MAX]; \ const char *ref_path_test = ref_path; \ @@ -1034,7 +1088,7 @@ TEST(path_util, PathSuffix) BLI_str_replace_char(path, '\\', '/'); \ free((void *)ref_path_test); \ } \ - EXPECT_STREQ(rel_path, path); \ + EXPECT_STREQ(path, rel_path_expect); \ } \ void(0) @@ -1044,17 +1098,17 @@ TEST(path_util, PathSuffix) # define ABS_PREFIX "" #endif -TEST(path_util, PathRelPath_Simple) +TEST(path_util, RelPath_Simple) { PATH_REL(ABS_PREFIX "/foo/bar/blender.blend", ABS_PREFIX "/foo/bar/", "//blender.blend"); } -TEST(path_util, PathRelPath_SimpleSubdir) +TEST(path_util, RelPath_SimpleSubdir) { PATH_REL(ABS_PREFIX "/foo/bar/blender.blend", ABS_PREFIX "/foo/bar", "//bar/blender.blend"); } -TEST(path_util, PathRelPath_BufferOverflowRoot) +TEST(path_util, RelPath_BufferOverflowRoot) { char abs_path_in[FILE_MAX]; const char *abs_prefix = ABS_PREFIX "/"; @@ -1070,7 +1124,7 @@ TEST(path_util, PathRelPath_BufferOverflowRoot) PATH_REL(abs_path_in, abs_prefix, abs_path_out); } -TEST(path_util, PathRelPath_BufferOverflowSubdir) +TEST(path_util, RelPath_BufferOverflowSubdir) { char abs_path_in[FILE_MAX]; const char *ref_path_in = ABS_PREFIX "/foo/bar/"; @@ -1096,7 +1150,7 @@ TEST(path_util, PathRelPath_BufferOverflowSubdir) /** \name Tests for: #BLI_path_contains * \{ */ -TEST(path_util, PathContains) +TEST(path_util, Contains) { EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path")) << "A path contains itself"; EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path/inside")) @@ -1119,7 +1173,7 @@ TEST(path_util, PathContains) } #ifdef WIN32 -TEST(path_util, PathContains_Windows_case_insensitive) +TEST(path_util, Contains_Windows_case_insensitive) { EXPECT_TRUE(BLI_path_contains("C:\\some\\path", "c:\\SOME\\path\\inside")) << "On Windows path comparison should ignore case"; diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index 9429c21b56e..f2667f66c09 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -4305,6 +4305,9 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain) ARRAY_SIZE(tool_replace_table)); } } + + /* Rename Grease Pencil weight draw brush. */ + do_versions_rename_id(bmain, ID_BR, "Draw Weight", "Weight Draw"); } /** diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt index df9440ef414..ab584423dd1 100644 --- a/source/blender/compositor/realtime_compositor/CMakeLists.txt +++ b/source/blender/compositor/realtime_compositor/CMakeLists.txt @@ -118,6 +118,7 @@ set(GLSL_SRC shaders/compositor_glare_simple_star_vertical_pass.glsl shaders/compositor_glare_streaks_accumulate.glsl shaders/compositor_glare_streaks_filter.glsl + shaders/compositor_id_mask.glsl shaders/compositor_image_crop.glsl shaders/compositor_map_uv.glsl shaders/compositor_morphological_distance.glsl @@ -215,6 +216,7 @@ set(SRC_SHADER_CREATE_INFOS shaders/infos/compositor_filter_info.hh shaders/infos/compositor_flip_info.hh shaders/infos/compositor_glare_info.hh + shaders/infos/compositor_id_mask_info.hh shaders/infos/compositor_image_crop_info.hh shaders/infos/compositor_map_uv_info.hh shaders/infos/compositor_morphological_distance_feather_info.hh diff --git a/source/blender/compositor/realtime_compositor/intern/shader_node.cc b/source/blender/compositor/realtime_compositor/intern/shader_node.cc index 4ac83c010b2..e3c0b032dd7 100644 --- a/source/blender/compositor/realtime_compositor/intern/shader_node.cc +++ b/source/blender/compositor/realtime_compositor/intern/shader_node.cc @@ -98,6 +98,7 @@ static void gpu_stack_vector_from_socket(GPUNodeStack &stack, const bNodeSocket return; default: BLI_assert_unreachable(); + return; } } case SOCK_VECTOR: { @@ -115,6 +116,7 @@ static void gpu_stack_vector_from_socket(GPUNodeStack &stack, const bNodeSocket return; default: BLI_assert_unreachable(); + return; } } case SOCK_RGBA: { @@ -131,6 +133,7 @@ static void gpu_stack_vector_from_socket(GPUNodeStack &stack, const bNodeSocket return; default: BLI_assert_unreachable(); + return; } } default: diff --git a/source/blender/compositor/realtime_compositor/shaders/compositor_id_mask.glsl b/source/blender/compositor/realtime_compositor/shaders/compositor_id_mask.glsl new file mode 100644 index 00000000000..d7411586b5e --- /dev/null +++ b/source/blender/compositor/realtime_compositor/shaders/compositor_id_mask.glsl @@ -0,0 +1,11 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + float input_mask_value = texture_load(input_mask_tx, texel).x; + float mask = int(round(input_mask_value)) == index ? 1.0 : 0.0; + + imageStore(output_mask_img, texel, vec4(mask)); +} diff --git a/source/blender/compositor/realtime_compositor/shaders/infos/compositor_id_mask_info.hh b/source/blender/compositor/realtime_compositor/shaders/infos/compositor_id_mask_info.hh new file mode 100644 index 00000000000..ce4fb8f6325 --- /dev/null +++ b/source/blender/compositor/realtime_compositor/shaders/infos/compositor_id_mask_info.hh @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_id_mask) + .local_group_size(16, 16) + .push_constant(Type::INT, "index") + .sampler(0, ImageType::FLOAT_2D, "input_mask_tx") + .image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_mask_img") + .compute_source("compositor_id_mask.glsl") + .do_static_compilation(true); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_key.cc b/source/blender/depsgraph/intern/builder/deg_builder_key.cc index b3ba0449e76..62e89878abd 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_key.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_key.cc @@ -84,6 +84,19 @@ RNAPathKey::RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop, RNAPoin { } +RNAPathKey::RNAPathKey(const PointerRNA &target_prop, + const char *rna_path_from_target_prop, + const RNAPointerSource source) + : id(target_prop.owner_id), source(source) +{ + /* Try to resolve path. */ + int index; + if (!RNA_path_resolve_full(&target_prop, rna_path_from_target_prop, &ptr, &prop, &index)) { + ptr = PointerRNA_NULL; + prop = nullptr; + } +} + string RNAPathKey::identifier() const { const char *id_name = (id) ? id->name : ""; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_key.h b/source/blender/depsgraph/intern/builder/deg_builder_key.h index 0335e80951d..6a26a75308e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_key.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_key.h @@ -188,6 +188,9 @@ struct PersistentOperationKey : public OperationKey { struct RNAPathKey { RNAPathKey(ID *id, const char *path, RNAPointerSource source); + RNAPathKey(const PointerRNA &target_prop, + const char *rna_path_from_target_prop, + RNAPointerSource source); RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop, RNAPointerSource source); string identifier() const; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 1072509bbf7..8c7831d7e93 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1807,7 +1807,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) add_relation(target_key, driver_key, "Target -> Driver"); } else if (dtar->rna_path != nullptr && dtar->rna_path[0] != '\0') { - RNAPathKey variable_exit_key(target_id, dtar->rna_path, RNAPointerSource::EXIT); + RNAPathKey variable_exit_key(target_prop, dtar->rna_path, RNAPointerSource::EXIT); if (RNA_pointer_is_null(&variable_exit_key.ptr)) { continue; } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl index 1da741d7609..957c9b01a2a 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl @@ -590,7 +590,7 @@ void dof_gather_accumulator(sampler2D color_tx, * The full pixel neighborhood is gathered. * \{ */ -void dof_slight_focus_gather(sampler2D depth_tx, +void dof_slight_focus_gather(depth2D depth_tx, sampler2D color_tx, sampler2D bkh_lut_tx, /* Renamed because of ugly macro job. */ float radius, diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_update_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_update_comp.glsl index 479a6b590b0..cea25ef7ce0 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_update_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_update_comp.glsl @@ -62,7 +62,7 @@ void main() int mask_shift = 1; #define downsample_level(out_mip__, lod_) \ - active_thread = all(lessThan(local_px, gl_WorkGroupSize.xy >> uint(mask_shift))); \ + active_thread = all(lessThan(uvec2(local_px), gl_WorkGroupSize.xy >> uint(mask_shift))); \ barrier(); /* Wait for previous writes to finish. */ \ if (active_thread) { \ max_depth = max_v4(load_local_depths(local_px)); \ @@ -89,12 +89,12 @@ void main() } finished_tile_counter = 0u; - ivec2 iter = divide_ceil(imageSize(out_mip_5), ivec2(gl_WorkGroupSize * 2u)); + ivec2 iter = divide_ceil(imageSize(out_mip_5), ivec2(gl_WorkGroupSize.xy * 2u)); ivec2 image_border = imageSize(out_mip_5) - 1; for (int y = 0; y < iter.y; y++) { for (int x = 0; x < iter.x; x++) { /* Load result of the other work groups. */ - kernel_origin = ivec2(gl_WorkGroupSize) * ivec2(x, y); + kernel_origin = ivec2(gl_WorkGroupSize.xy) * ivec2(x, y); src_px = ivec2(kernel_origin + local_px) * 2; vec4 samp; samp.x = imageLoad(out_mip_5, min(src_px + ivec2(0, 1), image_border)).x; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_tile_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_tile_comp.glsl index 37705e22b22..1f012a44acf 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_tile_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_tile_comp.glsl @@ -168,13 +168,15 @@ void main() } /* Fallthrough to the hemispheric case. */ case LIGHT_RECT: - case LIGHT_ELLIPSE: + case LIGHT_ELLIPSE: { vec3 v000 = vP - v_right * radius - v_up * radius; vec3 v100 = v000 + v_right * (radius * 2.0); vec3 v010 = v000 + v_up * (radius * 2.0); vec3 v001 = v000 - v_back * radius; Box bbox = shape_box(v000, v100, v010, v001); intersect_tile = intersect_tile && intersect(tile, bbox); + break; + } default: break; } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl index 07139ea6a09..e365da53d2b 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl @@ -74,8 +74,10 @@ void main() vec4 max_motion = imageLoad(in_tiles_img, src_tile); - MotionPayload payload_prv = motion_blur_tile_indirection_pack_payload(max_motion.xy, src_tile); - MotionPayload payload_nxt = motion_blur_tile_indirection_pack_payload(max_motion.zw, src_tile); + MotionPayload payload_prv = motion_blur_tile_indirection_pack_payload(max_motion.xy, + uvec2(src_tile)); + MotionPayload payload_nxt = motion_blur_tile_indirection_pack_payload(max_motion.zw, + uvec2(src_tile)); if (true) { /* Rectangular area (in tiles) where the motion vector spreads. */ MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.xy); @@ -85,17 +87,20 @@ void main() for (int y = 0; y < motion_rect.extent.y; y++) { ivec2 tile = motion_rect.bottom_left + ivec2(x, y); if (is_inside_motion_line(tile, motion_line)) { - motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_PREV, tile, payload_prv); + motion_blur_tile_indirection_store( + tile_indirection_buf, MOTION_PREV, uvec2(tile), payload_prv); /* FIXME: This is a bit weird, but for some reason, we need the store the same vector in * the motion next so that weighting in gather pass is better. */ - motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_NEXT, tile, payload_nxt); + motion_blur_tile_indirection_store( + tile_indirection_buf, MOTION_NEXT, uvec2(tile), payload_nxt); } } } } if (true) { - MotionPayload payload = motion_blur_tile_indirection_pack_payload(max_motion.zw, src_tile); + MotionPayload payload = motion_blur_tile_indirection_pack_payload(max_motion.zw, + uvec2(src_tile)); /* Rectangular area (in tiles) where the motion vector spreads. */ MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.zw); MotionLine motion_line = compute_motion_line(src_tile, max_motion.zw); @@ -104,10 +109,12 @@ void main() for (int y = 0; y < motion_rect.extent.y; y++) { ivec2 tile = motion_rect.bottom_left + ivec2(x, y); if (is_inside_motion_line(tile, motion_line)) { - motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_NEXT, tile, payload_nxt); + motion_blur_tile_indirection_store( + tile_indirection_buf, MOTION_NEXT, uvec2(tile), payload_nxt); /* FIXME: This is a bit weird, but for some reason, we need the store the same vector in * the motion next so that weighting in gather pass is better. */ - motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_PREV, tile, payload_prv); + motion_blur_tile_indirection_store( + tile_indirection_buf, MOTION_PREV, uvec2(tile), payload_prv); } } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl index 5249e6637b6..1408f28e585 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl @@ -178,10 +178,10 @@ void main() vec4 max_motion; /* Load dilation result from the indirection table. */ ivec2 tile_prev; - motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_PREV, tile, tile_prev); + motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_PREV, uvec2(tile), tile_prev); max_motion.xy = imageLoad(in_tiles_img, tile_prev).xy; ivec2 tile_next; - motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_NEXT, tile, tile_next); + motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_NEXT, uvec2(tile), tile_next); max_motion.zw = imageLoad(in_tiles_img, tile_next).zw; Accumulator accum; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl index db38baab6a4..6d802a6d79a 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl @@ -242,13 +242,13 @@ void output_aov(vec4 color, float value, uint hash) #if defined(MAT_AOV_SUPPORT) && defined(GPU_FRAGMENT_SHADER) for (int i = 0; i < AOV_MAX && i < aov_buf.color_len; i++) { if (aov_buf.hash_color[i] == hash) { - imageStore(aov_color_img, ivec3(gl_FragCoord.xy, i), color); + imageStore(aov_color_img, ivec3(ivec2(gl_FragCoord.xy), i), color); return; } } for (int i = 0; i < AOV_MAX && i < aov_buf.value_len; i++) { if (aov_buf.hash_value[i] == hash) { - imageStore(aov_value_img, ivec3(gl_FragCoord.xy, i), vec4(value)); + imageStore(aov_value_img, ivec3(ivec2(gl_FragCoord.xy), i), vec4(value)); return; } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_update_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_update_comp.glsl index 475d456db7a..9f9a4c88f9c 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_update_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_update_comp.glsl @@ -65,7 +65,7 @@ void main() } AABB aabb_tag; - AABB aabb_map = AABB(vec3(-0.99999), vec3(0.99999)); + AABB aabb_map = shape_aabb(vec3(-0.99999), vec3(0.99999)); /* Directionnal winmat have no correct near/far in the Z dimension at this point. * Do not clip in this dimension. */ @@ -87,7 +87,7 @@ void main() for (int y = box_min.y; y <= box_max.y; y++) { for (int x = box_min.x; x <= box_max.x; x++) { int tile_index = shadow_tile_offset(ivec2(x, y), tilemap.tiles_index, lod); - atomicOr(tiles_buf[tile_index], SHADOW_DO_UPDATE); + atomicOr(tiles_buf[tile_index], uint(SHADOW_DO_UPDATE)); } } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl index bb18f56ec74..172fe9488f4 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl @@ -21,7 +21,7 @@ void shadow_tag_usage_tile(LightData light, ivec2 tile_co, int lod, int tilemap_ tile_co >>= lod; int tile_index = shadow_tile_offset(tile_co, tilemaps_buf[tilemap_index].tiles_index, lod); - atomicOr(tiles_buf[tile_index], SHADOW_IS_USED); + atomicOr(tiles_buf[tile_index], uint(SHADOW_IS_USED)); } void shadow_tag_usage_tilemap_directional(uint l_idx, vec3 P, vec3 V, float radius) diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_visibility_comp.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_visibility_comp.glsl index aef73672a8a..346e10d7083 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_visibility_comp.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_visibility_comp.glsl @@ -44,7 +44,7 @@ bool is_visible(IsectBox box) bool intersects_near_plane(IsectBox box) { - vec4 near_plane = drw_view_culling.planes[4]; + vec4 near_plane = drw_view_culling.frustum_planes.planes[4]; bool on_positive_side = false; bool on_negative_side = false; diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h index 28090ef2b46..3ad1e11df28 100644 --- a/source/blender/draw/intern/draw_shader_shared.h +++ b/source/blender/draw/intern/draw_shader_shared.h @@ -21,6 +21,8 @@ typedef struct DispatchCommand DispatchCommand; typedef struct DRWDebugPrintBuffer DRWDebugPrintBuffer; typedef struct DRWDebugVert DRWDebugVert; typedef struct DRWDebugDrawBuffer DRWDebugDrawBuffer; +typedef struct FrustumCorners FrustumCorners; +typedef struct FrustumPlanes FrustumPlanes; /* __cplusplus is true when compiling with MSL. */ # if defined(__cplusplus) && !defined(GPU_SHADER) @@ -94,11 +96,27 @@ uint drw_view_id = 0; # define DRW_VIEW_FROM_RESOURCE_ID drw_view_id = (drw_ResourceID & DRW_VIEW_MASK) #endif +struct FrustumCorners { + float4 corners[8]; +}; +BLI_STATIC_ASSERT_ALIGN(FrustumCorners, 16) + +struct FrustumPlanes { + /* [0] left + * [1] right + * [2] bottom + * [3] top + * [4] near + * [5] far */ + float4 planes[6]; +}; +BLI_STATIC_ASSERT_ALIGN(FrustumPlanes, 16) + struct ViewCullingData { /** \note vec3 array padded to vec4. */ /** Frustum corners. */ - float4 corners[8]; - float4 planes[6]; + FrustumCorners frustum_corners; + FrustumPlanes frustum_planes; float4 bound_sphere; }; BLI_STATIC_ASSERT_ALIGN(ViewCullingData, 16) diff --git a/source/blender/draw/intern/draw_view.cc b/source/blender/draw/intern/draw_view.cc index 30417ff6420..c6b7ac11017 100644 --- a/source/blender/draw/intern/draw_view.cc +++ b/source/blender/draw/intern/draw_view.cc @@ -50,7 +50,8 @@ void View::frustum_boundbox_calc(int view_id) } #endif - MutableSpan corners = {culling_[view_id].corners, ARRAY_SIZE(culling_[view_id].corners)}; + MutableSpan corners = {culling_[view_id].frustum_corners.corners, + ARRAY_SIZE(culling_[view_id].frustum_corners.corners)}; float left, right, bottom, top, near, far; bool is_persp = data_[view_id].winmat[3][3] == 0.0f; @@ -89,15 +90,15 @@ void View::frustum_culling_planes_calc(int view_id) { float4x4 persmat = data_[view_id].winmat * data_[view_id].viewmat; planes_from_projmat(persmat.ptr(), - culling_[view_id].planes[0], - culling_[view_id].planes[5], - culling_[view_id].planes[1], - culling_[view_id].planes[3], - culling_[view_id].planes[4], - culling_[view_id].planes[2]); + culling_[view_id].frustum_planes.planes[0], + culling_[view_id].frustum_planes.planes[5], + culling_[view_id].frustum_planes.planes[1], + culling_[view_id].frustum_planes.planes[3], + culling_[view_id].frustum_planes.planes[4], + culling_[view_id].frustum_planes.planes[2]); /* Normalize. */ - for (float4 &plane : culling_[view_id].planes) { + for (float4 &plane : culling_[view_id].frustum_planes.planes) { plane.w /= normalize_v3(plane); } } @@ -105,7 +106,8 @@ void View::frustum_culling_planes_calc(int view_id) void View::frustum_culling_sphere_calc(int view_id) { BoundSphere &bsphere = *reinterpret_cast(&culling_[view_id].bound_sphere); - Span corners = {culling_[view_id].corners, ARRAY_SIZE(culling_[view_id].corners)}; + Span corners = {culling_[view_id].frustum_corners.corners, + ARRAY_SIZE(culling_[view_id].frustum_corners.corners)}; /* Extract Bounding Sphere */ if (data_[view_id].winmat[3][3] != 0.0f) { diff --git a/source/blender/draw/intern/shaders/common_aabb_lib.glsl b/source/blender/draw/intern/shaders/common_aabb_lib.glsl index b5f664a6779..5adcdec4a3e 100644 --- a/source/blender/draw/intern/shaders/common_aabb_lib.glsl +++ b/source/blender/draw/intern/shaders/common_aabb_lib.glsl @@ -9,6 +9,14 @@ struct AABB { vec3 min, max; }; +AABB shape_aabb(vec3 min, vec3 max) +{ + AABB aabb; + aabb.min = min; + aabb.max = max; + return aabb; +} + AABB aabb_init_min_max() { AABB aabb; diff --git a/source/blender/draw/intern/shaders/common_intersect_lib.glsl b/source/blender/draw/intern/shaders/common_intersect_lib.glsl index e23216ec2e2..252298022e3 100644 --- a/source/blender/draw/intern/shaders/common_intersect_lib.glsl +++ b/source/blender/draw/intern/shaders/common_intersect_lib.glsl @@ -136,7 +136,7 @@ bool intersect_view(Pyramid pyramid) for (int p = 0; p < 6; ++p) { bool is_any_vertex_on_positive_side = false; for (int v = 0; v < 5; ++v) { - float test = dot(drw_view_culling.planes[p], vec4(pyramid.corners[v], 1.0)); + float test = dot(drw_view_culling.frustum_planes.planes[p], vec4(pyramid.corners[v], 1.0)); if (test > 0.0) { is_any_vertex_on_positive_side = true; break; @@ -158,7 +158,8 @@ bool intersect_view(Pyramid pyramid) for (int p = 0; p < 5; ++p) { bool is_any_vertex_on_positive_side = false; for (int v = 0; v < 8; ++v) { - float test = dot(i_pyramid.planes[p], vec4(drw_view_culling.corners[v].xyz, 1.0)); + float test = dot(i_pyramid.planes[p], + vec4(drw_view_culling.frustum_corners.corners[v].xyz, 1.0)); if (test > 0.0) { is_any_vertex_on_positive_side = true; break; @@ -181,7 +182,7 @@ bool intersect_view(Box box) for (int p = 0; p < 6; ++p) { bool is_any_vertex_on_positive_side = false; for (int v = 0; v < 8; ++v) { - float test = dot(drw_view_culling.planes[p], vec4(box.corners[v], 1.0)); + float test = dot(drw_view_culling.frustum_planes.planes[p], vec4(box.corners[v], 1.0)); if (test > 0.0) { is_any_vertex_on_positive_side = true; break; @@ -203,7 +204,8 @@ bool intersect_view(Box box) for (int p = 0; p < 6; ++p) { bool is_any_vertex_on_positive_side = false; for (int v = 0; v < 8; ++v) { - float test = dot(i_box.planes[p], vec4(drw_view_culling.corners[v].xyz, 1.0)); + float test = dot(i_box.planes[p], + vec4(drw_view_culling.frustum_corners.corners[v].xyz, 1.0)); if (test > 0.0) { is_any_vertex_on_positive_side = true; break; @@ -227,7 +229,7 @@ bool intersect_view(IsectBox i_box) for (int p = 0; p < 6; ++p) { bool is_any_vertex_on_positive_side = false; for (int v = 0; v < 8; ++v) { - float test = dot(drw_view_culling.planes[p], vec4(i_box.corners[v], 1.0)); + float test = dot(drw_view_culling.frustum_planes.planes[p], vec4(i_box.corners[v], 1.0)); if (test > 0.0) { is_any_vertex_on_positive_side = true; break; @@ -247,7 +249,8 @@ bool intersect_view(IsectBox i_box) for (int p = 0; p < 6; ++p) { bool is_any_vertex_on_positive_side = false; for (int v = 0; v < 8; ++v) { - float test = dot(i_box.planes[p], vec4(drw_view_culling.corners[v].xyz, 1.0)); + float test = dot(i_box.planes[p], + vec4(drw_view_culling.frustum_corners.corners[v].xyz, 1.0)); if (test > 0.0) { is_any_vertex_on_positive_side = true; break; @@ -268,7 +271,7 @@ bool intersect_view(Sphere sphere) bool intersects = true; for (int p = 0; p < 6 && intersects; ++p) { - float dist_to_plane = dot(drw_view_culling.planes[p], vec4(sphere.center, 1.0)); + float dist_to_plane = dot(drw_view_culling.frustum_planes.planes[p], vec4(sphere.center, 1.0)); if (dist_to_plane < -sphere.radius) { intersects = false; } diff --git a/source/blender/draw/intern/shaders/common_shape_lib.glsl b/source/blender/draw/intern/shaders/common_shape_lib.glsl index 56722c417aa..25a2781d729 100644 --- a/source/blender/draw/intern/shaders/common_shape_lib.glsl +++ b/source/blender/draw/intern/shaders/common_shape_lib.glsl @@ -18,7 +18,10 @@ struct Circle { Circle shape_circle(vec2 center, float radius) { - return Circle(center, radius); + Circle circle; + circle.center = center; + circle.radius = radius; + return circle; } /** \} */ @@ -34,7 +37,10 @@ struct Sphere { Sphere shape_sphere(vec3 center, float radius) { - return Sphere(center, radius); + Sphere sphere; + sphere.center = center; + sphere.radius = radius; + return sphere; } /** \} */ @@ -192,6 +198,14 @@ Frustum shape_frustum(vec3 corners[8]) struct Cone { vec3 direction; float angle_cos; + +#ifdef GPU_METAL + inline Cone() = default; + inline Cone(vec3 in_direction, float in_angle_cos) + : direction(in_direction), angle_cos(in_angle_cos) + { + } +#endif }; Cone shape_cone(vec3 direction, float angle_cosine) diff --git a/source/blender/draw/intern/shaders/draw_view_finalize_comp.glsl b/source/blender/draw/intern/shaders/draw_view_finalize_comp.glsl index f3af010a47c..6fc34af815d 100644 --- a/source/blender/draw/intern/shaders/draw_view_finalize_comp.glsl +++ b/source/blender/draw/intern/shaders/draw_view_finalize_comp.glsl @@ -33,18 +33,19 @@ void projmat_dimensions(mat4 winmat, } } -void frustum_boundbox_calc(mat4 winmat, mat4 viewinv, out vec4 corners[8]) +void frustum_boundbox_calc(mat4 winmat, mat4 viewinv, out FrustumCorners frustum_corners) { float left, right, bottom, top, near, far; bool is_persp = winmat[3][3] == 0.0; projmat_dimensions(winmat, left, right, bottom, top, near, far); - corners[0][2] = corners[3][2] = corners[7][2] = corners[4][2] = -near; - corners[0][0] = corners[3][0] = left; - corners[4][0] = corners[7][0] = right; - corners[0][1] = corners[4][1] = bottom; - corners[7][1] = corners[3][1] = top; + frustum_corners.corners[0][2] = frustum_corners.corners[3][2] = frustum_corners.corners[7][2] = + frustum_corners.corners[4][2] = -near; + frustum_corners.corners[0][0] = frustum_corners.corners[3][0] = left; + frustum_corners.corners[4][0] = frustum_corners.corners[7][0] = right; + frustum_corners.corners[0][1] = frustum_corners.corners[4][1] = bottom; + frustum_corners.corners[7][1] = frustum_corners.corners[3][1] = top; /* Get the coordinates of the far plane. */ if (is_persp) { @@ -55,25 +56,20 @@ void frustum_boundbox_calc(mat4 winmat, mat4 viewinv, out vec4 corners[8]) top *= sca_far; } - corners[1][2] = corners[2][2] = corners[6][2] = corners[5][2] = -far; - corners[1][0] = corners[2][0] = left; - corners[6][0] = corners[5][0] = right; - corners[1][1] = corners[5][1] = bottom; - corners[2][1] = corners[6][1] = top; + frustum_corners.corners[1][2] = frustum_corners.corners[2][2] = frustum_corners.corners[6][2] = + frustum_corners.corners[5][2] = -far; + frustum_corners.corners[1][0] = frustum_corners.corners[2][0] = left; + frustum_corners.corners[6][0] = frustum_corners.corners[5][0] = right; + frustum_corners.corners[1][1] = frustum_corners.corners[5][1] = bottom; + frustum_corners.corners[2][1] = frustum_corners.corners[6][1] = top; /* Transform into world space. */ for (int i = 0; i < 8; i++) { - corners[i].xyz = transform_point(viewinv, corners[i].xyz); + frustum_corners.corners[i].xyz = transform_point(viewinv, frustum_corners.corners[i].xyz); } } -void planes_from_projmat(mat4 mat, - out vec4 left, - out vec4 right, - out vec4 bottom, - out vec4 top, - out vec4 near, - out vec4 far) +void planes_from_projmat(mat4 mat, out FrustumPlanes frustum_planes) { /* References: * @@ -81,35 +77,35 @@ void planes_from_projmat(mat4 mat, * http://www8.cs.umu.se/kurser/5DV051/HT12/lab/plane_extraction.pdf */ mat = transpose(mat); - left = mat[3] + mat[0]; - right = mat[3] - mat[0]; - bottom = mat[3] + mat[1]; - top = mat[3] - mat[1]; - near = mat[3] + mat[2]; - far = mat[3] - mat[2]; + frustum_planes.planes[0] = mat[3] + mat[0]; + frustum_planes.planes[1] = mat[3] - mat[0]; + frustum_planes.planes[2] = mat[3] + mat[1]; + frustum_planes.planes[3] = mat[3] - mat[1]; + frustum_planes.planes[4] = mat[3] + mat[2]; + frustum_planes.planes[5] = mat[3] - mat[2]; } -void frustum_culling_planes_calc(mat4 winmat, mat4 viewmat, out vec4 planes[6]) +void frustum_culling_planes_calc(mat4 winmat, mat4 viewmat, out FrustumPlanes frustum_planes) { mat4 persmat = winmat * viewmat; - planes_from_projmat(persmat, planes[0], planes[5], planes[1], planes[3], planes[4], planes[2]); + planes_from_projmat(persmat, frustum_planes); /* Normalize. */ for (int p = 0; p < 6; p++) { - planes[p] /= length(planes[p].xyz); + frustum_planes.planes[p] /= length(frustum_planes.planes[p].xyz); } } -vec4 frustum_culling_sphere_calc(vec4 corners[8]) +vec4 frustum_culling_sphere_calc(FrustumCorners frustum_corners) { /* Extract Bounding Sphere */ /* TODO(fclem): This is significantly less precise than CPU, but it isn't used in most cases. */ vec4 bsphere; - bsphere.xyz = (corners[0].xyz + corners[6].xyz) * 0.5; + bsphere.xyz = (frustum_corners.corners[0].xyz + frustum_corners.corners[6].xyz) * 0.5; bsphere.w = 0.0; for (int i = 0; i < 8; i++) { - bsphere.w = max(bsphere.w, distance(bsphere.xyz, corners[i].xyz)); + bsphere.w = max(bsphere.w, distance(bsphere.xyz, frustum_corners.corners[i].xyz)); } return bsphere; } @@ -125,11 +121,15 @@ void main() return; } - frustum_boundbox_calc(drw_view.winmat, drw_view.viewinv, view_culling_buf[drw_view_id].corners); + /* Read frustom_corners from device memory, update, and write back. */ + FrustumCorners frustum_corners = view_culling_buf[drw_view_id].frustum_corners; + frustum_boundbox_calc(drw_view.winmat, drw_view.viewinv, frustum_corners); + view_culling_buf[drw_view_id].frustum_corners = frustum_corners; - frustum_culling_planes_calc( - drw_view.winmat, drw_view.viewmat, view_culling_buf[drw_view_id].planes); + /* Read frustum_planes from device memory, update, and write back. */ + FrustumPlanes frustum_planes = view_culling_buf[drw_view_id].frustum_planes; + frustum_culling_planes_calc(drw_view.winmat, drw_view.viewmat, frustum_planes); - view_culling_buf[drw_view_id].bound_sphere = frustum_culling_sphere_calc( - view_culling_buf[drw_view_id].corners); + view_culling_buf[drw_view_id].frustum_planes = frustum_planes; + view_culling_buf[drw_view_id].bound_sphere = frustum_culling_sphere_calc(frustum_corners); } diff --git a/source/blender/draw/intern/shaders/draw_visibility_comp.glsl b/source/blender/draw/intern/shaders/draw_visibility_comp.glsl index f3ca51dbf6b..0d2717aea64 100644 --- a/source/blender/draw/intern/shaders/draw_visibility_comp.glsl +++ b/source/blender/draw/intern/shaders/draw_visibility_comp.glsl @@ -34,8 +34,9 @@ void main() bounds.bounding_corners[1].xyz, bounds.bounding_corners[2].xyz, bounds.bounding_corners[3].xyz); - Sphere bounding_sphere = Sphere(bounds.bounding_sphere.xyz, bounds.bounding_sphere.w); - Sphere inscribed_sphere = Sphere(bounds.bounding_sphere.xyz, bounds._inner_sphere_radius); + Sphere bounding_sphere = shape_sphere(bounds.bounding_sphere.xyz, bounds.bounding_sphere.w); + Sphere inscribed_sphere = shape_sphere(bounds.bounding_sphere.xyz, + bounds._inner_sphere_radius); for (drw_view_id = 0; drw_view_id < view_len; drw_view_id++) { if (drw_view_culling.bound_sphere.w == -1.0) { diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 810914dc6cb..8fd3cbe2451 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -233,7 +233,8 @@ AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale) ANIMCONT_DOPESHEET, ANIMCONT_FCURVES, ANIMCONT_NLA, - ANIMCONT_CHANNEL)) { + ANIMCONT_CHANNEL, + ANIMCONT_TIMELINE)) { /* handling depends on the type of animation-context we've got */ if (ale) { /* NLA Control Curves occur on NLA strips, @@ -343,12 +344,20 @@ static void fcurve_scene_coord_range_get(Scene *scene, int end = fcu->totvert; if (use_preview_only) { - /* Preview frame ranges need to be converted to bezt array indices. */ - bool replace = false; - start = BKE_fcurve_bezt_binarysearch_index( - fcu->bezt, scene->r.psfra, fcu->totvert, &replace); + if (fcu->bezt) { + /* Preview frame ranges need to be converted to bezt array indices. */ + bool replace = false; + start = BKE_fcurve_bezt_binarysearch_index( + fcu->bezt, scene->r.psfra, fcu->totvert, &replace); - end = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, scene->r.pefra, fcu->totvert, &replace); + end = BKE_fcurve_bezt_binarysearch_index( + fcu->bezt, scene->r.pefra + 1, fcu->totvert, &replace); + } + else if (fcu->fpt) { + const int unclamped_start = (int)(scene->r.psfra - fcu->fpt[0].vec[0]); + start = max_ii(unclamped_start, 0); + end = min_ii(unclamped_start + (scene->r.pefra - scene->r.psfra) + 1, fcu->totvert); + } } if (fcu->bezt) { diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 982f3585b33..fb775fde717 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -808,11 +808,14 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES ops.gpencil.primitive_line ops.gpencil.primitive_polyline ops.gpencil.radius + ops.gpencil.sculpt_average + ops.gpencil.sculpt_blur ops.gpencil.sculpt_clone ops.gpencil.sculpt_grab ops.gpencil.sculpt_pinch ops.gpencil.sculpt_push ops.gpencil.sculpt_randomize + ops.gpencil.sculpt_smear ops.gpencil.sculpt_smooth ops.gpencil.sculpt_strength ops.gpencil.sculpt_thickness diff --git a/source/blender/editors/gpencil_legacy/gpencil_data.c b/source/blender/editors/gpencil_legacy/gpencil_data.c index 846e2f3893f..25d424b92cb 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_data.c +++ b/source/blender/editors/gpencil_legacy/gpencil_data.c @@ -2079,7 +2079,7 @@ static void gpencil_brush_delete_mode_brushes(Main *bmain, } if (mode == CTX_MODE_WEIGHT_GPENCIL) { - if (preset != GP_BRUSH_PRESET_DRAW_WEIGHT) { + if ((preset < GP_BRUSH_PRESET_WEIGHT_DRAW) || (preset > GP_BRUSH_PRESET_WEIGHT_SMEAR)) { continue; } if ((brush_active) && (brush_active->gpencil_weight_tool != brush->gpencil_weight_tool)) { @@ -2666,58 +2666,67 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op) continue; } - /* look for tot value */ - float *tot_values = MEM_callocN(gps->totpoints * sizeof(float), __func__); - + /* Loop all points in stroke. */ for (int i = 0; i < gps->totpoints; i++) { + int v; + float sum = 0.0f; + float sum_lock = 0.0f; + float sum_unlock = 0.0f; + + /* Get vertex groups and weights. */ dvert = &gps->dvert[i]; - for (int v = 0; v < defbase_tot; v++) { + + /* Sum weights. */ + for (v = 0; v < defbase_tot; v++) { + /* Get vertex group. */ defgroup = BLI_findlink(&gpd->vertex_group_names, v); - /* skip NULL or locked groups */ - if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) { - continue; - } - - /* skip current */ - if ((lock_active) && (v == def_nr)) { + if (defgroup == NULL) { continue; } + /* Get weight in vertex group. */ dw = BKE_defvert_find_index(dvert, v); - if (dw != NULL) { - tot_values[i] += dw->weight; + if (dw == NULL) { + continue; + } + sum += dw->weight; + + /* Vertex group locked or unlocked? */ + if ((defgroup->flag & DG_LOCK_WEIGHT) || ((lock_active) && (v == def_nr))) { + sum_lock += dw->weight; + } + else { + sum_unlock += dw->weight; } } - } - /* normalize weights */ - for (int i = 0; i < gps->totpoints; i++) { - if (tot_values[i] == 0.0f) { + if ((sum == 1.0f) || (sum_unlock == 0.0f)) { continue; } - dvert = &gps->dvert[i]; - for (int v = 0; v < defbase_tot; v++) { + /* Normalize weights. */ + float fac = MAX2(0, (1.0f - sum_lock) / sum_unlock); + + for (v = 0; v < defbase_tot; v++) { + /* Get vertex group. */ defgroup = BLI_findlink(&gpd->vertex_group_names, v); - /* skip NULL or locked groups */ - if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) { - continue; - } - - /* skip current */ - if ((lock_active) && (v == def_nr)) { + if (defgroup == NULL) { continue; } + /* Get weight in vertex group. */ dw = BKE_defvert_find_index(dvert, v); - if (dw != NULL) { - dw->weight = dw->weight / tot_values[i]; + if (dw == NULL) { + continue; + } + + /* Normalize in unlocked vertex groups only. */ + if (!((defgroup->flag & DG_LOCK_WEIGHT) || ((lock_active) && (v == def_nr)))) { + dw->weight *= fac; + CLAMP(dw->weight, 0.0f, 1.0f); } } } - - /* free temp array */ - MEM_SAFE_FREE(tot_values); } CTX_DATA_END; diff --git a/source/blender/editors/gpencil_legacy/gpencil_edit.c b/source/blender/editors/gpencil_legacy/gpencil_edit.c index b6eb55bc937..d98615ab166 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_edit.c +++ b/source/blender/editors/gpencil_legacy/gpencil_edit.c @@ -725,7 +725,9 @@ static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op) } if (mode == OB_MODE_VERTEX_GPENCIL) { - /* Be sure we have brushes. */ + /* Be sure we have brushes. + * Need Draw as well (used for Palettes). */ + BKE_paint_ensure(ts, (Paint **)&ts->gp_paint); BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint); const bool reset_mode = (ts->gp_vertexpaint->paint.brush == NULL); diff --git a/source/blender/editors/gpencil_legacy/gpencil_intern.h b/source/blender/editors/gpencil_legacy/gpencil_intern.h index fdfc7a51b4a..d03322c98bb 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_intern.h +++ b/source/blender/editors/gpencil_legacy/gpencil_intern.h @@ -518,6 +518,8 @@ void GPENCIL_OT_stroke_editcurve_set_handle_type(struct wmOperatorType *ot); */ void GPENCIL_OT_sculpt_paint(struct wmOperatorType *ot); void GPENCIL_OT_weight_paint(struct wmOperatorType *ot); +void GPENCIL_OT_weight_toggle_direction(struct wmOperatorType *ot); +void GPENCIL_OT_weight_sample(struct wmOperatorType *ot); /* buttons editing --- */ diff --git a/source/blender/editors/gpencil_legacy/gpencil_ops.c b/source/blender/editors/gpencil_legacy/gpencil_ops.c index b534928999d..2db2cab7d0b 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_ops.c +++ b/source/blender/editors/gpencil_legacy/gpencil_ops.c @@ -292,6 +292,24 @@ static bool gpencil_stroke_weightmode_draw_poll(bContext *C) return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_DRAW); } +/* Poll callback for weight paint (Blur) */ +static bool gpencil_stroke_weightmode_blur_poll(bContext *C) +{ + return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_BLUR); +} + +/* Poll callback for weight paint (Average) */ +static bool gpencil_stroke_weightmode_average_poll(bContext *C) +{ + return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_AVERAGE); +} + +/* Poll callback for weight paint (Smear) */ +static bool gpencil_stroke_weightmode_smear_poll(bContext *C) +{ + return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_SMEAR); +} + /* Stroke Editing Keymap - Only when editmode is enabled */ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) { @@ -460,6 +478,24 @@ static void ed_keymap_gpencil_weightpainting_draw(wmKeyConfig *keyconf) wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Draw)", 0, 0); keymap->poll = gpencil_stroke_weightmode_draw_poll; } +/* keys for weight with a blur brush */ +static void ed_keymap_gpencil_weightpainting_blur(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Blur)", 0, 0); + keymap->poll = gpencil_stroke_weightmode_blur_poll; +} +/* keys for weight with a average brush */ +static void ed_keymap_gpencil_weightpainting_average(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Average)", 0, 0); + keymap->poll = gpencil_stroke_weightmode_average_poll; +} +/* keys for weight with a smear brush */ +static void ed_keymap_gpencil_weightpainting_smear(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Smear)", 0, 0); + keymap->poll = gpencil_stroke_weightmode_smear_poll; +} /* ==================== */ @@ -485,6 +521,9 @@ void ED_keymap_gpencil(wmKeyConfig *keyconf) ed_keymap_gpencil_sculptpainting_clone(keyconf); ed_keymap_gpencil_weightpainting(keyconf); ed_keymap_gpencil_weightpainting_draw(keyconf); + ed_keymap_gpencil_weightpainting_blur(keyconf); + ed_keymap_gpencil_weightpainting_average(keyconf); + ed_keymap_gpencil_weightpainting_smear(keyconf); ed_keymap_gpencil_vertexpainting(keyconf); ed_keymap_gpencil_vertexpainting_draw(keyconf); ed_keymap_gpencil_vertexpainting_blur(keyconf); @@ -564,6 +603,8 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_sculpt_paint); WM_operatortype_append(GPENCIL_OT_weight_paint); + WM_operatortype_append(GPENCIL_OT_weight_toggle_direction); + WM_operatortype_append(GPENCIL_OT_weight_sample); /* Edit stroke editcurve */ diff --git a/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c b/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c index da3706ed34b..c27a6073b35 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c @@ -9,6 +9,9 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_kdtree.h" +#include "BLI_listbase.h" #include "BLI_math.h" #include "BLT_translation.h" @@ -16,6 +19,7 @@ #include "DNA_armature_types.h" #include "DNA_brush_types.h" #include "DNA_gpencil_legacy_types.h" +#include "DNA_gpencil_modifier_types.h" #include "BKE_action.h" #include "BKE_brush.h" @@ -50,6 +54,9 @@ /* ************************************************ */ /* General Brush Editing Context */ #define GP_SELECT_BUFFER_CHUNK 256 +#define GP_FIND_NEAREST_BUFFER_CHUNK 1024 +#define GP_FIND_NEAREST_EPSILON 1e-6f +#define GP_STROKE_HASH_BITSHIFT 16 /* Grid of Colors for Smear. */ typedef struct tGP_Grid { @@ -70,10 +77,12 @@ typedef struct tGP_Selected { bGPDstroke *gps; /** Point index in points array. */ int pt_index; - /** Position */ + /** Position. */ int pc[2]; - /** Color */ + /** Color. */ float color[4]; + /** Weight. */ + float weight; } tGP_Selected; /* Context for brush operators */ @@ -102,23 +111,30 @@ typedef struct tGP_BrushWeightpaintData { bool is_multiframe; bool use_multiframe_falloff; - /* active vertex group */ + /* Draw tool: add or subtract? */ + bool subtract; + + /* Auto-normalize weights of bone-deformed vertices? */ + bool auto_normalize; + + /* Active vertex group */ int vrgroup; /* Brush Runtime Data: */ /* - position and pressure * - the *_prev variants are the previous values */ - float mval[2], mval_prev[2]; - float pressure, pressure_prev; + float mouse[2], mouse_prev[2]; + float pressure; - /* - Effect 2D vector */ - float dvec[2]; + /* - Brush direction. */ + float brush_dir[2]; + bool brush_dir_is_set; - /* - multi-frame falloff factor. */ + /* - Multi-frame falloff factor. */ float mf_falloff; - /* brush geometry (bounding box). */ + /* Brush geometry (bounding box). */ rcti brush_rect; /* Temp data to save selected points */ @@ -128,45 +144,364 @@ typedef struct tGP_BrushWeightpaintData { int pbuffer_used; /** Number of total elements available in cache. */ int pbuffer_size; + /** Average weight of elements in cache (used for average tool). */ + float pbuffer_avg_weight; + + /* Temp data for find-nearest-points, used by blur and smear tool. */ + bool use_find_nearest; + /** Buffer of stroke points during one mouse swipe. */ + tGP_Selected *fn_pbuffer; + /** Hash table of added points (to avoid duplicate entries). */ + GHash *fn_added; + /** KDtree for finding nearest points. */ + KDTree_2d *fn_kdtree; + /** Number of points used in find-nearest set. */ + uint fn_used; + /** Number of points available in find-nearest set. */ + uint fn_size; + /** Flag for balancing kdtree. */ + bool fn_do_balance; + + /* Temp data for auto-normalize weights used by deforming bones. */ + /** Boolean array of locked vertex groups. */ + bool *vgroup_locked; + /** Boolean array of vertex groups deformed by bones. */ + bool *vgroup_bone_deformed; + /** Number of vertex groups in object. */ + int vgroup_tot; + } tGP_BrushWeightpaintData; /* Ensure the buffer to hold temp selected point size is enough to save all points selected. */ -static tGP_Selected *gpencil_select_buffer_ensure(tGP_Selected *buffer_array, - int *buffer_size, - int *buffer_used, - const bool clear) +static void gpencil_select_buffer_ensure(tGP_BrushWeightpaintData *gso, const bool clear) { - tGP_Selected *p = NULL; - /* By default a buffer is created with one block with a predefined number of free slots, * if the size is not enough, the cache is reallocated adding a new block of free slots. * This is done in order to keep cache small and improve speed. */ - if (*buffer_used + 1 > *buffer_size) { - if ((*buffer_size == 0) || (buffer_array == NULL)) { - p = MEM_callocN(sizeof(struct tGP_Selected) * GP_SELECT_BUFFER_CHUNK, __func__); - *buffer_size = GP_SELECT_BUFFER_CHUNK; + if ((gso->pbuffer_used + 1) > gso->pbuffer_size) { + if ((gso->pbuffer_size == 0) || (gso->pbuffer == NULL)) { + gso->pbuffer = MEM_callocN(sizeof(struct tGP_Selected) * GP_SELECT_BUFFER_CHUNK, __func__); + gso->pbuffer_size = GP_SELECT_BUFFER_CHUNK; } else { - *buffer_size += GP_SELECT_BUFFER_CHUNK; - p = MEM_recallocN(buffer_array, sizeof(struct tGP_Selected) * *buffer_size); + gso->pbuffer_size += GP_SELECT_BUFFER_CHUNK; + gso->pbuffer = MEM_recallocN(gso->pbuffer, sizeof(struct tGP_Selected) * gso->pbuffer_size); } - - if (p == NULL) { - *buffer_size = *buffer_used = 0; - } - - buffer_array = p; } - /* clear old data */ + /* Clear old data. */ if (clear) { - *buffer_used = 0; - if (buffer_array != NULL) { - memset(buffer_array, 0, sizeof(tGP_Selected) * *buffer_size); + gso->pbuffer_used = 0; + if (gso->pbuffer != NULL) { + memset(gso->pbuffer, 0, sizeof(tGP_Selected) * gso->pbuffer_size); } } - return buffer_array; + /* Create or enlarge buffer for find-nearest-points. */ + if (gso->use_find_nearest && ((gso->fn_used + 1) > gso->fn_size)) { + gso->fn_size += GP_FIND_NEAREST_BUFFER_CHUNK; + + /* Stroke point buffer. */ + if (gso->fn_pbuffer == NULL) { + gso->fn_pbuffer = MEM_callocN(sizeof(struct tGP_Selected) * gso->fn_size, __func__); + } + else { + gso->fn_pbuffer = MEM_recallocN(gso->fn_pbuffer, sizeof(struct tGP_Selected) * gso->fn_size); + } + + /* Stroke point hash table (for duplicate checking.) */ + if (gso->fn_added == NULL) { + gso->fn_added = BLI_ghash_int_new("GP weight paint find nearest"); + } + + /* KDtree of stroke points. */ + bool do_tree_rebuild = false; + if (gso->fn_kdtree != NULL) { + BLI_kdtree_2d_free(gso->fn_kdtree); + do_tree_rebuild = true; + } + gso->fn_kdtree = BLI_kdtree_2d_new(gso->fn_size); + + if (do_tree_rebuild) { + for (int i = 0; i < gso->fn_used; i++) { + float pc_f[2]; + copy_v2fl_v2i(pc_f, gso->fn_pbuffer[i].pc); + BLI_kdtree_2d_insert(gso->fn_kdtree, i, pc_f); + } + } + } +} + +/* Ensure a vertex group for the weight paint brush. */ +static void gpencil_vertex_group_ensure(tGP_BrushWeightpaintData *gso) +{ + if (gso->vrgroup >= 0) { + return; + } + if (gso->object == NULL) { + return; + } + + DEG_relations_tag_update(gso->bmain); + gso->vrgroup = 0; + + Object *ob_armature = BKE_modifiers_is_deformed_by_armature(gso->object); + if (ob_armature == NULL) { + BKE_object_defgroup_add(gso->object); + return; + } + Bone *actbone = ((bArmature *)ob_armature->data)->act_bone; + if (actbone == NULL) { + return; + } + bPoseChannel *pchan = BKE_pose_channel_find_name(ob_armature->pose, actbone->name); + if (pchan == NULL) { + return; + } + bDeformGroup *dg = BKE_object_defgroup_find_name(gso->object, pchan->name); + if (dg == NULL) { + BKE_object_defgroup_add_name(gso->object, pchan->name); + } +} + +static void gpencil_select_buffer_avg_weight_set(tGP_BrushWeightpaintData *gso) +{ + if (gso->pbuffer_used == 0) { + gso->pbuffer_avg_weight = 0.0f; + return; + } + float sum = 0; + for (int i = 0; i < gso->pbuffer_used; i++) { + tGP_Selected *selected = &gso->pbuffer[i]; + sum += selected->weight; + } + gso->pbuffer_avg_weight = sum / gso->pbuffer_used; + CLAMP(gso->pbuffer_avg_weight, 0.0f, 1.0f); +} + +/* Get boolean array of vertex groups deformed by GP armature modifiers. + * GP equivalent of `BKE_object_defgroup_validmap_get`. + */ +static bool *gpencil_vgroup_bone_deformed_map_get(Object *ob, const int defbase_tot) +{ + bDeformGroup *dg; + bool *vgroup_bone_deformed; + GHash *gh; + int i; + const ListBase *defbase = BKE_object_defgroup_list(ob); + + if (BLI_listbase_is_empty(defbase)) { + return NULL; + } + + /* Add all vertex group names to a hash table. */ + gh = BLI_ghash_str_new_ex(__func__, defbase_tot); + for (dg = defbase->first; dg; dg = dg->next) { + BLI_ghash_insert(gh, dg->name, NULL); + } + BLI_assert(BLI_ghash_len(gh) == defbase_tot); + + /* Now loop through the armature modifiers and identify deform bones. */ + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { + if (md->type != eGpencilModifierType_Armature) { + continue; + } + + ArmatureGpencilModifierData *amd = (ArmatureGpencilModifierData *)md; + + if (amd->object && amd->object->pose) { + bPose *pose = amd->object->pose; + bPoseChannel *chan; + + for (chan = pose->chanbase.first; chan; chan = chan->next) { + void **val_p; + if (chan->bone->flag & BONE_NO_DEFORM) { + continue; + } + + val_p = BLI_ghash_lookup_p(gh, chan->name); + if (val_p) { + *val_p = POINTER_FROM_INT(1); + } + } + } + } + + /* Mark vertex groups with reference in the bone hash table. */ + vgroup_bone_deformed = MEM_mallocN(sizeof(*vgroup_bone_deformed) * defbase_tot, __func__); + for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) { + vgroup_bone_deformed[i] = (BLI_ghash_lookup(gh, dg->name) != NULL); + } + + BLI_assert(i == BLI_ghash_len(gh)); + + BLI_ghash_free(gh, NULL, NULL); + + return vgroup_bone_deformed; +} + +/* ************************************************ */ +/* Auto-normalize Operations + * This section defines the functions for auto-normalizing the sum of weights to 1.0 + * for points in vertex groups deformed by bones. + * The logic is copied from `editors/sculpt_paint/paint_vertex.cc`. */ + +/** + * Normalize weights of a stroke point deformed by bones. + */ +static void do_weight_paint_normalize_all(MDeformVert *dvert, + const int defbase_tot, + const bool *vgroup_bone_deformed) +{ + float sum = 0.0f, fac; + uint tot = 0; + MDeformWeight *dw; + + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + tot++; + sum += dw->weight; + } + } + + if ((tot == 0) || (sum == 1.0f)) { + return; + } + + if (sum != 0.0f) { + fac = 1.0f / sum; + + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + dw->weight *= fac; + } + } + } + else { + fac = 1.0f / tot; + + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + dw->weight = fac; + } + } + } +} + +/** + * A version of #do_weight_paint_normalize_all that only changes unlocked weights. + */ +static bool do_weight_paint_normalize_all_unlocked(MDeformVert *dvert, + const int defbase_tot, + const bool *vgroup_bone_deformed, + const bool *vgroup_locked, + const bool lock_active_vgroup, + const int active_vgroup) +{ + float sum = 0.0f, fac; + float sum_unlock = 0.0f; + float sum_lock = 0.0f; + uint tot = 0; + MDeformWeight *dw; + + if (vgroup_locked == NULL) { + do_weight_paint_normalize_all(dvert, defbase_tot, vgroup_bone_deformed); + return true; + } + + if (dvert->totweight <= 1) { + return true; + } + + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + sum += dw->weight; + + if (vgroup_locked[dw->def_nr] || (lock_active_vgroup && active_vgroup == dw->def_nr)) { + sum_lock += dw->weight; + } + else { + tot++; + sum_unlock += dw->weight; + } + } + } + + if (sum == 1.0f) { + return true; + } + + if (tot == 0) { + return false; + } + + if (sum_lock >= 1.0f - VERTEX_WEIGHT_LOCK_EPSILON) { + /* Locked groups make it impossible to fully normalize, + * zero out what we can and return false. */ + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + *dw = dvert->dw[i]; + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + if ((vgroup_locked[dw->def_nr] == false) && + !(lock_active_vgroup && active_vgroup == dw->def_nr)) { + dw->weight = 0.0f; + } + } + } + + return (sum_lock == 1.0f); + } + if (sum_unlock != 0.0f) { + fac = (1.0f - sum_lock) / sum_unlock; + + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + if ((vgroup_locked[dw->def_nr] == false) && + !(lock_active_vgroup && active_vgroup == dw->def_nr)) { + dw->weight *= fac; + CLAMP(dw->weight, 0.0f, 1.0f); + } + } + } + } + else { + fac = (1.0f - sum_lock) / tot; + CLAMP(fac, 0.0f, 1.0f); + + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + if ((vgroup_locked[dw->def_nr] == false) && + !(lock_active_vgroup && active_vgroup == dw->def_nr)) { + dw->weight = fac; + } + } + } + } + + return true; +} + +/** + * A version of #do_weight_paint_normalize_all that only changes unlocked weights + * and does a second pass without the active vertex group locked when the first pass fails. + */ +static void do_weight_paint_normalize_all_try(MDeformVert *dvert, tGP_BrushWeightpaintData *gso) +{ + /* First pass with both active and explicitly locked vertex groups restricted from change. */ + bool succes = do_weight_paint_normalize_all_unlocked( + dvert, gso->vgroup_tot, gso->vgroup_bone_deformed, gso->vgroup_locked, true, gso->vrgroup); + + if (!succes) { + /* Second pass with active vertex group unlocked. */ + do_weight_paint_normalize_all_unlocked( + dvert, gso->vgroup_tot, gso->vgroup_bone_deformed, gso->vgroup_locked, false, -1); + } } /* Brush Operations ------------------------------- */ @@ -185,10 +520,9 @@ static float brush_influence_calc(tGP_BrushWeightpaintData *gso, const int radiu } /* distance fading */ - int mval_i[2]; - round_v2i_v2fl(mval_i, gso->mval); - float distance = (float)len_v2v2_int(mval_i, co); - influence *= 1.0f - (distance / max_ff(radius, 1e-8)); + int mouse_i[2]; + round_v2i_v2fl(mouse_i, gso->mouse); + float distance = (float)len_v2v2_int(mouse_i, co); /* Apply Brush curve. */ float brush_falloff = BKE_brush_curve_strength(brush, distance, (float)radius); @@ -202,12 +536,19 @@ static float brush_influence_calc(tGP_BrushWeightpaintData *gso, const int radiu } /* Compute effect vector for directional brushes. */ -static void brush_calc_dvec_2d(tGP_BrushWeightpaintData *gso) +static void brush_calc_brush_dir_2d(tGP_BrushWeightpaintData *gso) { - gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]); - gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]); + sub_v2_v2v2(gso->brush_dir, gso->mouse, gso->mouse_prev); - normalize_v2(gso->dvec); + /* Skip tiny changes in direction, we want the bigger movements only. */ + if (len_squared_v2(gso->brush_dir) < 9.0f) { + return; + } + + normalize_v2(gso->brush_dir); + + gso->brush_dir_is_set = true; + copy_v2_v2(gso->mouse_prev, gso->mouse); } /* ************************************************ */ @@ -222,58 +563,213 @@ static bool brush_draw_apply(tGP_BrushWeightpaintData *gso, const int radius, const int co[2]) { - /* create dvert */ - BKE_gpencil_dvert_ensure(gps); - MDeformVert *dvert = gps->dvert + pt_index; - float inf; - /* Compute strength of effect */ - inf = brush_influence_calc(gso, radius, co); + /* Compute strength of effect. */ + float inf = brush_influence_calc(gso, radius, co); - /* need a vertex group */ - if (gso->vrgroup == -1) { - if (gso->object) { - Object *ob_armature = BKE_modifiers_is_deformed_by_armature(gso->object); - if (ob_armature != NULL) { - Bone *actbone = ((bArmature *)ob_armature->data)->act_bone; - if (actbone != NULL) { - bPoseChannel *pchan = BKE_pose_channel_find_name(ob_armature->pose, actbone->name); - if (pchan != NULL) { - bDeformGroup *dg = BKE_object_defgroup_find_name(gso->object, pchan->name); - if (dg == NULL) { - dg = BKE_object_defgroup_add_name(gso->object, pchan->name); - } - } + /* Get current weight. */ + MDeformWeight *dw = BKE_defvert_ensure_index(dvert, gso->vrgroup); + if (dw == NULL) { + return false; + } + + /* Apply brush weight. */ + float bweight = (gso->subtract) ? -gso->brush->weight : gso->brush->weight; + dw->weight = interpf(bweight, dw->weight, inf); + CLAMP(dw->weight, 0.0f, 1.0f); + + /* Perform auto-normalize. */ + if (gso->auto_normalize) { + do_weight_paint_normalize_all_try(dvert, gso); + } + + return true; +} + +/* Average Brush */ +static bool brush_average_apply(tGP_BrushWeightpaintData *gso, + bGPDstroke *gps, + int pt_index, + const int radius, + const int co[2]) +{ + MDeformVert *dvert = gps->dvert + pt_index; + + /* Compute strength of effect. */ + float inf = brush_influence_calc(gso, radius, co); + + /* Get current weight. */ + MDeformWeight *dw = BKE_defvert_ensure_index(dvert, gso->vrgroup); + if (dw == NULL) { + return false; + } + + /* Blend weight with average weight under the brush. */ + dw->weight = interpf(gso->pbuffer_avg_weight, dw->weight, inf); + CLAMP(dw->weight, 0.0f, 1.0f); + + /* Perform auto-normalize. */ + if (gso->auto_normalize) { + do_weight_paint_normalize_all_try(dvert, gso); + } + + return true; +} + +/* Blur Brush */ +static bool brush_blur_apply(tGP_BrushWeightpaintData *gso, + bGPDstroke *gps, + int pt_index, + const int radius, + const int co[2]) +{ + MDeformVert *dvert = gps->dvert + pt_index; + + /* Compute strength of effect. */ + float inf = brush_influence_calc(gso, radius, co); + + /* Get current weight. */ + MDeformWeight *dw = BKE_defvert_ensure_index(dvert, gso->vrgroup); + if (dw == NULL) { + return false; + } + + /* Find the 5 nearest points (this includes the to-be-blurred point itself). */ + KDTreeNearest_2d nearest[5]; + float pc_f[2]; + copy_v2fl_v2i(pc_f, co); + const int tot = BLI_kdtree_2d_find_nearest_n(gso->fn_kdtree, pc_f, nearest, 5); + + /* Calculate the average (=blurred) weight. */ + float blur_weight = 0.0f, dist_sum = 0.0f; + int count = 0; + for (int i = 0; i < tot; i++) { + dist_sum += nearest[i].dist; + count++; + } + if (count <= 1) { + return false; + } + for (int i = 0; i < tot; i++) { + /* Weighted average, based on distance to point. */ + blur_weight += (1.0f - nearest[i].dist / dist_sum) * gso->fn_pbuffer[nearest[i].index].weight; + } + blur_weight /= (count - 1); + + /* Blend weight with blurred weight. */ + dw->weight = interpf(blur_weight, dw->weight, inf); + CLAMP(dw->weight, 0.0f, 1.0f); + + /* Perform auto-normalize. */ + if (gso->auto_normalize) { + do_weight_paint_normalize_all_try(dvert, gso); + } + + return true; +} + +/* Smear Brush */ +static bool brush_smear_apply(tGP_BrushWeightpaintData *gso, + bGPDstroke *gps, + int pt_index, + const int radius, + const int co[2]) +{ + MDeformVert *dvert = gps->dvert + pt_index; + + /* Get current weight. */ + MDeformWeight *dw = BKE_defvert_ensure_index(dvert, gso->vrgroup); + if (dw == NULL) { + return false; + } + + /* Find the 8 nearest points (this includes the to-be-blurred point itself). */ + KDTreeNearest_2d nearest[8]; + float pc_f[2]; + copy_v2fl_v2i(pc_f, co); + const int tot = BLI_kdtree_2d_find_nearest_n(gso->fn_kdtree, pc_f, nearest, 8); + + /* For smearing a weight from point A to point B, we look for a point A 'behind' the brush, + * matching the brush angle best and with the shortest distance to B. */ + float point_dot[8] = {0}; + float point_dir[2]; + float score_max = 0.0f, dist_min = FLT_MAX, dist_max = 0.0f; + int i_max = -1, count = 0; + + for (int i = 0; i < tot; i++) { + /* Skip the point we are about to smear. */ + if (nearest[i].dist > GP_FIND_NEAREST_EPSILON) { + sub_v2_v2v2(point_dir, pc_f, nearest[i].co); + normalize_v2(point_dir); + + /* Match A-B direction with brush direction. */ + point_dot[i] = dot_v2v2(point_dir, gso->brush_dir); + if (point_dot[i] > 0.0f) { + count++; + float dist = nearest[i].dist; + if (dist < dist_min) { + dist_min = dist; + } + if (dist > dist_max) { + dist_max = dist; } } - else { - BKE_object_defgroup_add(gso->object); + } + } + if (count == 0) { + return false; + } + + /* Find best match in angle and distance. */ + float dist_f = (dist_min == dist_max) ? 1.0f : 0.95f / (dist_max - dist_min); + for (int i = 0; i < tot; i++) { + if (point_dot[i] > 0.0f) { + float score = point_dot[i] * (1.0f - (nearest[i].dist - dist_min) * dist_f); + if (score > score_max) { + score_max = score; + i_max = i; } - DEG_relations_tag_update(gso->bmain); - gso->vrgroup = 0; } } - else { - bDeformGroup *defgroup = BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup); - if (defgroup->flag & DG_LOCK_WEIGHT) { - return false; - } + if (i_max == -1) { + return false; } - /* Get current weight and blend. */ - MDeformWeight *dw = BKE_defvert_ensure_index(dvert, gso->vrgroup); - if (dw) { - dw->weight = interpf(gso->brush->weight, dw->weight, inf); - CLAMP(dw->weight, 0.0f, 1.0f); + + /* Compute strength of effect. */ + float inf = brush_influence_calc(gso, radius, co); + + /* Smear the weight. */ + dw->weight = interpf(gso->fn_pbuffer[nearest[i_max].index].weight, dw->weight, inf); + CLAMP(dw->weight, 0.0f, 1.0f); + + /* Perform auto-normalize. */ + if (gso->auto_normalize) { + do_weight_paint_normalize_all_try(dvert, gso); } + return true; } /* ************************************************ */ /* Header Info */ -static void gpencil_weightpaint_brush_header_set(bContext *C) +static void gpencil_weightpaint_brush_header_set(bContext *C, tGP_BrushWeightpaintData *gso) { - ED_workspace_status_text(C, TIP_("GPencil Weight Paint: LMB to paint | RMB/Escape to Exit")); + switch (gso->brush->gpencil_weight_tool) { + case GPWEIGHT_TOOL_DRAW: + ED_workspace_status_text(C, TIP_("GPencil Weight Paint: LMB to paint | RMB/Escape to Exit")); + break; + case GPWEIGHT_TOOL_BLUR: + ED_workspace_status_text(C, TIP_("GPencil Weight Blur: LMB to blur | RMB/Escape to Exit")); + break; + case GPWEIGHT_TOOL_AVERAGE: + ED_workspace_status_text( + C, TIP_("GPencil Weight Average: LMB to set average | RMB/Escape to Exit")); + break; + case GPWEIGHT_TOOL_SMEAR: + ED_workspace_status_text(C, TIP_("GPencil Weight Smear: LMB to smear | RMB/Escape to Exit")); + break; + } } /* ************************************************ */ @@ -307,6 +803,14 @@ static bool gpencil_weightpaint_brush_init(bContext *C, wmOperator *op) gso->pbuffer_size = 0; gso->pbuffer_used = 0; + gso->fn_pbuffer = NULL; + gso->fn_added = NULL; + gso->fn_kdtree = NULL; + gso->fn_used = 0; + gso->fn_size = 0; + gso->use_find_nearest = ((gso->brush->gpencil_weight_tool == GPWEIGHT_TOOL_BLUR) || + (gso->brush->gpencil_weight_tool == GPWEIGHT_TOOL_SMEAR)); + gso->gpd = ED_gpencil_data_get_active(C); gso->scene = scene; gso->object = ob; @@ -332,11 +836,32 @@ static bool gpencil_weightpaint_brush_init(bContext *C, wmOperator *op) BKE_curvemapping_init(ts->gp_sculpt.cur_falloff); } + /* Draw tool: add or subtract weight? */ + gso->subtract = (gso->brush->gpencil_settings->sculpt_flag & BRUSH_DIR_IN); + + /* Setup auto-normalize. */ + gso->auto_normalize = (ts->auto_normalize && gso->vrgroup != -1); + if (gso->auto_normalize) { + gso->vgroup_tot = BLI_listbase_count(&gso->gpd->vertex_group_names); + /* Get boolean array of vertex groups deformed by bones. */ + gso->vgroup_bone_deformed = gpencil_vgroup_bone_deformed_map_get(ob, gso->vgroup_tot); + if (gso->vgroup_bone_deformed != NULL) { + /* Get boolean array of locked vertex groups. */ + gso->vgroup_locked = BKE_object_defgroup_lock_flags_get(ob, gso->vgroup_tot); + if (gso->vgroup_locked == NULL) { + gso->vgroup_locked = (bool *)MEM_callocN(sizeof(bool) * gso->vgroup_tot, __func__); + } + } + else { + gso->auto_normalize = false; + } + } + /* Setup space conversions. */ gpencil_point_conversion_init(C, &gso->gsc); /* Update header. */ - gpencil_weightpaint_brush_header_set(C); + gpencil_weightpaint_brush_header_set(C, gso); return true; } @@ -349,6 +874,15 @@ static void gpencil_weightpaint_brush_exit(bContext *C, wmOperator *op) ED_workspace_status_text(C, NULL); /* Free operator data */ + MEM_SAFE_FREE(gso->vgroup_bone_deformed); + MEM_SAFE_FREE(gso->vgroup_locked); + if (gso->fn_kdtree != NULL) { + BLI_kdtree_2d_free(gso->fn_kdtree); + } + if (gso->fn_added != NULL) { + BLI_ghash_free(gso->fn_added, NULL, NULL); + } + MEM_SAFE_FREE(gso->fn_pbuffer); MEM_SAFE_FREE(gso->pbuffer); MEM_SAFE_FREE(gso); op->customdata = NULL; @@ -357,6 +891,27 @@ static void gpencil_weightpaint_brush_exit(bContext *C, wmOperator *op) /* Poll callback for stroke weight paint operator. */ static bool gpencil_weightpaint_brush_poll(bContext *C) { + if (!ED_operator_regionactive(C)) { + CTX_wm_operator_poll_msg_set(C, "Active region not set"); + return false; + } + + ScrArea *area = CTX_wm_area(C); + if (area->spacetype != SPACE_VIEW3D) { + return false; + } + + bGPdata *gpd = ED_gpencil_data_get_active(C); + if ((gpd == NULL) || (!GPENCIL_WEIGHT_MODE(gpd))) { + return false; + } + + ToolSettings *ts = CTX_data_scene(C)->toolsettings; + if (!ts->gp_weightpaint->paint.brush) { + CTX_wm_operator_poll_msg_set(C, "Grease Pencil has no active paint tool"); + return false; + } + /* NOTE: this is a bit slower, but is the most accurate... */ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0; } @@ -364,36 +919,88 @@ static bool gpencil_weightpaint_brush_poll(bContext *C) /* Helper to save the points selected by the brush. */ static void gpencil_save_selected_point(tGP_BrushWeightpaintData *gso, bGPDstroke *gps, - int index, - int pc[2]) + const int gps_index, + const int index, + const int pc[2], + const bool within_brush) { tGP_Selected *selected; bGPDspoint *pt = &gps->points[index]; /* Ensure the array to save the list of selected points is big enough. */ - gso->pbuffer = gpencil_select_buffer_ensure( - gso->pbuffer, &gso->pbuffer_size, &gso->pbuffer_used, false); + gpencil_select_buffer_ensure(gso, false); - selected = &gso->pbuffer[gso->pbuffer_used]; - selected->gps = gps; - selected->pt_index = index; - copy_v2_v2_int(selected->pc, pc); - copy_v4_v4(selected->color, pt->vert_color); + /* Copy point data. */ + if (within_brush) { + selected = &gso->pbuffer[gso->pbuffer_used]; + selected->gps = gps; + selected->pt_index = index; + copy_v2_v2_int(selected->pc, pc); + copy_v4_v4(selected->color, pt->vert_color); + gso->pbuffer_used++; + } - gso->pbuffer_used++; + /* Ensure vertex group and dvert. */ + gpencil_vertex_group_ensure(gso); + BKE_gpencil_dvert_ensure(gps); + + /* Copy current weight. */ + MDeformVert *dvert = gps->dvert + index; + MDeformWeight *dw = BKE_defvert_find_index(dvert, gso->vrgroup); + if (within_brush && (dw != NULL)) { + selected->weight = dw->weight; + } + + /* Store point for finding nearest points (blur, smear). */ + if (gso->use_find_nearest) { + /* Create hash key, assuming there are no more than 65536 strokes in a frame + * and 65536 points in a stroke. */ + const int point_hash = (gps_index << GP_STROKE_HASH_BITSHIFT) + index; + + /* Prevent duplicate points in buffer. */ + if (!BLI_ghash_haskey(gso->fn_added, POINTER_FROM_INT(point_hash))) { + /* Add stroke point to find-nearest buffer. */ + selected = &gso->fn_pbuffer[gso->fn_used]; + copy_v2_v2_int(selected->pc, pc); + selected->weight = (dw == NULL) ? 0.0f : dw->weight; + + BLI_ghash_insert( + gso->fn_added, POINTER_FROM_INT(point_hash), POINTER_FROM_INT(gso->fn_used)); + + float pc_f[2]; + copy_v2_fl2(pc_f, (float)pc[0], (float)pc[1]); + BLI_kdtree_2d_insert(gso->fn_kdtree, gso->fn_used, pc_f); + + gso->fn_do_balance = true; + gso->fn_used++; + } + else { + /* Update weight of point in buffer. */ + int *idx = BLI_ghash_lookup(gso->fn_added, POINTER_FROM_INT(point_hash)); + selected = &gso->fn_pbuffer[POINTER_AS_INT(idx)]; + selected->weight = (dw == NULL) ? 0.0f : dw->weight; + } + } } /* Select points in this stroke and add to an array to be used later. */ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, bGPDstroke *gps, + const int gps_index, const float diff_mat[4][4], const float bound_mat[4][4]) { GP_SpaceConversion *gsc = &gso->gsc; rcti *rect = &gso->brush_rect; Brush *brush = gso->brush; - const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : + /* For the blur tool, look a bit wider than the brush itself, + * because we need the weight of surrounding points to perform the blur. */ + const bool widen_brush = (gso->brush->gpencil_weight_tool == GPWEIGHT_TOOL_BLUR); + int radius_brush = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : gso->brush->size; + int radius_wide = (widen_brush) ? radius_brush * 1.3f : radius_brush; + bool within_brush = true; + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; bGPDspoint *pt_active = NULL; @@ -405,8 +1012,8 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, int index; bool include_last = false; - /* Check if the stroke collide with brush. */ - if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) { + /* Check if the stroke collides with brush. */ + if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mouse, radius_wide, bound_mat)) { return; } @@ -420,12 +1027,16 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, /* Do bound-box check first. */ if (!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ - int mval_i[2]; - round_v2i_v2fl(mval_i, gso->mval); - if (len_v2v2_int(mval_i, pc1) <= radius) { + int mouse_i[2]; + round_v2i_v2fl(mouse_i, gso->mouse); + int mlen = len_v2v2_int(mouse_i, pc1); + if (mlen <= radius_wide) { /* apply operation to this point */ if (pt_active != NULL) { - gpencil_save_selected_point(gso, gps_active, 0, pc1); + if (widen_brush) { + within_brush = (mlen <= radius_brush); + } + gpencil_save_selected_point(gso, gps_active, gps_index, 0, pc1, within_brush); } } } @@ -453,14 +1064,19 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, * brush region (either within stroke painted, or on its lines) * - this assumes that line-width is irrelevant. */ - if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { + if (gpencil_stroke_inside_circle( + gso->mouse, radius_wide, pc1[0], pc1[1], pc2[0], pc2[1])) { + if (widen_brush) { + within_brush = (gpencil_stroke_inside_circle( + gso->mouse, radius_brush, pc1[0], pc1[1], pc2[0], pc2[1])); + } /* To each point individually... */ pt = &gps->points[i]; pt_active = pt->runtime.pt_orig; if (pt_active != NULL) { index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; - gpencil_save_selected_point(gso, gps_active, index, pc1); + gpencil_save_selected_point(gso, gps_active, gps_index, index, pc1, within_brush); } /* Only do the second point if this is the last segment, @@ -476,7 +1092,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, pt_active = pt->runtime.pt_orig; if (pt_active != NULL) { index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1; - gpencil_save_selected_point(gso, gps_active, index, pc2); + gpencil_save_selected_point(gso, gps_active, gps_index, index, pc2, within_brush); include_last = false; } } @@ -494,8 +1110,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, pt_active = pt->runtime.pt_orig; if (pt_active != NULL) { index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; - gpencil_save_selected_point(gso, gps_active, index, pc1); - + gpencil_save_selected_point(gso, gps_active, gps_index, index, pc1, true); include_last = false; } } @@ -507,7 +1122,6 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, /* Apply weight paint brushes to strokes in the given frame. */ static bool gpencil_weightpaint_brush_do_frame(bContext *C, tGP_BrushWeightpaintData *gso, - bGPDlayer *gpl, bGPDframe *gpf, const float diff_mat[4][4], const float bound_mat[4][4]) @@ -518,39 +1132,68 @@ static bool gpencil_weightpaint_brush_do_frame(bContext *C, gso->brush->size * gso->pressure : gso->brush->size; tGP_Selected *selected = NULL; - int i; + gso->fn_do_balance = false; /*--------------------------------------------------------------------- * First step: select the points affected. This step is required to have * all selected points before apply the effect, because it could be * required to do some step. Now is not used, but the operator is ready. *--------------------------------------------------------------------- */ - LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + int gps_index; + LISTBASE_FOREACH_INDEX (bGPDstroke *, gps, &gpf->strokes, gps_index) { /* Skip strokes that are invalid for current view. */ if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; } - /* Check if the color is editable. */ - if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { + /* Check if the color is visible. */ + if (ED_gpencil_stroke_material_visible(ob, gps) == false) { continue; } /* Check points below the brush. */ - gpencil_weightpaint_select_stroke(gso, gps, diff_mat, bound_mat); + gpencil_weightpaint_select_stroke(gso, gps, gps_index, diff_mat, bound_mat); + } + + bDeformGroup *defgroup = BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup); + if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) { + return false; } /*--------------------------------------------------------------------- - * Second step: Apply effect. + * Second step: Calculations on selected points. + *--------------------------------------------------------------------- */ + /* For average tool, get average weight of affected points. */ + if (tool == GPWEIGHT_TOOL_AVERAGE) { + gpencil_select_buffer_avg_weight_set(gso); + } + /* Balance find-nearest kdtree. */ + if (gso->use_find_nearest && gso->fn_do_balance) { + BLI_kdtree_2d_balance(gso->fn_kdtree); + } + + /*--------------------------------------------------------------------- + * Third step: Apply effect. *--------------------------------------------------------------------- */ bool changed = false; - for (i = 0; i < gso->pbuffer_used; i++) { - changed = true; + for (int i = 0; i < gso->pbuffer_used; i++) { selected = &gso->pbuffer[i]; switch (tool) { case GPWEIGHT_TOOL_DRAW: { - brush_draw_apply(gso, selected->gps, selected->pt_index, radius, selected->pc); - changed |= true; + changed |= brush_draw_apply(gso, selected->gps, selected->pt_index, radius, selected->pc); + break; + } + case GPWEIGHT_TOOL_AVERAGE: { + changed |= brush_average_apply( + gso, selected->gps, selected->pt_index, radius, selected->pc); + break; + } + case GPWEIGHT_TOOL_BLUR: { + changed |= brush_blur_apply(gso, selected->gps, selected->pt_index, radius, selected->pc); + break; + } + case GPWEIGHT_TOOL_SMEAR: { + changed |= brush_smear_apply(gso, selected->gps, selected->pt_index, radius, selected->pc); break; } default: @@ -558,9 +1201,9 @@ static bool gpencil_weightpaint_brush_do_frame(bContext *C, break; } } + /* Clear the selected array, but keep the memory allocation. */ - gso->pbuffer = gpencil_select_buffer_ensure( - gso->pbuffer, &gso->pbuffer_size, &gso->pbuffer_used, true); + gpencil_select_buffer_ensure(gso, true); return changed; } @@ -615,17 +1258,14 @@ static bool gpencil_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeig } /* affect strokes in this frame */ - changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat, bound_mat); + changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpf, diff_mat, bound_mat); } } } else { - if (gpl->actframe != NULL) { - /* Apply to active frame's strokes */ - gso->mf_falloff = 1.0f; - changed |= gpencil_weightpaint_brush_do_frame( - C, gso, gpl, gpl->actframe, diff_mat, bound_mat); - } + /* Apply to active frame's strokes */ + gso->mf_falloff = 1.0f; + changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl->actframe, diff_mat, bound_mat); } } @@ -645,17 +1285,18 @@ static void gpencil_weightpaint_brush_apply(bContext *C, wmOperator *op, Pointer /* Get latest mouse coordinates */ RNA_float_get_array(itemptr, "mouse", mousef); - gso->mval[0] = mouse[0] = (int)(mousef[0]); - gso->mval[1] = mouse[1] = (int)(mousef[1]); + gso->mouse[0] = mouse[0] = (int)(mousef[0]); + gso->mouse[1] = mouse[1] = (int)(mousef[1]); gso->pressure = RNA_float_get(itemptr, "pressure"); /* Store coordinates as reference, if operator just started running */ if (gso->first) { - gso->mval_prev[0] = gso->mval[0]; - gso->mval_prev[1] = gso->mval[1]; - gso->pressure_prev = gso->pressure; + gso->mouse_prev[0] = gso->mouse[0]; + gso->mouse_prev[1] = gso->mouse[1]; + gso->brush_dir_is_set = false; } + gso->first = false; /* Update brush_rect, so that it represents the bounding rectangle of brush. */ gso->brush_rect.xmin = mouse[0] - radius; @@ -663,22 +1304,23 @@ static void gpencil_weightpaint_brush_apply(bContext *C, wmOperator *op, Pointer gso->brush_rect.xmax = mouse[0] + radius; gso->brush_rect.ymax = mouse[1] + radius; - /* Calculate 2D direction vector and relative angle. */ - brush_calc_dvec_2d(gso); + /* Calculate brush direction. */ + if (gso->brush->gpencil_weight_tool == GPWEIGHT_TOOL_SMEAR) { + brush_calc_brush_dir_2d(gso); + if (!gso->brush_dir_is_set) { + return; + } + } + + /* Apply brush to layers. */ changed = gpencil_weightpaint_brush_apply_to_layers(C, gso); - /* Updates */ + /* Updates. */ if (changed) { DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } - - /* Store values for next step */ - gso->mval_prev[0] = gso->mval[0]; - gso->mval_prev[1] = gso->mval[1]; - gso->pressure_prev = gso->pressure; - gso->first = false; } /* Running --------------------------------------------- */ @@ -699,7 +1341,6 @@ static void gpencil_weightpaint_brush_apply_event(bContext *C, RNA_collection_add(op->ptr, "stroke", &itemptr); RNA_float_set_array(&itemptr, "mouse", mouse); - RNA_boolean_set(&itemptr, "pen_flip", event->modifier & KM_CTRL); RNA_boolean_set(&itemptr, "is_start", gso->first); /* Handle pressure sensitivity (which is supplied by tablets). */ @@ -888,7 +1529,7 @@ void GPENCIL_OT_weight_paint(wmOperatorType *ot) /* identifiers */ ot->name = "Stroke Weight Paint"; ot->idname = "GPENCIL_OT_weight_paint"; - ot->description = "Paint stroke points with a color"; + ot->description = "Draw weight on stroke points"; /* api callbacks */ ot->exec = gpencil_weightpaint_brush_exec; @@ -908,3 +1549,175 @@ void GPENCIL_OT_weight_paint(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } + +/* -------------------------------------------------------------------- */ +/* Weight Toggle Add/Subtract Operator */ +static int gpencil_weight_toggle_direction_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *UNUSED(event)) +{ + ToolSettings *ts = CTX_data_tool_settings(C); + Paint *paint = &ts->gp_weightpaint->paint; + + /* Toggle Add/Subtract flag. */ + paint->brush->gpencil_settings->sculpt_flag ^= BRUSH_DIR_IN; + + /* Update tool settings. */ + WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_weight_toggle_direction(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Weight Paint Toggle Direction"; + ot->idname = "GPENCIL_OT_weight_toggle_direction"; + ot->description = "Toggle Add/Subtract for the weight paint draw tool"; + + /* api callbacks */ + ot->invoke = gpencil_weight_toggle_direction_invoke; + ot->poll = gpencil_weightpaint_brush_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* -------------------------------------------------------------------- */ +/* Weight Sample Operator */ +static int gpencil_weight_sample_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + /* Get mouse position. */ + int mouse[2]; + mouse[0] = event->mval[0] + 1; + mouse[1] = event->mval[1] + 1; + float mouse_f[2]; + copy_v2fl_v2i(mouse_f, mouse); + + /* Get active GP object. */ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Object *ob = CTX_data_active_object(C); + bGPdata *gpd = ED_gpencil_data_get_active(C); + + if ((ob == NULL) || (gpd == NULL)) { + return OPERATOR_CANCELLED; + } + + /* Get active vertex group. */ + int vgroup = gpd->vertex_group_active_index - 1; + bDeformGroup *defgroup = BLI_findlink(&gpd->vertex_group_names, vgroup); + if (!defgroup) { + return OPERATOR_CANCELLED; + } + + /* Init space conversion. */ + GP_SpaceConversion gsc = {NULL}; + gpencil_point_conversion_init(C, &gsc); + + /* Get evaluated GP object. */ + Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &ob->id); + bGPdata *gpd_eval = (bGPdata *)ob_eval->data; + + /* Get brush radius. */ + ToolSettings *ts = CTX_data_tool_settings(C); + Brush *brush = ts->gp_weightpaint->paint.brush; + const int radius = brush->size; + + /* Init closest points. */ + float closest_dist[2] = {FLT_MAX, FLT_MAX}; + float closest_weight[2] = {0.0f, 0.0f}; + int closest_count = 0; + int pc[2] = {0}; + + /* Inspect all layers. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_eval->layers) { + /* If no active frame, don't do anything. */ + if (gpl->actframe == NULL) { + continue; + } + + /* Calculate transform matrix. */ + float diff_mat[4][4], bound_mat[4][4]; + BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat); + copy_m4_m4(bound_mat, diff_mat); + mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_invmat); + + /* Inspect all strokes in active frame. */ + LISTBASE_FOREACH (bGPDstroke *, gps, &gpl->actframe->strokes) { + /* Look for strokes that collide with the brush. */ + if (!ED_gpencil_stroke_check_collision(&gsc, gps, mouse_f, radius, bound_mat)) { + continue; + } + if (gps->dvert == NULL) { + continue; + } + + /* Look for two closest points. */ + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + bGPDspoint npt; + + gpencil_point_to_world_space(pt, diff_mat, &npt); + gpencil_point_to_xy(&gsc, gps, &npt, &pc[0], &pc[1]); + + float dist = len_v2v2_int(pc, mouse); + + if ((dist < closest_dist[0]) || (dist < closest_dist[1])) { + /* Get weight. */ + MDeformVert *dvert = &gps->dvert[i]; + MDeformWeight *dw = BKE_defvert_find_index(dvert, vgroup); + if (dw == NULL) { + continue; + } + if (dist < closest_dist[0]) { + closest_dist[1] = closest_dist[0]; + closest_weight[1] = closest_weight[0]; + closest_dist[0] = dist; + closest_weight[0] = dw->weight; + closest_count++; + } + else if (dist < closest_dist[1]) { + closest_dist[1] = dist; + closest_weight[1] = dw->weight; + closest_count++; + } + } + } + } + } + + /* Set brush weight, based on points found.*/ + if (closest_count > 0) { + if (closest_count == 1) { + brush->weight = closest_weight[0]; + } + else { + CLAMP_MIN(closest_dist[1], 1e-6f); + float dist_sum = closest_dist[0] + closest_dist[1]; + brush->weight = (1.0f - closest_dist[0] / dist_sum) * closest_weight[0] + + (1.0f - closest_dist[1] / dist_sum) * closest_weight[1]; + } + + /* Update tool settings. */ + WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); + + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +void GPENCIL_OT_weight_sample(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Weight Paint Sample Weight"; + ot->idname = "GPENCIL_OT_weight_sample"; + ot->description = "Use the mouse to sample a weight in the 3D view"; + + /* api callbacks */ + ot->invoke = gpencil_weight_sample_invoke; + ot->poll = gpencil_weightpaint_brush_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} diff --git a/source/blender/editors/interface/interface_icons.cc b/source/blender/editors/interface/interface_icons.cc index b5b190f7957..772f45ceb02 100644 --- a/source/blender/editors/interface/interface_icons.cc +++ b/source/blender/editors/interface/interface_icons.cc @@ -2215,6 +2215,15 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id) case GP_BRUSH_ICON_GPBRUSH_WEIGHT: br->id.icon_id = ICON_GPBRUSH_WEIGHT; break; + case GP_BRUSH_ICON_GPBRUSH_BLUR: + br->id.icon_id = ICON_BRUSH_BLUR; + break; + case GP_BRUSH_ICON_GPBRUSH_AVERAGE: + br->id.icon_id = ICON_BRUSH_BLUR; + break; + case GP_BRUSH_ICON_GPBRUSH_SMEAR: + br->id.icon_id = ICON_BRUSH_BLUR; + break; default: br->id.icon_id = ICON_GPBRUSH_PEN; break; diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc index 34d83e9118d..aee9a1a5fa0 100644 --- a/source/blender/editors/object/object_add.cc +++ b/source/blender/editors/object/object_add.cc @@ -3156,7 +3156,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id); Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_MESH); - me_eval = BKE_mesh_copy_for_eval(me_eval, false); + me_eval = BKE_mesh_copy_for_eval(me_eval); BKE_object_material_from_eval_data(bmain, newob, &me_eval->id); Mesh *new_mesh = (Mesh *)newob->data; BKE_mesh_nomain_to_mesh(me_eval, new_mesh, newob); @@ -3388,7 +3388,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) newob->type = OB_MESH; if (const Mesh *mesh_eval = geometry.get_mesh_for_read()) { - BKE_mesh_nomain_to_mesh(BKE_mesh_copy_for_eval(mesh_eval, false), new_mesh, newob); + BKE_mesh_nomain_to_mesh(BKE_mesh_copy_for_eval(mesh_eval), new_mesh, newob); BKE_object_material_from_eval_data(bmain, newob, &mesh_eval->id); new_mesh->attributes_for_write().remove_anonymous(); } diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index e7458f168bc..faea7712c26 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -1107,7 +1107,7 @@ static bool modifier_apply_obdata( /* Copy the relevant information to the original. */ Main *bmain = DEG_get_bmain(depsgraph); BKE_object_material_from_eval_data(bmain, ob, &pointcloud_eval->id); - BKE_pointcloud_nomain_to_pointcloud(pointcloud_eval, &points, true); + BKE_pointcloud_nomain_to_pointcloud(pointcloud_eval, &points); } else { /* TODO: implement for volumes. */ diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index f9bad0c6e06..a9ee1d32803 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -778,7 +778,7 @@ static Mesh *remesh_symmetry_bisect(Mesh *mesh, eSymmetryAxes symmetry_axes) mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE; Mesh *mesh_bisect, *mesh_bisect_temp; - mesh_bisect = BKE_mesh_copy_for_eval(mesh, false); + mesh_bisect = BKE_mesh_copy_for_eval(mesh); int axis; float plane_co[3], plane_no[3]; @@ -860,7 +860,7 @@ static void quadriflow_start_job(void *customdata, bool *stop, bool *do_update, /* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without * freeing the original ID */ - bisect_mesh = BKE_mesh_copy_for_eval(mesh, false); + bisect_mesh = BKE_mesh_copy_for_eval(mesh); /* Bisect the input mesh using the paint symmetry settings */ bisect_mesh = remesh_symmetry_bisect(bisect_mesh, qj->symmetry_axes); diff --git a/source/blender/editors/screen/area.cc b/source/blender/editors/screen/area.cc index 1b6cb2a80de..3bb43bcb975 100644 --- a/source/blender/editors/screen/area.cc +++ b/source/blender/editors/screen/area.cc @@ -1845,6 +1845,18 @@ static void ed_default_handlers( wmKeyMap *keymap_weight_draw = WM_keymap_ensure( wm->defaultconf, "Grease Pencil Stroke Weight (Draw)", 0, 0); WM_event_add_keymap_handler(handlers, keymap_weight_draw); + + wmKeyMap *keymap_weight_blur = WM_keymap_ensure( + wm->defaultconf, "Grease Pencil Stroke Weight (Blur)", 0, 0); + WM_event_add_keymap_handler(handlers, keymap_weight_blur); + + wmKeyMap *keymap_weight_average = WM_keymap_ensure( + wm->defaultconf, "Grease Pencil Stroke Weight (Average)", 0, 0); + WM_event_add_keymap_handler(handlers, keymap_weight_average); + + wmKeyMap *keymap_weight_smear = WM_keymap_ensure( + wm->defaultconf, "Grease Pencil Stroke Weight (Smear)", 0, 0); + WM_event_add_keymap_handler(handlers, keymap_weight_smear); } } diff --git a/source/blender/editors/sculpt_paint/paint_mask.cc b/source/blender/editors/sculpt_paint/paint_mask.cc index 2ccfa93c5b5..6a6bc0759ad 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.cc +++ b/source/blender/editors/sculpt_paint/paint_mask.cc @@ -1135,7 +1135,7 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex const int trim_totverts = tot_screen_points * 2; const int trim_totpolys = (2 * (tot_screen_points - 2)) + (2 * tot_screen_points); - trim_operation->mesh = BKE_mesh_new_nomain(trim_totverts, 0, trim_totpolys * 3, trim_totpolys); + trim_operation->mesh = BKE_mesh_new_nomain(trim_totverts, 0, trim_totpolys, trim_totpolys * 3); trim_operation->true_mesh_co = static_cast( MEM_malloc_arrayN(trim_totverts, sizeof(float[3]), "mesh orco")); diff --git a/source/blender/editors/sculpt_paint/paint_ops.cc b/source/blender/editors/sculpt_paint/paint_ops.cc index c68930fd43a..124250c44c9 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.cc +++ b/source/blender/editors/sculpt_paint/paint_ops.cc @@ -132,7 +132,19 @@ static eGPBrush_Presets gpencil_get_brush_preset_from_tool(bToolRef *tool, break; } case CTX_MODE_WEIGHT_GPENCIL: { - return GP_BRUSH_PRESET_DRAW_WEIGHT; + if (STREQ(tool->runtime->data_block, "DRAW")) { + return GP_BRUSH_PRESET_WEIGHT_DRAW; + } + if (STREQ(tool->runtime->data_block, "BLUR")) { + return GP_BRUSH_PRESET_WEIGHT_BLUR; + } + if (STREQ(tool->runtime->data_block, "AVERAGE")) { + return GP_BRUSH_PRESET_WEIGHT_AVERAGE; + } + if (STREQ(tool->runtime->data_block, "SMEAR")) { + return GP_BRUSH_PRESET_WEIGHT_SMEAR; + } + break; } case CTX_MODE_VERTEX_GPENCIL: { if (STREQ(tool->runtime->data_block, "DRAW")) { diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.cc b/source/blender/editors/sculpt_paint/sculpt_boundary.cc index 964633d988d..ce47e6c97cf 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.cc +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.cc @@ -7,7 +7,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_edgehash.h" #include "BLI_math.h" #include "BLI_task.h" @@ -199,7 +198,6 @@ static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss, struct BoundaryFloodFillData { SculptBoundary *boundary; GSet *included_verts; - EdgeSet *preview_edges; PBVHVertRef last_visited_vertex; }; diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.cc b/source/blender/editors/sculpt_paint/sculpt_expand.cc index 2aeff54e39f..523fcbae2c5 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.cc +++ b/source/blender/editors/sculpt_paint/sculpt_expand.cc @@ -148,8 +148,24 @@ static bool sculpt_expand_is_face_in_active_component(SculptSession *ss, ExpandCache *expand_cache, const int f) { - const int vert = ss->corner_verts[ss->polys[f].start()]; - return sculpt_expand_is_vert_in_active_component(ss, expand_cache, BKE_pbvh_make_vref(vert)); + PBVHVertRef vertex; + + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + vertex.i = ss->corner_verts[ss->polys[f].start()]; + break; + case PBVH_GRIDS: { + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + vertex.i = ss->polys[f].start() * key->grid_area; + + break; + } + case PBVH_BMESH: { + vertex.i = reinterpret_cast(ss->bm->ftable[f]->l_first->v); + break; + } + } + return sculpt_expand_is_vert_in_active_component(ss, expand_cache, vertex); } /** diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 4aa53f952cc..a9c041fb505 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1832,7 +1832,7 @@ static int file_external_operation_exec(bContext *C, wmOperator *op) #endif BKE_reportf( - op->reports, RPT_ERROR, "Failure to perform exernal file operation on \"%s\"", filepath); + op->reports, RPT_ERROR, "Failure to perform external file operation on \"%s\"", filepath); WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT); return OPERATOR_CANCELLED; } @@ -1869,7 +1869,7 @@ void FILE_OT_external_operation(wmOperatorType *ot) RNA_def_enum(ot->srna, "operation", file_external_operation, - 0, + FILE_EXTERNAL_OPERATION_OPEN, "Operation", "Operation to perform on the file or path"); } diff --git a/source/blender/editors/space_node/add_node_search.cc b/source/blender/editors/space_node/add_node_search.cc index c0ba8cd998e..56cfb2480e9 100644 --- a/source/blender/editors/space_node/add_node_search.cc +++ b/source/blender/editors/space_node/add_node_search.cc @@ -158,14 +158,17 @@ static void gather_add_node_operations(const bContext &C, { NODE_TYPES_BEGIN (node_type) { const char *disabled_hint; - if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) { + if (node_type->poll && !node_type->poll(node_type, &node_tree, &disabled_hint)) { + continue; + } + if (node_type->add_ui_poll && !node_type->add_ui_poll(&C)) { continue; } if (!node_type->gather_add_node_search_ops) { continue; } Vector info_items; - nodes::GatherAddNodeSearchParams params(*node_type, node_tree, info_items); + nodes::GatherAddNodeSearchParams params(C, *node_type, node_tree, info_items); node_type->gather_add_node_search_ops(params); for (nodes::AddNodeInfo &info : info_items) { AddNodeItem item{}; diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc index ae0261a57b9..e656a709cfb 100644 --- a/source/blender/editors/space_node/link_drag_search.cc +++ b/source/blender/editors/space_node/link_drag_search.cc @@ -285,7 +285,10 @@ static void gather_socket_link_operations(const bContext &C, { NODE_TYPES_BEGIN (node_type) { const char *disabled_hint; - if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) { + if (node_type->poll && !node_type->poll(node_type, &node_tree, &disabled_hint)) { + continue; + } + if (node_type->add_ui_poll && !node_type->add_ui_poll(&C)) { continue; } if (StringRefNull(node_type->ui_name).endswith("(Legacy)")) { diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index e20f2b63d53..87b733168bf 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -1242,7 +1242,7 @@ void sequencer_image_seq_reserve_frames( char ext[PATH_MAX]; char filename_stripped[PATH_MAX]; /* Strip the frame from filename and substitute with `#`. */ - BLI_path_frame_strip(filename, ext); + BLI_path_frame_strip(filename, ext, sizeof(ext)); for (int i = 0; i < len; i++, se++) { BLI_strncpy(filename_stripped, filename, sizeof(filename_stripped)); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index 975e4c10f21..33651885e2a 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -510,28 +510,23 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread } } else { - if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) { - Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval); - if (mesh == nullptr) { - return geometry_set; + if (BLI_listbase_count(&sspreadsheet->viewer_path.path) == 1) { + if (const GeometrySet *geometry_eval = object_eval->runtime.geometry_set_eval) { + geometry_set = *geometry_eval; + } + + if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) { + if (Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval)) { + BKE_mesh_wrapper_ensure_mdata(mesh); + geometry_set.replace_mesh(mesh, GeometryOwnershipType::ReadOnly); + } } - BKE_mesh_wrapper_ensure_mdata(mesh); - MeshComponent &mesh_component = geometry_set.get_component_for_write(); - mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); } else { - if (BLI_listbase_count(&sspreadsheet->viewer_path.path) == 1) { - /* Use final evaluated object. */ - if (object_eval->runtime.geometry_set_eval != nullptr) { - geometry_set = *object_eval->runtime.geometry_set_eval; - } - } - else { - if (const ViewerNodeLog *viewer_log = - nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_path( - sspreadsheet->viewer_path)) { - geometry_set = viewer_log->geometry; - } + if (const ViewerNodeLog *viewer_log = + nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_path( + sspreadsheet->viewer_path)) { + geometry_set = viewer_log->geometry; } } } diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 2ca90a2f788..747e3a537fa 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -45,7 +45,7 @@ set(SRC view3d_gizmo_navigate_type.c view3d_gizmo_preselect.c view3d_gizmo_preselect_type.cc - view3d_gizmo_ruler.c + view3d_gizmo_ruler.cc view3d_gizmo_tool_generic.c view3d_header.c view3d_iterators.cc diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.cc similarity index 80% rename from source/blender/editors/space_view3d/view3d_gizmo_ruler.c rename to source/blender/editors/space_view3d/view3d_gizmo_ruler.cc index 16195a896bd..e08c6989266 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.cc @@ -6,6 +6,9 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_math_matrix.hh" +#include "BLI_math_matrix_types.hh" +#include "BLI_math_vector_types.hh" #include "BLI_rect.h" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -58,6 +61,13 @@ #include "BLF_api.h" +using blender::float2; +using blender::float2x2; +using blender::float3; +using blender::float3x2; +using blender::float3x3; +using blender::float4; + /** * Supporting transform features could be removed if the actual transform system is used. * Keep the option open since each transform feature is duplicating logic. @@ -115,7 +125,7 @@ enum { struct RulerItem; -typedef struct RulerInfo { +struct RulerInfo { struct RulerItem *item_active; int flag; int snap_flag; @@ -143,27 +153,26 @@ typedef struct RulerInfo { wmGizmo *gizmo; PropertyRNA *prop_prevpoint; } snap_data; - -} RulerInfo; +}; /* -------------------------------------------------------------------- */ /* Ruler Item (two or three points) */ -typedef struct RulerItem { +struct RulerItem { wmGizmo gz; /** World-space coords, middle being optional. */ - float co[3][3]; + float3x3 co; int flag; int raycast_dir; /* RULER_DIRECTION_* */ -} RulerItem; +}; -typedef struct RulerInteraction { +struct RulerInteraction { /* selected coord */ char co_index; /* 0 -> 2 */ - float drag_start_co[3]; -} RulerInteraction; + float3 drag_start_co; +}; /* -------------------------------------------------------------------- */ /** \name Internal Ruler Utilities @@ -173,16 +182,16 @@ static RulerItem *ruler_item_add(wmGizmoGroup *gzgroup) { /* could pass this as an arg */ const wmGizmoType *gzt_ruler = WM_gizmotype_find("VIEW3D_GT_ruler_item", true); - RulerItem *ruler_item = (RulerItem *)WM_gizmo_new_ptr(gzt_ruler, gzgroup, NULL); + RulerItem *ruler_item = (RulerItem *)WM_gizmo_new_ptr(gzt_ruler, gzgroup, nullptr); WM_gizmo_set_flag(&ruler_item->gz, WM_GIZMO_DRAW_MODAL, true); return ruler_item; } static void ruler_item_remove(bContext *C, wmGizmoGroup *gzgroup, RulerItem *ruler_item) { - RulerInfo *ruler_info = gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); if (ruler_info->item_active == ruler_item) { - ruler_info->item_active = NULL; + ruler_info->item_active = nullptr; } WM_gizmo_unlink(&gzgroup->gizmos, gzgroup->parent_gzmap, &ruler_item->gz, C); } @@ -199,7 +208,7 @@ static void ruler_item_as_string( } else { BKE_unit_value_as_string( - numstr, numstr_size, (double)ruler_angle, prec, B_UNIT_ROTATION, unit, false); + numstr, numstr_size, double(ruler_angle), prec, B_UNIT_ROTATION, unit, false); } } else { @@ -211,7 +220,7 @@ static void ruler_item_as_string( else { BKE_unit_value_as_string(numstr, numstr_size, - (double)(ruler_len * unit->scale_length), + double(ruler_len * unit->scale_length), prec, B_UNIT_LENGTH, unit, @@ -222,10 +231,10 @@ static void ruler_item_as_string( static bool view3d_ruler_pick(wmGizmoGroup *gzgroup, RulerItem *ruler_item, - const float mval[2], + const float2 mval, int *r_co_index) { - RulerInfo *ruler_info = gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); ARegion *region = ruler_info->region; bool found = false; @@ -233,7 +242,7 @@ static bool view3d_ruler_pick(wmGizmoGroup *gzgroup, int co_index_best = -1; { - float co_ss[3][2]; + float3x2 co_ss; float dist; int j; @@ -250,10 +259,10 @@ static bool view3d_ruler_pick(wmGizmoGroup *gzgroup, found = true; { - const float dist_points[3] = { - len_squared_v2v2(co_ss[0], mval), - len_squared_v2v2(co_ss[1], mval), - len_squared_v2v2(co_ss[2], mval), + const float3 dist_points = { + blender::math::distance_squared(co_ss[0], mval), + blender::math::distance_squared(co_ss[1], mval), + blender::math::distance_squared(co_ss[2], mval), }; if (min_fff(UNPACK3(dist_points)) < RULER_PICK_DIST_SQ) { co_index_best = min_axis_v3(dist_points); @@ -271,9 +280,9 @@ static bool view3d_ruler_pick(wmGizmoGroup *gzgroup, found = true; { - const float dist_points[2] = { - len_squared_v2v2(co_ss[0], mval), - len_squared_v2v2(co_ss[2], mval), + const float2 dist_points = { + blender::math::distance_squared(co_ss[0], mval), + blender::math::distance_squared(co_ss[2], mval), }; if (min_ff(UNPACK2(dist_points)) < RULER_PICK_DIST_SQ) { co_index_best = (dist_points[0] < dist_points[1]) ? 0 : 2; @@ -316,9 +325,13 @@ static void ruler_state_set(RulerInfo *ruler_info, int state) ruler_info->state = state; } -static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3], const int xy[2]) +static void view3d_ruler_item_project(RulerInfo *ruler_info, float3 &r_co, const int xy[2]) { - ED_view3d_win_to_3d_int(ruler_info->area->spacedata.first, ruler_info->region, r_co, xy, r_co); + ED_view3d_win_to_3d_int(static_cast(ruler_info->area->spacedata.first), + ruler_info->region, + r_co, + xy, + r_co); } /** @@ -333,81 +346,77 @@ static bool view3d_ruler_item_mousemove(const bContext *C, const bool do_snap) { wmGizmo *snap_gizmo = ruler_info->snap_data.gizmo; - const float eps_bias = 0.0002f; + constexpr float eps_bias = 0.0002f; float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */ if (ruler_item) { - RulerInteraction *inter = ruler_item->gz.interaction_data; - float *co = ruler_item->co[inter->co_index]; + RulerInteraction *inter = static_cast(ruler_item->gz.interaction_data); + float3 &co = ruler_item->co[inter->co_index]; /* restore the initial depth */ - copy_v3_v3(co, inter->drag_start_co); + co = inter->drag_start_co; view3d_ruler_item_project(ruler_info, co, mval); if (do_thickness && inter->co_index != 1) { Scene *scene = DEG_get_input_scene(depsgraph); - View3D *v3d = ruler_info->area->spacedata.first; + View3D *v3d = static_cast(ruler_info->area->spacedata.first); SnapObjectContext *snap_context = ED_gizmotypes_snap_3d_context_ensure(scene, snap_gizmo); - const float mval_fl[2] = {UNPACK2(mval)}; - float ray_normal[3]; - float ray_start[3]; - float *co_other; + const float2 mval_fl = {float(mval[0]), float(mval[1])}; + float3 ray_normal; + float3 ray_start; + float3 &co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0]; - co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0]; + SnapObjectParams snap_object_params{}; + snap_object_params.snap_target_select = SCE_SNAP_TARGET_ALL; + snap_object_params.edit_mode_type = SNAP_GEOM_CAGE; - if (ED_transform_snap_object_project_view3d(snap_context, - depsgraph, - ruler_info->region, - v3d, - SCE_SNAP_MODE_FACE_RAYCAST, - &(const struct SnapObjectParams){ - .snap_target_select = SCE_SNAP_TARGET_ALL, - .edit_mode_type = SNAP_GEOM_CAGE, - }, - NULL, - mval_fl, - NULL, - &dist_px, - co, - ray_normal)) { - negate_v3(ray_normal); + eSnapMode hit = ED_transform_snap_object_project_view3d(snap_context, + depsgraph, + ruler_info->region, + v3d, + SCE_SNAP_MODE_FACE_RAYCAST, + &snap_object_params, + nullptr, + mval_fl, + nullptr, + &dist_px, + co, + ray_normal); + if (hit) { /* add some bias */ - madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias); + ray_start = co - ray_normal * eps_bias; ED_transform_snap_object_project_ray(snap_context, depsgraph, v3d, - &(const struct SnapObjectParams){ - .snap_target_select = SCE_SNAP_TARGET_ALL, - .edit_mode_type = SNAP_GEOM_CAGE, - }, + &snap_object_params, ray_start, - ray_normal, - NULL, + -ray_normal, + nullptr, co_other, - NULL); + nullptr); } } else { - View3D *v3d = ruler_info->area->spacedata.first; + View3D *v3d = static_cast(ruler_info->area->spacedata.first); if (do_snap) { - float *prev_point = NULL; + float3 *prev_point = nullptr; BLI_assert(ED_gizmotypes_snap_3d_is_enabled(snap_gizmo)); if (inter->co_index != 1) { if (ruler_item->flag & RULERITEM_USE_ANGLE) { - prev_point = ruler_item->co[1]; + prev_point = &ruler_item->co[1]; } else if (inter->co_index == 0) { - prev_point = ruler_item->co[2]; + prev_point = &ruler_item->co[2]; } else { - prev_point = ruler_item->co[0]; + prev_point = &ruler_item->co[0]; } } - if (prev_point != NULL) { + if (prev_point != nullptr) { RNA_property_float_set_array( - snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); + snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, *prev_point); } - ED_gizmotypes_snap_3d_data_get(C, snap_gizmo, co, NULL, NULL, NULL); + ED_gizmotypes_snap_3d_data_get(C, snap_gizmo, co, nullptr, nullptr, nullptr); } #ifdef USE_AXIS_CONSTRAINTS @@ -416,7 +425,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C, Scene *scene = DEG_get_input_scene(depsgraph); ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); - RegionView3D *rv3d = ruler_info->region->regiondata; + RegionView3D *rv3d = static_cast(ruler_info->region->regiondata); BKE_view_layer_synced_ensure(scene, view_layer); Object *ob = BKE_view_layer_active_object_get(view_layer); Object *obedit = OBEDIT_FROM_OBACT(ob); @@ -429,13 +438,12 @@ static bool view3d_ruler_item_mousemove(const bContext *C, } const int pivot_point = scene->toolsettings->transform_pivot_point; - float mat[3][3]; + float3x3 mat; ED_transform_calc_orientation_from_type_ex( - scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, mat); + scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, mat.ptr()); - invert_m3(mat); - mul_m3_m3_pre(ruler_item->co, mat); + ruler_item->co = blender::math::invert(mat) * ruler_item->co; /* Loop through the axes and constrain the dragged point to the current constrained axis. */ @@ -444,8 +452,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C, ruler_item->co[inter->co_index][i] = ruler_item->co[(inter->co_index == 0) ? 2 : 0][i]; } } - invert_m3(mat); - mul_m3_m3_pre(ruler_item->co, mat); + ruler_item->co = mat * ruler_item->co; } #endif } @@ -464,7 +471,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C, */ static bool gizmo_ruler_check_for_operator(const wmGizmoGroup *gzgroup) { - return gzgroup->customdata != NULL; + return gzgroup->customdata != nullptr; } /** \} */ @@ -481,13 +488,13 @@ static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd) return gpl; } } - return NULL; + return nullptr; } static RulerItem *gzgroup_ruler_item_first_get(wmGizmoGroup *gzgroup) { #ifndef NDEBUG - RulerInfo *ruler_info = gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); BLI_assert(gzgroup->gizmos.first == ruler_info->snap_data.gizmo); #endif return (RulerItem *)((wmGizmo *)gzgroup->gizmos.first)->next; @@ -508,13 +515,13 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) const char *ruler_name = RULER_ID; bool changed = false; - if (scene->gpd == NULL) { + if (scene->gpd == nullptr) { scene->gpd = BKE_gpencil_data_addnew(bmain, "Annotations"); } gpd = scene->gpd; gpl = view3d_ruler_layer_get(gpd); - if (gpl == NULL) { + if (gpl == nullptr) { gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false, false); copy_v4_v4(gpl->color, U.gpencil_new_layer_col); gpl->thickness = 1; @@ -530,10 +537,11 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) int j; /* allocate memory for a new stroke */ - gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); + gps = (bGPDstroke *)MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); if (ruler_item->flag & RULERITEM_USE_ANGLE) { gps->totpoints = 3; - pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + pt = gps->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, + "gp_stroke_points"); for (j = 0; j < 3; j++) { copy_v3_v3(&pt->x, ruler_item->co[j]); pt->pressure = 1.0f; @@ -543,7 +551,8 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) } else { gps->totpoints = 2; - pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + pt = gps->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, + "gp_stroke_points"); for (j = 0; j < 3; j += 2) { copy_v3_v3(&pt->x, ruler_item->co[j]); pt->pressure = 1.0f; @@ -578,10 +587,10 @@ static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup) gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV); if (gpf) { bGPDstroke *gps; - for (gps = gpf->strokes.first; gps; gps = gps->next) { + for (gps = static_cast(gpf->strokes.first); gps; gps = gps->next) { bGPDspoint *pt = gps->points; int j; - RulerItem *ruler_item = NULL; + RulerItem *ruler_item = nullptr; if (gps->totpoints == 3) { ruler_item = ruler_item_add(gzgroup); for (j = 0; j < 3; j++) { @@ -617,20 +626,19 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) { Scene *scene = CTX_data_scene(C); UnitSettings *unit = &scene->unit; - RulerInfo *ruler_info = gz->parent_gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gz->parent_gzgroup->customdata); RulerItem *ruler_item = (RulerItem *)gz; ARegion *region = ruler_info->region; - RegionView3D *rv3d = region->regiondata; + RegionView3D *rv3d = static_cast(region->regiondata); const float cap_size = 4.0f * UI_SCALE_FAC; const float bg_margin = 4.0f * UI_SCALE_FAC; const float arc_size = 64.0f * UI_SCALE_FAC; -#define ARC_STEPS 24 - const int arc_steps = ARC_STEPS; - const float color_act[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - const float color_base[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + constexpr int arc_steps = 24; + const float4 color_act = {1.0f, 1.0f, 1.0f, 1.0f}; + const float4 color_base = {0.0f, 0.0f, 0.0f, 1.0f}; uchar color_text[3]; uchar color_wire[3]; - float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f}; + float4 color_back = {1.0f, 1.0f, 1.0f, 0.5f}; /* Pixel Space. */ GPU_matrix_push_projection(); @@ -650,13 +658,13 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) UI_GetThemeColor3ubv(TH_WIRE, color_wire); /* Avoid white on white text. (TODO: Fix by using theme). */ - if ((int)color_text[0] + (int)color_text[1] + (int)color_text[2] > 127 * 3 * 0.6f) { + if (int(color_text[0]) + int(color_text[1]) + int(color_text[2]) > 127 * 3 * 0.6f) { copy_v3_fl(color_back, 0.0f); } const bool is_act = (ruler_info->item_active == ruler_item); - float dir_ruler[2]; - float co_ss[3][2]; + float2 dir_ruler; + float3x2 co_ss; bool proj_ok[3]; int j; @@ -682,14 +690,14 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) if (ruler_item->flag & RULERITEM_USE_ANGLE) { immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); - float viewport_size[4]; + float4 viewport_size(0.0f); GPU_viewport_size_get_f(viewport_size); immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); immUniform1i("colors_len", 2); /* "advanced" mode */ - const float *col = is_act ? color_act : color_base; + const float4 &col = is_act ? color_act : color_base; immUniform4f("color", 0.67f, 0.67f, 0.67f, 1.0f); - immUniform4f("color2", col[0], col[1], col[2], col[3]); + immUniform4fv("color2", col); immUniform1f("dash_width", 6.0f); immUniform1f("udash_factor", 0.5f); @@ -707,37 +715,34 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) /* arc */ { - float dir_tmp[3]; - float ar_coord[3]; + float3 dir_tmp; + float3 ar_coord; - float dir_a[3]; - float dir_b[3]; - float quat[4]; - float axis[3]; + float3 dir_a; + float3 dir_b; + float4 quat; + float3 axis; float angle; const float px_scale = (ED_view3d_pixel_size_no_ui_scale(rv3d, ruler_item->co[1]) * min_fff(arc_size, - len_v2v2(co_ss[0], co_ss[1]) / 2.0f, - len_v2v2(co_ss[2], co_ss[1]) / 2.0f)); + blender::math::distance(co_ss[0], co_ss[1]) / 2.0f, + blender::math::distance(co_ss[2], co_ss[1]) / 2.0f)); - sub_v3_v3v3(dir_a, ruler_item->co[0], ruler_item->co[1]); - sub_v3_v3v3(dir_b, ruler_item->co[2], ruler_item->co[1]); - normalize_v3(dir_a); - normalize_v3(dir_b); - - cross_v3_v3v3(axis, dir_a, dir_b); + dir_a = blender::math::normalize(ruler_item->co[0] - ruler_item->co[1]); + dir_b = blender::math::normalize(ruler_item->co[2] - ruler_item->co[1]); + axis = blender::math::cross(dir_a, dir_b); angle = angle_normalized_v3v3(dir_a, dir_b); axis_angle_to_quat(quat, axis, angle / arc_steps); - copy_v3_v3(dir_tmp, dir_a); + dir_tmp = dir_a; immUniformColor3ubv(color_wire); immBegin(GPU_PRIM_LINE_STRIP, arc_steps + 1); for (j = 0; j <= arc_steps; j++) { - madd_v3_v3v3fl(ar_coord, ruler_item->co[1], dir_tmp, px_scale); + ar_coord = ruler_item->co[1] + dir_tmp * px_scale; mul_qt_v3(quat, dir_tmp); immVertex3fv(shdr_pos_3d, ar_coord); @@ -758,7 +763,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immUniform1i("colors_len", 2); /* "advanced" mode */ const float *col = is_act ? color_act : color_base; immUniform4f("color", 0.67f, 0.67f, 0.67f, 1.0f); - immUniform4f("color2", col[0], col[1], col[2], col[3]); + immUniform4fv("color2", col); immUniform1f("dash_width", 6.0f); immUniform1f("udash_factor", 0.5f); @@ -784,19 +789,13 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); /* capping */ { - float rot_90_vec_a[2]; - float rot_90_vec_b[2]; - float cap[2]; + float2 cap; - sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]); - rot_90_vec_a[0] = -dir_ruler[1]; - rot_90_vec_a[1] = dir_ruler[0]; - normalize_v2(rot_90_vec_a); + dir_ruler = co_ss[0] - co_ss[1]; + float2 rot_90_vec_a = blender::math::normalize(float2{-dir_ruler[1], dir_ruler[0]}); - sub_v2_v2v2(dir_ruler, co_ss[1], co_ss[2]); - rot_90_vec_b[0] = -dir_ruler[1]; - rot_90_vec_b[1] = dir_ruler[0]; - normalize_v2(rot_90_vec_b); + dir_ruler = co_ss[1] - co_ss[2]; + float2 rot_90_vec_b = blender::math::normalize(float2{-dir_ruler[1], dir_ruler[0]}); GPU_blend(GPU_BLEND_ALPHA); @@ -820,16 +819,16 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2 + proj_ok[1] * 4); if (proj_ok[0]) { - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size); + cap = co_ss[0] + rot_90_vec_a * cap_size; immVertex2fv(shdr_pos_2d, cap); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size); + cap = co_ss[0] - rot_90_vec_a * cap_size; immVertex2fv(shdr_pos_2d, cap); } if (proj_ok[2]) { - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size); + cap = co_ss[2] + rot_90_vec_b * cap_size; immVertex2fv(shdr_pos_2d, cap); - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size); + cap = co_ss[2] - rot_90_vec_b * cap_size; immVertex2fv(shdr_pos_2d, cap); } @@ -849,7 +848,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) /* text */ char numstr[256]; - float numstr_size[2]; + float2 numstr_size; float posit[2]; const int prec = 2; /* XXX, todo, make optional */ @@ -885,14 +884,12 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) else { immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]); + dir_ruler = co_ss[0] - co_ss[2]; /* capping */ { - float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]}; - float cap[2]; - - normalize_v2(rot_90_vec); + float2 rot_90_vec = blender::math::normalize(float2{-dir_ruler[1], dir_ruler[0]}); + float2 cap; GPU_blend(GPU_BLEND_ALPHA); @@ -902,16 +899,16 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2); if (proj_ok[0]) { - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size); + cap = co_ss[0] + rot_90_vec * cap_size; immVertex2fv(shdr_pos_2d, cap); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size); + cap = co_ss[0] - rot_90_vec * cap_size; immVertex2fv(shdr_pos_2d, cap); } if (proj_ok[2]) { - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size); + cap = co_ss[2] + rot_90_vec * cap_size; immVertex2fv(shdr_pos_2d, cap); - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size); + cap = co_ss[2] - rot_90_vec * cap_size; immVertex2fv(shdr_pos_2d, cap); } @@ -923,19 +920,18 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) /* text */ char numstr[256]; - float numstr_size[2]; + float2 numstr_size; const int prec = 6; /* XXX, todo, make optional */ - float posit[2]; + float2 posit; ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); - mid_v2_v2v2(posit, co_ss[0], co_ss[2]); + posit = (co_ss[0] + co_ss[2]) / 2.0f; /* center text */ - posit[0] -= numstr_size[0] / 2.0f; - posit[1] -= numstr_size[1] / 2.0f; + posit -= numstr_size / 2.0f; /* draw text (bg) */ if (proj_ok[0] && proj_ok[2]) { @@ -965,14 +961,12 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) GPU_matrix_pop(); GPU_matrix_pop_projection(); - -#undef ARC_STEPS } -static int gizmo_ruler_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2]) +static int gizmo_ruler_test_select(bContext *, wmGizmo *gz, const int mval[2]) { RulerItem *ruler_item_pick = (RulerItem *)gz; - const float mval_fl[2] = {UNPACK2(mval)}; + const float mval_fl[2] = {float(mval[0]), float(mval[1])}; int co_index; /* select and drag */ @@ -996,7 +990,7 @@ static int gizmo_ruler_modal(bContext *C, { bool do_draw = false; int exit_code = OPERATOR_RUNNING_MODAL; - RulerInfo *ruler_info = gz->parent_gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gz->parent_gzgroup->customdata); RulerItem *ruler_item = (RulerItem *)gz; ARegion *region = CTX_wm_region(C); bool do_cursor_update = (event->val == KM_RELEASE) || (event->type == MOUSEMOVE); @@ -1036,7 +1030,8 @@ static int gizmo_ruler_modal(bContext *C, const bool do_snap = !(tweak_flag & WM_GIZMO_TWEAK_SNAP); #else /* Ensure snap is up to date. */ - ED_gizmotypes_snap_3d_data_get(C, ruler_info->snap_data.gizmo, NULL, NULL, NULL, NULL); + ED_gizmotypes_snap_3d_data_get( + C, ruler_info->snap_data.gizmo, nullptr, nullptr, nullptr, nullptr); const bool do_snap = ED_gizmotypes_snap_3d_is_enabled(ruler_info->snap_data.gizmo); #endif @@ -1066,9 +1061,9 @@ static int gizmo_ruler_modal(bContext *C, static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) { wmGizmoGroup *gzgroup = gz->parent_gzgroup; - RulerInfo *ruler_info = gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); RulerItem *ruler_item_pick = (RulerItem *)gz; - RulerInteraction *inter = MEM_callocN(sizeof(RulerInteraction), __func__); + RulerInteraction *inter = (RulerInteraction *)MEM_callocN(sizeof(RulerInteraction), __func__); gz->interaction_data = inter; ARegion *region = ruler_info->region; @@ -1091,7 +1086,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) /* find the factor */ { - float co_ss[2][2]; + float2x2 co_ss; float fac; ED_view3d_project_float_global( @@ -1102,8 +1097,8 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) fac = line_point_factor_v2(mval_fl, co_ss[0], co_ss[1]); CLAMP(fac, 0.0f, 1.0f); - interp_v3_v3v3( - ruler_item_pick->co[1], ruler_item_pick->co[0], ruler_item_pick->co[2], fac); + ruler_item_pick->co[1] = blender::math::interpolate( + ruler_item_pick->co[0], ruler_item_pick->co[2], fac); } /* update the new location */ @@ -1117,7 +1112,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) ruler_state_set(ruler_info, RULER_STATE_DRAG); /* store the initial depth */ - copy_v3_v3(inter->drag_start_co, ruler_item_pick->co[inter->co_index]); + inter->drag_start_co = ruler_item_pick->co[inter->co_index]; } if (inter->co_index == 1) { @@ -1129,20 +1124,20 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) { /* Set Snap prev point. */ - float *prev_point; + float3 *prev_point; if (ruler_item_pick->flag & RULERITEM_USE_ANGLE) { - prev_point = (inter->co_index != 1) ? ruler_item_pick->co[1] : NULL; + prev_point = (inter->co_index != 1) ? &ruler_item_pick->co[1] : nullptr; } else if (inter->co_index == 0) { - prev_point = ruler_item_pick->co[2]; + prev_point = &ruler_item_pick->co[2]; } else { - prev_point = ruler_item_pick->co[0]; + prev_point = &ruler_item_pick->co[0]; } if (prev_point) { RNA_property_float_set_array( - ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); + ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, *prev_point); } else { RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint); @@ -1157,7 +1152,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel) { wmGizmoGroup *gzgroup = gz->parent_gzgroup; - RulerInfo *ruler_info = gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); if (!cancel) { if (ruler_info->state == RULER_STATE_DRAG) { @@ -1205,21 +1200,21 @@ void VIEW3D_GT_ruler_item(wmGizmoType *gzt) static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup) { - RulerInfo *ruler_info = MEM_callocN(sizeof(RulerInfo), __func__); + RulerInfo *ruler_info = (RulerInfo *)MEM_callocN(sizeof(RulerInfo), __func__); wmGizmo *gizmo; { /* The gizmo snap has to be the first gizmo. */ const wmGizmoType *gzt_snap; gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true); - gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL); + gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, nullptr); RNA_enum_set(gizmo->ptr, "snap_elements_force", SCE_SNAP_MODE_GEOM); ED_gizmotypes_snap_3d_flag_set(gizmo, V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE); - WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); + WM_gizmo_set_color(gizmo, blender::float4(1.0f)); wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_ruler_add", true); - WM_gizmo_operator_set(gizmo, 0, ot, NULL); + WM_gizmo_operator_set(gizmo, 0, ot, nullptr); } if (view3d_ruler_from_gpencil(C, gzgroup)) { @@ -1264,8 +1259,8 @@ void VIEW3D_GGT_ruler(wmGizmoGroupType *gzgt) static bool view3d_ruler_poll(bContext *C) { bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); - if ((tref_rt == NULL) || !STREQ(view3d_gzgt_ruler_id, tref_rt->gizmo_group) || - CTX_wm_region_view3d(C) == NULL) { + if ((tref_rt == nullptr) || !STREQ(view3d_gzgt_ruler_id, tref_rt->gizmo_group) || + CTX_wm_region_view3d(C) == nullptr) { return false; } return true; @@ -1298,10 +1293,10 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e /* This is a little weak, but there is no real good way to tweak directly. */ WM_gizmo_highlight_set(gzmap, &ruler_item->gz); if (WM_operator_name_call( - C, "GIZMOGROUP_OT_gizmo_tweak", WM_OP_INVOKE_REGION_WIN, NULL, event) == + C, "GIZMOGROUP_OT_gizmo_tweak", WM_OP_INVOKE_REGION_WIN, nullptr, event) == OPERATOR_RUNNING_MODAL) { - RulerInfo *ruler_info = gzgroup->customdata; - RulerInteraction *inter = ruler_item->gz.interaction_data; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); + RulerInteraction *inter = static_cast(ruler_item->gz.interaction_data); struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); inter->co_index = 0; @@ -1344,7 +1339,7 @@ void VIEW3D_OT_ruler_add(wmOperatorType *ot) /** \name Remove Ruler Operator * \{ */ -static int view3d_ruler_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int view3d_ruler_remove_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) { ARegion *region = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); @@ -1360,7 +1355,7 @@ static int view3d_ruler_remove_invoke(bContext *C, wmOperator *op, const wmEvent if (!gizmo_ruler_check_for_operator(gzgroup)) { return OPERATOR_CANCELLED; } - RulerInfo *ruler_info = gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); if (ruler_info->item_active) { RulerItem *ruler_item = ruler_info->item_active; if ((ruler_item->flag & RULERITEM_USE_ANGLE) && diff --git a/source/blender/editors/transform/transform_gizmo_3d.cc b/source/blender/editors/transform/transform_gizmo_3d.cc index e61990732ee..594b55992ad 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.cc +++ b/source/blender/editors/transform/transform_gizmo_3d.cc @@ -1464,7 +1464,7 @@ static void gizmo_3d_setup_draw_modal(wmGizmo *axis, const int axis_idx, const i case MAN_AXIS_SCALE_Z: { float end, start_co[3] = {0.0f, 0.0f, 0.0f}; - gizmo_line_range(twtype, axis_type, NULL, &end); + gizmo_line_range(twtype, axis_type, nullptr, &end); RNA_float_set(axis->ptr, "length", end); RNA_enum_set(axis->ptr, "draw_options", @@ -1797,7 +1797,7 @@ static void gizmo_refresh_from_matrix(wmGizmo *axis, copy_m4_m4(axis->matrix_basis, twmat); if (scale) { float end; - gizmo_line_range(twtype, axis_type, NULL, &end); + gizmo_line_range(twtype, axis_type, nullptr, &end); RNA_float_set(axis->ptr, "length", end * scale[aidx_norm]); } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index f1e83c5090c..64bd87cbf79 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -580,6 +580,33 @@ void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3 scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, r_mat); } +static void handle_armature_parent_orientation(Object *ob, float r_mat[3][3]) +{ + bPoseChannel *active_pchan = BKE_pose_channel_active(ob, false); + + /* Check if target bone is a child. */ + if (active_pchan->parent) { + /* For child, show parent local regardless if "local location" is set for parent bone. */ + transform_orientations_create_from_axis(r_mat, UNPACK3(active_pchan->parent->pose_mat)); + return; + } + + /* For root, use local transform of armature object. */ + transform_orientations_create_from_axis(r_mat, UNPACK3(ob->object_to_world)); +} + +static void handle_object_parent_orientation(Object *ob, float r_mat[3][3]) +{ + /* If object has parent, then orient to parent. */ + if (ob->parent) { + transform_orientations_create_from_axis(r_mat, UNPACK3(ob->parent->object_to_world)); + } + else { + /* If object doesn't have parent, then orient to world. */ + unit_m3(r_mat); + } +} + short ED_transform_calc_orientation_from_type_ex(const Scene *scene, ViewLayer *view_layer, const View3D *v3d, @@ -609,6 +636,20 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene, /* If not gimbal, fall through to normal. */ ATTR_FALLTHROUGH; } + case V3D_ORIENT_PARENT: { + if (ob) { + if (ob->mode & OB_MODE_POSE) { + handle_armature_parent_orientation(ob, r_mat); + break; + } + else { + handle_object_parent_orientation(ob, r_mat); + break; + } + } + /* No break; we define 'parent' as 'normal' otherwise. */ + ATTR_FALLTHROUGH; + } case V3D_ORIENT_NORMAL: { if (obedit || (ob && ob->mode & OB_MODE_POSE)) { ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat); @@ -621,7 +662,7 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene, if (ob) { if (ob->mode & OB_MODE_POSE) { /* Each bone moves on its own local axis, but to avoid confusion, - * use the active pones axis for display #33575, this works as expected on a single + * use the active bone's axis for display #33575, this works as expected on a single * bone and users who select many bones will understand what's going on and what local * means when they start transforming. */ ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat); @@ -741,6 +782,8 @@ const char *transform_orientations_spacename_get(TransInfo *t, const short orien return TIP_("view"); case V3D_ORIENT_CURSOR: return TIP_("cursor"); + case V3D_ORIENT_PARENT: + return TIP_("parent"); case V3D_ORIENT_CUSTOM_MATRIX: return TIP_("custom"); case V3D_ORIENT_CUSTOM: diff --git a/source/blender/editors/undo/memfile_undo.cc b/source/blender/editors/undo/memfile_undo.cc index 33f75b00a7c..0df00e5050e 100644 --- a/source/blender/editors/undo/memfile_undo.cc +++ b/source/blender/editors/undo/memfile_undo.cc @@ -243,9 +243,9 @@ static void memfile_undosys_step_decode(struct bContext *C, * modified IDs should already have other depsgraph update tags anyway. * However, for the sake of consistency, it's better to effectively use it, * since content of that ID pointer does have been modified. */ - unsigned int recalc_flags = id->recalc | ((id->tag & LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE) ? - ID_RECALC_COPY_ON_WRITE : - IDRecalcFlag(0)); + uint recalc_flags = id->recalc | ((id->tag & LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE) ? + ID_RECALC_COPY_ON_WRITE : + IDRecalcFlag(0)); /* Tag depsgraph to update data-block for changes that happened between the * current and the target state, see direct_link_id_restore_recalc(). */ if (recalc_flags != 0) { diff --git a/source/blender/geometry/GEO_mesh_to_curve.hh b/source/blender/geometry/GEO_mesh_to_curve.hh index 17eb311ccc2..d52246db724 100644 --- a/source/blender/geometry/GEO_mesh_to_curve.hh +++ b/source/blender/geometry/GEO_mesh_to_curve.hh @@ -25,7 +25,7 @@ bke::CurvesGeometry mesh_to_curve_convert( const bke::AnonymousAttributePropagationInfo &propagation_info); bke::CurvesGeometry create_curve_from_vert_indices( - const Mesh &mesh, + const bke::AttributeAccessor &mesh_attributes, Span vert_indices, Span curve_offsets, IndexRange cyclic_curves, diff --git a/source/blender/geometry/intern/mesh_merge_by_distance.cc b/source/blender/geometry/intern/mesh_merge_by_distance.cc index 53b57289f0d..ba869b10e9b 100644 --- a/source/blender/geometry/intern/mesh_merge_by_distance.cc +++ b/source/blender/geometry/intern/mesh_merge_by_distance.cc @@ -1544,7 +1544,7 @@ static Mesh *create_merged_mesh(const Mesh &mesh, const int result_npolys = src_polys.size() - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len; Mesh *result = BKE_mesh_new_nomain_from_template( - &mesh, result_nverts, result_nedges, result_nloops, result_npolys); + &mesh, result_nverts, result_nedges, result_npolys, result_nloops); MutableSpan dst_edges = result->edges_for_write(); MutableSpan dst_poly_offsets = result->poly_offsets_for_write(); MutableSpan dst_corner_verts = result->corner_verts_for_write(); diff --git a/source/blender/geometry/intern/mesh_primitive_cuboid.cc b/source/blender/geometry/intern/mesh_primitive_cuboid.cc index fe1d466dcc3..a07c8a7268f 100644 --- a/source/blender/geometry/intern/mesh_primitive_cuboid.cc +++ b/source/blender/geometry/intern/mesh_primitive_cuboid.cc @@ -400,7 +400,7 @@ Mesh *create_cuboid_mesh(const float3 &size, { const CuboidConfig config(size, verts_x, verts_y, verts_z); - Mesh *mesh = BKE_mesh_new_nomain(config.vertex_count, 0, config.loop_count, config.poly_count); + Mesh *mesh = BKE_mesh_new_nomain(config.vertex_count, 0, config.poly_count, config.loop_count); MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); MutableSpan corner_verts = mesh->corner_verts_for_write(); diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index 14dfcc5bacb..a68e0489494 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -19,7 +19,7 @@ namespace blender::geometry { bke::CurvesGeometry create_curve_from_vert_indices( - const Mesh &mesh, + const bke::AttributeAccessor &mesh_attributes, const Span vert_indices, const Span curve_offsets, const IndexRange cyclic_curves, @@ -30,7 +30,6 @@ bke::CurvesGeometry create_curve_from_vert_indices( curves.offsets_for_write().last() = vert_indices.size(); curves.fill_curve_types(CURVE_TYPE_POLY); - const bke::AttributeAccessor mesh_attributes = mesh.attributes(); bke::MutableAttributeAccessor curves_attributes = curves.attributes_for_write(); if (!cyclic_curves.is_empty()) { @@ -82,7 +81,7 @@ struct CurveFromEdgesOutput { }; static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num, - Span> edges) + const Span edges) { Vector vert_indices; vert_indices.reserve(edges.size()); @@ -90,9 +89,9 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num, /* Compute the number of edges connecting to each vertex. */ Array neighbor_count(verts_num, 0); - for (const std::pair &edge : edges) { - neighbor_count[edge.first]++; - neighbor_count[edge.second]++; + for (const int2 &edge : edges) { + neighbor_count[edge[0]]++; + neighbor_count[edge[1]]++; } /* Compute an offset into the array of neighbor edges based on the counts. */ @@ -108,8 +107,8 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num, /* Calculate the indices of each vertex's neighboring edges. */ Array neighbors(edges.size() * 2); for (const int i : edges.index_range()) { - const int v1 = edges[i].first; - const int v2 = edges[i].second; + const int v1 = edges[i][0]; + const int v2 = edges[i][1]; neighbors[neighbor_offsets[v1] + used_slots[v1]] = v2; neighbors[neighbor_offsets[v2] + used_slots[v2]] = v1; used_slots[v1]++; @@ -199,19 +198,17 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num, return {std::move(vert_indices), std::move(curve_offsets), cyclic_curves}; } -/** - * Get a separate array of the indices for edges in a selection (a boolean attribute). - * This helps to make the above algorithm simpler by removing the need to check for selection - * in many places. - */ -static Vector> get_selected_edges(const Mesh &mesh, const IndexMask selection) +static bke::CurvesGeometry edges_to_curves_convert( + const Mesh &mesh, + const Span edges, + const bke::AnonymousAttributePropagationInfo &propagation_info) { - Vector> selected_edges; - const Span edges = mesh.edges(); - for (const int i : selection) { - selected_edges.append({edges[i][0], edges[i][1]}); - } - return selected_edges; + CurveFromEdgesOutput output = edges_to_curve_point_indices(mesh.totvert, edges); + return create_curve_from_vert_indices(mesh.attributes(), + output.vert_indices, + output.curve_offsets, + output.cyclic_curves, + propagation_info); } bke::CurvesGeometry mesh_to_curve_convert( @@ -219,11 +216,13 @@ bke::CurvesGeometry mesh_to_curve_convert( const IndexMask selection, const bke::AnonymousAttributePropagationInfo &propagation_info) { - Vector> selected_edges = get_selected_edges(mesh, selection); - CurveFromEdgesOutput output = edges_to_curve_point_indices(mesh.totvert, selected_edges); - - return create_curve_from_vert_indices( - mesh, output.vert_indices, output.curve_offsets, output.cyclic_curves, propagation_info); + const Span edges = mesh.edges(); + if (selection.size() == edges.size()) { + return edges_to_curves_convert(mesh, edges, propagation_info); + } + Array selected_edges(selection.size()); + array_utils::gather(edges, selection, selected_edges.as_mutable_span()); + return edges_to_curves_convert(mesh, selected_edges, propagation_info); } } // namespace blender::geometry diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 30324dbdab1..9bf0823aa35 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -939,8 +939,8 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set, mesh_info.stored_vertex_ids = ids_attribute.varray.get_internal_span().typed(); } } - mesh_info.material_indices =* - attributes.lookup_or_default("material_index", ATTR_DOMAIN_FACE, 0); + mesh_info.material_indices = *attributes.lookup_or_default( + "material_index", ATTR_DOMAIN_FACE, 0); } info.no_loose_edges_hint = std::all_of( @@ -1081,7 +1081,7 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, const int tot_loops = last_task.start_indices.loop + last_mesh.totloop; const int tot_poly = last_task.start_indices.poly + last_mesh.totpoly; - Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, tot_loops, tot_poly); + Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, tot_poly, tot_loops); MeshComponent &dst_component = r_realized_geometry.get_component_for_write(); dst_component.replace(dst_mesh); bke::MutableAttributeAccessor dst_attributes = dst_mesh->attributes_for_write(); diff --git a/source/blender/geometry/intern/uv_pack.cc b/source/blender/geometry/intern/uv_pack.cc index 1e56a4acce4..22ab4473734 100644 --- a/source/blender/geometry/intern/uv_pack.cc +++ b/source/blender/geometry/intern/uv_pack.cc @@ -198,7 +198,7 @@ void PackIsland::calculate_pre_rotation_(const UVPackIsland_Params ¶ms) } const float(*source)[2] = reinterpret_cast(coords.data()); - float angle = -BLI_convexhull_aabb_fit_points_2d(source, (int)coords.size()); + float angle = -BLI_convexhull_aabb_fit_points_2d(source, int(coords.size())); if (1) { /* "Stand-up" islands. */ diff --git a/source/blender/gpu/metal/mtl_query.mm b/source/blender/gpu/metal/mtl_query.mm index f2c05ce9afd..897f9cb202e 100644 --- a/source/blender/gpu/metal/mtl_query.mm +++ b/source/blender/gpu/metal/mtl_query.mm @@ -33,6 +33,11 @@ void MTLQueryPool::allocate() gpu::MTLBuffer *buffer = MTLContext::get_global_memory_manager()->allocate(buffer_size_in_bytes, true); BLI_assert(buffer); + + /* We must zero-initialize the query buffer as visibility queries with no draws between + * begin and end will not write any result to the buffer. */ + memset(buffer->get_host_ptr(), 0, buffer_size_in_bytes); + buffer->flush(); buffer_.append(buffer); } diff --git a/source/blender/gpu/shaders/metal/mtl_shader_defines.msl b/source/blender/gpu/shaders/metal/mtl_shader_defines.msl index a192e51a0ec..dfb74a3e76b 100644 --- a/source/blender/gpu/shaders/metal/mtl_shader_defines.msl +++ b/source/blender/gpu/shaders/metal/mtl_shader_defines.msl @@ -101,10 +101,18 @@ struct constexp_uvec3 { return 0; } } - inline operator uint3() const + constexpr inline operator uint3() const { return xyz; } + constexpr inline operator uint2() const + { + return xy; + } + constexpr inline operator uint() const + { + return x; + } }; constexpr constexp_uvec3 __internal_workgroupsize_get() @@ -140,6 +148,10 @@ template T atomicSub(threadgroup T &mem, T data) { return atomic_fetch_sub_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); } +template T atomicAnd(threadgroup T &mem, T data) +{ + return atomic_fetch_and_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); +} template T atomicOr(threadgroup T &mem, T data) { return atomic_fetch_or_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); @@ -152,29 +164,41 @@ template T atomicXor(threadgroup T &mem, T data) /* Device memory. */ template T atomicMax(device T &mem, T data) { - return atomic_fetch_max_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); + return atomic_fetch_max_explicit((device _atomic *)&mem, data, memory_order_relaxed); } template T atomicMin(device T &mem, T data) { - return atomic_fetch_min_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); + return atomic_fetch_min_explicit((device _atomic *)&mem, data, memory_order_relaxed); } template T atomicAdd(device T &mem, T data) { - return atomic_fetch_add_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); + return atomic_fetch_add_explicit((device _atomic *)&mem, data, memory_order_relaxed); } template T atomicSub(device T &mem, T data) { - return atomic_fetch_sub_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); + return atomic_fetch_sub_explicit((device _atomic *)&mem, data, memory_order_relaxed); +} +template T atomicAnd(device T &mem, T data) +{ + return atomic_fetch_and_explicit((device _atomic *)&mem, data, memory_order_relaxed); } template T atomicOr(device T &mem, T data) { - return atomic_fetch_or_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); + return atomic_fetch_or_explicit((device _atomic *)&mem, data, memory_order_relaxed); } template T atomicXor(device T &mem, T data) { - return atomic_fetch_xor_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); + return atomic_fetch_xor_explicit((device _atomic *)&mem, data, memory_order_relaxed); } +/* Unblock texture atomic compilation. + * TODO(Metal): This is not correct for global atomic behaviour, but will be safe within a single thread. + * We need to re-visit the solution for this use-case and use a 2D texture buffer instead. */ +#define imageAtomicMin(tex, coord, data) \ + uint val = _texelFetch_internal(tex, coord, 0).r;\ + _texture_write_internal(tex, coord, uint4((val < data) ? val : data));\ + tex.texture->fence(); + /* Used to replace 'out' in function parameters with threadlocal reference * shortened to avoid expanding the glsl source string. */ #define THD thread @@ -1126,6 +1150,27 @@ inline float4 uintBitsToFloat(uint4 f) return as_type(f); } +#define bitfieldReverse reverse_bits +#define bitfieldExtract extract_bits +#define bitfieldInsert insert_bits +#define bitCount popcount + +template T findLSB(T x) +{ + /* ctz returns the number of trailing zeroes. To fetch the index of the LSB, we can also use this + * value as index, however need to filter out the case where the input value is zero to match + * GLSL functionality. */ + return (x == T(0)) ? T(-1) : T(ctz(x)); +} + +template T findMSB(T x) +{ + /* clz returns the number of leading zeroes. To fetch the index of the LSB, we can also use this + * value as index when offset by 1. however need to filter out the case where the input value is + * zero to match GLSL functionality. 000000010*/ + return (x == T(0)) ? T(-1) : (clz(T(0)) - clz(x) - T(1)); +} + /* Texture size functions. Add texture types as needed. */ #define imageSize(image) textureSize(image, 0) diff --git a/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl b/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl index f2d972ea574..eb09f580391 100644 --- a/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl +++ b/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl @@ -15,6 +15,12 @@ #define depthCubeArray samplerCubeArray #define depth2DArrayShadow sampler2DArrayShadow +/* Memory scope and pass by reference types. + * NOTE: These are required by Metal, but are not required in all cases by GLSL. */ +#define device +#define threadgroup +#define OUT(type, name, array_len) out type name[array_len] + /* Backend Functions. */ #define select(A, B, mask) mix(A, B, mask) diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h index 005b56ba7b4..d713b978eda 100644 --- a/source/blender/imbuf/intern/IMB_filetype.h +++ b/source/blender/imbuf/intern/IMB_filetype.h @@ -184,7 +184,7 @@ struct ImBuf *imb_load_cineon(const unsigned char *mem, * \{ */ bool imb_is_a_dpx(const unsigned char *buf, size_t size); -bool imb_save_dpx(struct ImBuf *buf, const char *filepath, int flags); +bool imb_save_dpx(struct ImBuf *ibuf, const char *filepath, int flags); struct ImBuf *imb_load_dpx(const unsigned char *mem, size_t size, int flags, diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 155aa4783a0..00baceff4ac 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -560,6 +560,12 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags return false; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + delete file_stream; + printf("OpenEXR-save: UNKNOWN ERROR\n"); + + return false; + } delete file_stream; return true; @@ -636,6 +642,11 @@ static bool imb_save_openexr_float(ImBuf *ibuf, const char *name, const int flag delete file_stream; return false; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + printf("OpenEXR-save: UNKNOWN ERROR\n"); + delete file_stream; + return false; + } delete file_stream; return true; @@ -939,6 +950,15 @@ bool IMB_exr_begin_write(void *handle, data->ofile = nullptr; data->ofile_stream = nullptr; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + std::cerr << "IMB_exr_begin_write: UNKNOWN ERROR" << std::endl; + + delete data->ofile; + delete data->ofile_stream; + + data->ofile = nullptr; + data->ofile_stream = nullptr; + } return (data->ofile != nullptr); } @@ -999,7 +1019,7 @@ void IMB_exrtile_begin_write( data->ofile_stream = new OFileStream(filepath); data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), headers.data(), headers.size()); } - catch (const std::exception &) { + catch (...) { /* Catch-all for edge cases or compiler bugs. */ delete data->mpofile; delete data->ofile_stream; @@ -1024,7 +1044,7 @@ bool IMB_exr_begin_read( data->ifile_stream = new IFileStream(filepath); data->ifile = new MultiPartInputFile(*(data->ifile_stream)); } - catch (const std::exception &) { + catch (...) { /* Catch-all for edge cases or compiler bugs. */ delete data->ifile; delete data->ifile_stream; @@ -1199,6 +1219,9 @@ void IMB_exr_write_channels(void *handle) catch (const std::exception &exc) { std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + std::cerr << "OpenEXR-writePixels: UNKNOWN ERROR" << std::endl; + } /* Free temporary buffers. */ if (rect_half != nullptr) { MEM_freeN(rect_half); @@ -1258,6 +1281,9 @@ void IMB_exrtile_write_channels( catch (const std::exception &exc) { std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + std::cerr << "OpenEXR-writeTile: UNKNOWN ERROR" << std::endl; + } } void IMB_exr_read_channels(void *handle) @@ -1336,6 +1362,10 @@ void IMB_exr_read_channels(void *handle) std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl; break; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + std::cerr << "OpenEXR-readPixels: UNKNOWN ERROR: " << std::endl; + break; + } } } @@ -2150,6 +2180,16 @@ struct ImBuf *imb_load_openexr(const uchar *mem, delete file; delete membuf; + return nullptr; + } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + std::cerr << "OpenEXR-Load: UNKNOWN ERROR" << std::endl; + if (ibuf) { + IMB_freeImBuf(ibuf); + } + delete file; + delete membuf; + return nullptr; } } @@ -2254,6 +2294,12 @@ struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath, delete stream; return nullptr; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + std::cerr << "OpenEXR-Thumbnail: UNKNOWN ERROR" << std::endl; + delete file; + delete stream; + return nullptr; + } return nullptr; } diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index fa8b8ea1c96..4c673260802 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -723,7 +723,7 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, if (topology_changed(existing_mesh, sample_sel)) { new_mesh = BKE_mesh_new_nomain_from_template( - existing_mesh, positions->size(), 0, face_indices->size(), face_counts->size()); + existing_mesh, positions->size(), 0, face_counts->size(), face_indices->size()); settings.read_flag |= MOD_MESHSEQ_READ_ALL; } diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h index eab9ef7cb8f..c10997637e0 100644 --- a/source/blender/io/collada/MeshImporter.h +++ b/source/blender/io/collada/MeshImporter.h @@ -83,7 +83,7 @@ class MeshImporter : public MeshImporterBase { struct Primitive { int poly_index; int *material_indices; - unsigned int totpoly; + uint totpoly; }; typedef std::map> MaterialIdPrimitiveArrayMap; /* crazy name! */ @@ -92,10 +92,7 @@ class MeshImporter : public MeshImporterBase { * A pair/of geom UID and mat UID, one geometry can have several materials. */ std::multimap materials_mapped_to_geom; - bool set_poly_indices(int *poly_verts, - int loop_index, - const unsigned int *indices, - int loop_count); + bool set_poly_indices(int *poly_verts, int loop_index, const uint *indices, int loop_count); void set_face_uv(blender::float2 *mloopuv, UVDataWrapper &uvs, @@ -140,9 +137,7 @@ class MeshImporter : public MeshImporterBase { */ static void mesh_add_edges(Mesh *mesh, int len); - unsigned int get_loose_edge_count(COLLADAFW::Mesh *mesh); - - CustomData create_edge_custom_data(EdgeHash *eh); + uint get_loose_edge_count(COLLADAFW::Mesh *mesh); /** * Return the number of faces by summing up @@ -168,11 +163,11 @@ class MeshImporter : public MeshImporterBase { * So this function MUST be called after read_faces() (see below) */ void read_lines(COLLADAFW::Mesh *mesh, Mesh *me); - unsigned int get_vertex_count(COLLADAFW::Polygons *mp, int index); + uint get_vertex_count(COLLADAFW::Polygons *mp, int index); void get_vector(float v[3], COLLADAFW::MeshVertexData &arr, int i, int stride); - bool is_flat_face(unsigned int *nind, COLLADAFW::MeshVertexData &nor, int count); + bool is_flat_face(uint *nind, COLLADAFW::MeshVertexData &nor, int count); /** * Returns the list of Users of the given Mesh object. diff --git a/source/blender/io/ply/importer/ply_import.cc b/source/blender/io/ply/importer/ply_import.cc index a17aa51bf23..cee1ad6d469 100644 --- a/source/blender/io/ply/importer/ply_import.cc +++ b/source/blender/io/ply/importer/ply_import.cc @@ -203,21 +203,19 @@ void importer_main(Main *bmain, } /* Create mesh and do all prep work. */ - Mesh *mesh = BKE_mesh_add(bmain, ob_name); + Mesh *mesh_in_main = BKE_mesh_add(bmain, ob_name); BKE_view_layer_base_deselect_all(scene, view_layer); LayerCollection *lc = BKE_layer_collection_get_active(view_layer); Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name); - BKE_mesh_assign_object(bmain, obj, mesh); + BKE_mesh_assign_object(bmain, obj, mesh_in_main); BKE_collection_object_add(bmain, lc->collection, obj); BKE_view_layer_synced_ensure(scene, view_layer); Base *base = BKE_view_layer_base_find(view_layer, obj); BKE_view_layer_base_select_and_set_active(view_layer, base); /* Stuff ply data into the mesh. */ - Mesh *temp_val = convert_ply_to_mesh(*data, mesh, import_params); - if (import_params.merge_verts && temp_val != mesh) { - BKE_mesh_nomain_to_mesh(temp_val, mesh, obj); - } + Mesh *mesh = convert_ply_to_mesh(*data, import_params); + BKE_mesh_nomain_to_mesh(mesh, mesh_in_main, obj); /* Object matrix and finishing up. */ float global_scale = import_params.global_scale; diff --git a/source/blender/io/ply/importer/ply_import_mesh.cc b/source/blender/io/ply/importer/ply_import_mesh.cc index bc2b67dbf21..2a3d8df326f 100644 --- a/source/blender/io/ply/importer/ply_import_mesh.cc +++ b/source/blender/io/ply/importer/ply_import_mesh.cc @@ -7,6 +7,7 @@ #include "BKE_attribute.h" #include "BKE_attribute.hh" #include "BKE_customdata.h" +#include "BKE_lib_id.h" #include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" @@ -17,23 +18,18 @@ #include "ply_import_mesh.hh" namespace blender::io::ply { -Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ms) +Mesh *convert_ply_to_mesh(PlyData &data, const PLYImportParams ¶ms) { + Mesh *mesh = BKE_mesh_new_nomain( + data.vertices.size(), data.edges.size(), data.face_sizes.size(), data.face_vertices.size()); - /* Add vertices to the mesh. */ - mesh->totvert = int(data.vertices.size()); - CustomData_add_layer_named( - &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh->totvert, "position"); mesh->vert_positions_for_write().copy_from(data.vertices); bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); if (!data.edges.is_empty()) { - mesh->totedge = int(data.edges.size()); - CustomData_add_layer_named( - &mesh->edata, CD_PROP_INT32_2D, CD_CONSTRUCT, mesh->totedge, ".edge_verts"); MutableSpan edges = mesh->edges_for_write(); - for (int i = 0; i < mesh->totedge; i++) { + for (const int i : data.edges.index_range()) { int32_t v1 = data.edges[i].first; int32_t v2 = data.edges[i].second; if (v1 >= mesh->totvert) { @@ -50,18 +46,12 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ /* Add faces to the mesh. */ if (!data.face_sizes.is_empty()) { - /* Create poly and loop layers. */ - mesh->totpoly = int(data.face_sizes.size()); - mesh->totloop = int(data.face_vertices.size()); - BKE_mesh_poly_offsets_ensure_alloc(mesh); - CustomData_add_layer_named( - &mesh->ldata, CD_PROP_INT32, CD_CONSTRUCT, mesh->totloop, ".corner_vert"); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); MutableSpan corner_verts = mesh->corner_verts_for_write(); /* Fill in face data. */ uint32_t offset = 0; - for (int i = 0; i < mesh->totpoly; i++) { + for (const int i : data.face_sizes.index_range()) { uint32_t size = data.face_sizes[i]; poly_offsets[i] = offset; for (int j = 0; j < size; j++) { @@ -83,12 +73,12 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ attributes.lookup_or_add_for_write_span("Col", ATTR_DOMAIN_POINT); if (params.vertex_colors == PLY_VERTEX_COLOR_SRGB) { - for (int i = 0; i < data.vertex_colors.size(); i++) { + for (const int i : data.vertex_colors.index_range()) { srgb_to_linearrgb_v4(colors.span[i], data.vertex_colors[i]); } } else { - for (int i = 0; i < data.vertex_colors.size(); i++) { + for (const int i : data.vertex_colors.index_range()) { copy_v4_v4(colors.span[i], data.vertex_colors[i]); } } @@ -101,7 +91,7 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ if (!data.uv_coordinates.is_empty()) { bke::SpanAttributeWriter uv_map = attributes.lookup_or_add_for_write_only_span( "UVMap", ATTR_DOMAIN_CORNER); - for (size_t i = 0; i < data.face_vertices.size(); i++) { + for (const int i : data.face_vertices.index_range()) { uv_map.span[i] = data.uv_coordinates[data.face_vertices[i]]; } uv_map.finish(); @@ -116,17 +106,18 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ mesh, reinterpret_cast(data.vertex_normals.data())); } + BKE_mesh_smooth_flag_set(mesh, false); + /* Merge all vertices on the same location. */ if (params.merge_verts) { - std::optional return_value = blender::geometry::mesh_merge_by_distance_all( + std::optional merged_mesh = blender::geometry::mesh_merge_by_distance_all( *mesh, IndexMask(mesh->totvert), 0.0001f); - if (return_value.has_value()) { - mesh = return_value.value(); + if (merged_mesh) { + BKE_id_free(nullptr, &mesh->id); + mesh = *merged_mesh; } } - BKE_mesh_smooth_flag_set(mesh, false); - return mesh; } } // namespace blender::io::ply diff --git a/source/blender/io/ply/importer/ply_import_mesh.hh b/source/blender/io/ply/importer/ply_import_mesh.hh index 7dddff4f41a..e1d057f4358 100644 --- a/source/blender/io/ply/importer/ply_import_mesh.hh +++ b/source/blender/io/ply/importer/ply_import_mesh.hh @@ -13,9 +13,8 @@ namespace blender::io::ply { /** * Converts the #PlyData data-structure to a mesh. - * \param data: The PLY data. - * \return The mesh that can be used inside blender. + * \return A new mesh that can be used inside blender. */ -Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ms); +Mesh *convert_ply_to_mesh(PlyData &data, const PLYImportParams ¶ms); } // namespace blender::io::ply diff --git a/source/blender/io/stl/importer/stl_import.cc b/source/blender/io/stl/importer/stl_import.cc index 9ca002b71e8..628b3603a1f 100644 --- a/source/blender/io/stl/importer/stl_import.cc +++ b/source/blender/io/stl/importer/stl_import.cc @@ -78,13 +78,9 @@ void importer_main(Main *bmain, BLI_strncpy(ob_name, BLI_path_basename(import_params.filepath), FILE_MAX); BLI_path_extension_strip(ob_name); - Mesh *mesh = nullptr; - if (is_ascii_stl) { - mesh = read_stl_ascii(import_params.filepath, bmain, ob_name, import_params.use_facet_normal); - } - else { - mesh = read_stl_binary(file, bmain, ob_name, import_params.use_facet_normal); - } + Mesh *mesh = is_ascii_stl ? + read_stl_ascii(import_params.filepath, import_params.use_facet_normal) : + read_stl_binary(file, import_params.use_facet_normal); if (mesh == nullptr) { fprintf(stderr, "STL Importer: Failed to import mesh '%s'\n", import_params.filepath); @@ -99,10 +95,12 @@ void importer_main(Main *bmain, BKE_mesh_validate(mesh, verbose_validate, false); } + Mesh *mesh_in_main = BKE_mesh_add(bmain, ob_name); + BKE_mesh_nomain_to_mesh(mesh, mesh_in_main, nullptr); BKE_view_layer_base_deselect_all(scene, view_layer); LayerCollection *lc = BKE_layer_collection_get_active(view_layer); Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name); - BKE_mesh_assign_object(bmain, obj, mesh); + BKE_mesh_assign_object(bmain, obj, mesh_in_main); BKE_collection_object_add(bmain, lc->collection, obj); BKE_view_layer_synced_ensure(scene, view_layer); Base *base = BKE_view_layer_base_find(view_layer, obj); diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.cc b/source/blender/io/stl/importer/stl_import_ascii_reader.cc index 8bfe4924cc5..e213fa94bf0 100644 --- a/source/blender/io/stl/importer/stl_import_ascii_reader.cc +++ b/source/blender/io/stl/importer/stl_import_ascii_reader.cc @@ -111,13 +111,13 @@ static inline void parse_float3(StringBuffer &buf, float out[3]) } } -Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals) +Mesh *read_stl_ascii(const char *filepath, const bool use_custom_normals) { size_t buffer_len; void *buffer = BLI_file_read_text_as_mem(filepath, 0, &buffer_len); if (buffer == nullptr) { fprintf(stderr, "STL Importer: cannot read from ASCII STL file: '%s'\n", filepath); - return BKE_mesh_add(bmain, mesh_name); + return nullptr; } BLI_SCOPED_DEFER([&]() { MEM_freeN(buffer); }); @@ -154,7 +154,7 @@ Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool us } } - return stl_mesh.to_mesh(bmain, mesh_name); + return stl_mesh.to_mesh(); } } // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.hh b/source/blender/io/stl/importer/stl_import_ascii_reader.hh index e8aed911bf1..9998f111eda 100644 --- a/source/blender/io/stl/importer/stl_import_ascii_reader.hh +++ b/source/blender/io/stl/importer/stl_import_ascii_reader.hh @@ -30,6 +30,6 @@ namespace blender::io::stl { -Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals); +Mesh *read_stl_ascii(const char *filepath, bool use_custom_normals); } // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.cc b/source/blender/io/stl/importer/stl_import_binary_reader.cc index 26d9e3406e7..d6b6aa1b33f 100644 --- a/source/blender/io/stl/importer/stl_import_binary_reader.cc +++ b/source/blender/io/stl/importer/stl_import_binary_reader.cc @@ -29,7 +29,7 @@ struct STLBinaryTriangle { }; #pragma pack(pop) -Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals) +Mesh *read_stl_binary(FILE *file, const bool use_custom_normals) { const int chunk_size = 1024; uint32_t num_tris = 0; @@ -40,7 +40,7 @@ Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_ } if (num_tris == 0) { - return BKE_mesh_add(bmain, mesh_name); + return BKE_mesh_new_nomain(0, 0, 0, 0); } Array tris_buf(chunk_size); @@ -57,7 +57,7 @@ Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_ } } - return stl_mesh.to_mesh(bmain, mesh_name); + return stl_mesh.to_mesh(); } } // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.hh b/source/blender/io/stl/importer/stl_import_binary_reader.hh index 71d5dbbbe58..729da94f6bc 100644 --- a/source/blender/io/stl/importer/stl_import_binary_reader.hh +++ b/source/blender/io/stl/importer/stl_import_binary_reader.hh @@ -26,6 +26,6 @@ namespace blender::io::stl { const size_t BINARY_HEADER_SIZE = 80; const size_t BINARY_STRIDE = 12 * 4 + 2; -Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals); +Mesh *read_stl_binary(FILE *file, bool use_custom_normals); } // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc index 1c19a96cc0d..34104348c7d 100644 --- a/source/blender/io/stl/importer/stl_import_mesh.cc +++ b/source/blender/io/stl/importer/stl_import_mesh.cc @@ -10,6 +10,7 @@ #include "BKE_mesh.hh" #include "BLI_array.hh" +#include "BLI_array_utils.hh" #include "BLI_math_vector.h" #include "BLI_math_vector.hh" #include "BLI_task.hh" @@ -60,7 +61,7 @@ void STLMeshHelper::add_triangle(const float3 &a, } } -Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) +Mesh *STLMeshHelper::to_mesh() { if (degenerate_tris_num_ > 0) { std::cout << "STL Importer: " << degenerate_tris_num_ << " degenerate triangles were removed" @@ -71,21 +72,10 @@ Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) << std::endl; } - Mesh *mesh = BKE_mesh_add(bmain, mesh_name); - /* User count is already 1 here, but will be set later in #BKE_mesh_assign_object. */ - id_us_min(&mesh->id); + Mesh *mesh = BKE_mesh_new_nomain(verts_.size(), 0, tris_.size(), tris_.size() * 3); - mesh->totvert = verts_.size(); - CustomData_add_layer_named( - &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh->totvert, "position"); mesh->vert_positions_for_write().copy_from(verts_); - mesh->totpoly = tris_.size(); - mesh->totloop = tris_.size() * 3; - BKE_mesh_poly_offsets_ensure_alloc(mesh); - CustomData_add_layer_named( - &mesh->ldata, CD_PROP_INT32, CD_SET_DEFAULT, mesh->totloop, ".corner_vert"); - MutableSpan poly_offsets = mesh->poly_offsets_for_write(); threading::parallel_for(poly_offsets.index_range(), 4096, [&](const IndexRange range) { for (const int i : range) { @@ -93,14 +83,7 @@ Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) } }); - MutableSpan corner_verts = mesh->corner_verts_for_write(); - threading::parallel_for(tris_.index_range(), 2048, [&](IndexRange tris_range) { - for (const int i : tris_range) { - corner_verts[3 * i] = tris_[i].v1; - corner_verts[3 * i + 1] = tris_[i].v2; - corner_verts[3 * i + 2] = tris_[i].v3; - } - }); + array_utils::copy(tris_.as_span().cast(), mesh->corner_verts_for_write()); /* NOTE: edges must be calculated first before setting custom normals. */ BKE_mesh_calc_edges(mesh, false, false); diff --git a/source/blender/io/stl/importer/stl_import_mesh.hh b/source/blender/io/stl/importer/stl_import_mesh.hh index 658d42ca7a7..7d6ae101b09 100644 --- a/source/blender/io/stl/importer/stl_import_mesh.hh +++ b/source/blender/io/stl/importer/stl_import_mesh.hh @@ -65,7 +65,7 @@ class STLMeshHelper { const float3 &b, const float3 &c, const float3 &custom_normal); - Mesh *to_mesh(Main *bmain, char *mesh_name); + Mesh *to_mesh(); }; } // namespace blender::io::stl diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 762686331f8..79c382581e1 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -942,7 +942,7 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, if (topology_changed(existing_mesh, params.motion_sample_time)) { new_mesh = true; active_mesh = BKE_mesh_new_nomain_from_template( - existing_mesh, positions_.size(), 0, face_indices_.size(), face_counts_.size()); + existing_mesh, positions_.size(), 0, face_counts_.size(), face_indices_.size()); for (pxr::TfToken token : uv_tokens) { add_customdata_cb(active_mesh, token.GetText(), CD_PROP_FLOAT2); diff --git a/source/blender/io/usd/intern/usd_reader_shape.cc b/source/blender/io/usd/intern/usd_reader_shape.cc index d1352c3006a..32bedc3114f 100644 --- a/source/blender/io/usd/intern/usd_reader_shape.cc +++ b/source/blender/io/usd/intern/usd_reader_shape.cc @@ -179,7 +179,7 @@ Mesh *USDShapeReader::mesh_from_prim(Mesh *existing_mesh, Mesh *active_mesh = nullptr; if (!position_counts_match || !poly_counts_match) { active_mesh = BKE_mesh_new_nomain_from_template( - existing_mesh, positions.size(), 0, face_indices.size(), face_counts.size()); + existing_mesh, positions.size(), 0, face_counts.size(), face_indices.size()); } else { active_mesh = existing_mesh; diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc index d4869cec929..358f1e8fc24 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc @@ -48,7 +48,7 @@ Object *MeshFromGeometry::create_mesh(Main *bmain, const int64_t tot_face_elems{mesh_geometry_.face_elements_.size()}; const int64_t tot_loops{mesh_geometry_.total_loops_}; - Mesh *mesh = BKE_mesh_new_nomain(tot_verts_object, tot_edges, tot_loops, tot_face_elems); + Mesh *mesh = BKE_mesh_new_nomain(tot_verts_object, tot_edges, tot_face_elems, tot_loops); Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name.c_str()); obj->data = BKE_object_obdata_add_from_type(bmain, OB_MESH, ob_name.c_str()); diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc index 161c2817ba3..8028419ef10 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -99,7 +99,7 @@ TEST(obj_exporter_utils, append_negative_frame_to_filename) char path_with_frame[FILE_MAX] = {0}; const bool ok = append_frame_to_filename(path_original, frame, path_with_frame); EXPECT_TRUE(ok); - EXPECT_EQ_ARRAY(path_with_frame, path_truth, BLI_strlen_utf8(path_truth)); + EXPECT_STREQ(path_with_frame, path_truth); } TEST(obj_exporter_utils, append_positive_frame_to_filename) @@ -110,7 +110,7 @@ TEST(obj_exporter_utils, append_positive_frame_to_filename) char path_with_frame[FILE_MAX] = {0}; const bool ok = append_frame_to_filename(path_original, frame, path_with_frame); EXPECT_TRUE(ok); - EXPECT_EQ_ARRAY(path_with_frame, path_truth, BLI_strlen_utf8(path_truth)); + EXPECT_STREQ(path_with_frame, path_truth); } static std::string read_temp_file_in_string(const std::string &file_path) diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h index 9a0ad3b6d99..34ba89e8e7e 100644 --- a/source/blender/makesdna/DNA_brush_enums.h +++ b/source/blender/makesdna/DNA_brush_enums.h @@ -50,7 +50,10 @@ typedef enum eGPBrush_Presets { GP_BRUSH_PRESET_CLONE_STROKE = 208, /* Weight Paint 300-399. */ - GP_BRUSH_PRESET_DRAW_WEIGHT = 300, + GP_BRUSH_PRESET_WEIGHT_DRAW = 300, + GP_BRUSH_PRESET_WEIGHT_BLUR = 301, + GP_BRUSH_PRESET_WEIGHT_AVERAGE = 302, + GP_BRUSH_PRESET_WEIGHT_SMEAR = 303, } eGPBrush_Presets; /* BrushGpencilSettings->flag */ @@ -187,6 +190,9 @@ typedef enum eGP_BrushIcons { GP_BRUSH_ICON_GPBRUSH_PINCH = 26, GP_BRUSH_ICON_GPBRUSH_CLONE = 27, GP_BRUSH_ICON_GPBRUSH_WEIGHT = 28, + GP_BRUSH_ICON_GPBRUSH_BLUR = 29, + GP_BRUSH_ICON_GPBRUSH_AVERAGE = 30, + GP_BRUSH_ICON_GPBRUSH_SMEAR = 31, } eGP_BrushIcons; typedef enum eBrushCurvePreset { @@ -607,6 +613,9 @@ typedef enum eBrushGPSculptTool { /* BrushGpencilSettings->brush type */ typedef enum eBrushGPWeightTool { GPWEIGHT_TOOL_DRAW = 0, + GPWEIGHT_TOOL_BLUR = 1, + GPWEIGHT_TOOL_AVERAGE = 2, + GPWEIGHT_TOOL_SMEAR = 3, } eBrushGPWeightTool; /* direction that the brush displaces along */ diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 7829c5d3f44..c659069c19a 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -602,6 +602,10 @@ enum { CU_CHINFO_OVERFLOW = 1 << 6, }; +/** User adjustable as styles (not relating to run-time layout calculation). */ +#define CU_CHINFO_STYLE_ALL \ + (CU_CHINFO_BOLD | CU_CHINFO_ITALIC | CU_CHINFO_UNDERLINE | CU_CHINFO_SMALLCAPS) + /* mixed with KEY_LINEAR but define here since only curve supports */ #define KEY_CU_EASE 3 diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index ff82cd2183f..741f5e1ae44 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -630,6 +630,7 @@ enum { V3D_ORIENT_VIEW = 3, V3D_ORIENT_GIMBAL = 4, V3D_ORIENT_CURSOR = 5, + V3D_ORIENT_PARENT = 6, V3D_ORIENT_CUSTOM = 1024, /** Runtime only, never saved to DNA. */ V3D_ORIENT_CUSTOM_MATRIX = (V3D_ORIENT_CUSTOM - 1), diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c index 887fa662e97..66c11f2fe57 100644 --- a/source/blender/makesrna/intern/rna_animviz.c +++ b/source/blender/makesrna/intern/rna_animviz.c @@ -157,6 +157,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Color", "Custom color for motion path"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* Line width */ prop = RNA_def_property(srna, "line_thickness", PROP_INT, PROP_NONE); @@ -164,6 +165,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) RNA_def_property_range(prop, 1, 6); RNA_def_property_ui_text(prop, "Line Thickness", "Line thickness for motion path"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* Settings */ prop = RNA_def_property(srna, "use_bone_head", PROP_BOOLEAN, PROP_NONE); @@ -184,6 +186,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_CUSTOM); RNA_def_property_ui_text(prop, "Custom Colors", "Use custom color for this motion path"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* Draw lines between keyframes */ prop = RNA_def_property(srna, "lines", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 4fda642e2e2..9505031bb76 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -293,7 +293,18 @@ const EnumPropertyItem rna_enum_brush_gpencil_weight_types_items[] = { "WEIGHT", ICON_GPBRUSH_WEIGHT, "Weight", - "Weight Paint for Vertex Groups"}, + "Paint weight in active vertex group"}, + {GPWEIGHT_TOOL_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", "Blur weight in active vertex group"}, + {GPWEIGHT_TOOL_AVERAGE, + "AVERAGE", + ICON_BRUSH_BLUR, + "Average", + "Average weight in active vertex group"}, + {GPWEIGHT_TOOL_SMEAR, + "SMEAR", + ICON_BRUSH_SMEAR, + "Smear", + "Smear weight in active vertex group"}, {0, NULL, 0, NULL, NULL}, }; @@ -401,6 +412,9 @@ static EnumPropertyItem rna_enum_gpencil_brush_sculpt_icons_items[] = { static EnumPropertyItem rna_enum_gpencil_brush_weight_icons_items[] = { {GP_BRUSH_ICON_GPBRUSH_WEIGHT, "DRAW", ICON_GPBRUSH_WEIGHT, "Draw", ""}, + {GP_BRUSH_ICON_GPBRUSH_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", ""}, + {GP_BRUSH_ICON_GPBRUSH_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", ""}, + {GP_BRUSH_ICON_GPBRUSH_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", ""}, {0, NULL, 0, NULL, NULL}, }; static EnumPropertyItem rna_enum_gpencil_brush_vertex_icons_items[] = { diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index c2dc81bb9e5..7ad1adb66b4 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -628,6 +628,11 @@ const EnumPropertyItem rna_enum_transform_orientation_items[] = { ICON_ORIENTATION_CURSOR, "Cursor", "Align the transformation axes to the 3D cursor"}, + {V3D_ORIENT_PARENT, + "PARENT", + ICON_BLANK1, + "Parent", + "Align the transformation axes to the object's parent space"}, // {V3D_ORIENT_CUSTOM, "CUSTOM", 0, "Custom", "Use a custom transform orientation"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 1cad3b2bb75..6013f09ddbe 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1496,8 +1496,8 @@ static void rna_SequenceTimelineChannel_name_set(PointerRNA *ptr, const char *va sizeof(channel->name)); } -static void rna_SequenceTimelineChannel_mute_update(Main *UNUSED(bmain), - Scene *UNUSED(active_scene), +static void rna_SequenceTimelineChannel_mute_update(Main *bmain, + Scene *active_scene, PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; @@ -1516,6 +1516,8 @@ static void rna_SequenceTimelineChannel_mute_update(Main *UNUSED(bmain), LISTBASE_FOREACH (Sequence *, seq, seqbase) { SEQ_relations_invalidate_cache_composite(scene, seq); } + + rna_Sequence_sound_update(bmain, active_scene, ptr); } static char *rna_SeqTimelineChannel_path(const PointerRNA *ptr) diff --git a/source/blender/modifiers/intern/MOD_array.cc b/source/blender/modifiers/intern/MOD_array.cc index 80ea448ed51..3174c0eafc4 100644 --- a/source/blender/modifiers/intern/MOD_array.cc +++ b/source/blender/modifiers/intern/MOD_array.cc @@ -551,7 +551,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, /* Initialize a result dm */ result = BKE_mesh_new_nomain_from_template( - mesh, result_nverts, result_nedges, result_nloops, result_npolys); + mesh, result_nverts, result_nedges, result_npolys, result_nloops); float(*result_positions)[3] = BKE_mesh_vert_positions_for_write(result); blender::MutableSpan result_edges = result->edges_for_write(); blender::MutableSpan result_poly_offsets = result->poly_offsets_for_write(); diff --git a/source/blender/modifiers/intern/MOD_build.cc b/source/blender/modifiers/intern/MOD_build.cc index f9533cf6b2c..63cb59f09c0 100644 --- a/source/blender/modifiers/intern/MOD_build.cc +++ b/source/blender/modifiers/intern/MOD_build.cc @@ -189,7 +189,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* now we know the number of verts, edges and faces, we can create the mesh. */ result = BKE_mesh_new_nomain_from_template( - mesh, BLI_ghash_len(vertHash), BLI_ghash_len(edgeHash), loops_dst_num, faces_dst_num); + mesh, BLI_ghash_len(vertHash), BLI_ghash_len(edgeHash), faces_dst_num, loops_dst_num); blender::MutableSpan result_edges = result->edges_for_write(); blender::MutableSpan result_poly_offsets = result->poly_offsets_for_write(); blender::MutableSpan result_corner_verts = result->corner_verts_for_write(); diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc index 53da9d7b856..25bccff6670 100644 --- a/source/blender/modifiers/intern/MOD_mask.cc +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -702,8 +702,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext * /*ctx*/, M Mesh *result = BKE_mesh_new_nomain_from_template(mesh, verts_masked_num + verts_add_num, edges_masked_num + edges_add_num, - loops_masked_num + loops_add_num, - polys_masked_num + polys_add_num); + polys_masked_num + polys_add_num, + loops_masked_num + loops_add_num); copy_masked_verts_to_new_mesh(*mesh, *result, vertex_map); if (use_interpolation) { diff --git a/source/blender/modifiers/intern/MOD_ocean.cc b/source/blender/modifiers/intern/MOD_ocean.cc index a7453756f56..06a78e81dfc 100644 --- a/source/blender/modifiers/intern/MOD_ocean.cc +++ b/source/blender/modifiers/intern/MOD_ocean.cc @@ -255,7 +255,7 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig, co gogd.sx /= gogd.rx; gogd.sy /= gogd.ry; - result = BKE_mesh_new_nomain(verts_num, 0, polys_num * 4, polys_num); + result = BKE_mesh_new_nomain(verts_num, 0, polys_num, polys_num * 4); BKE_mesh_copy_parameters_for_eval(result, mesh_orig); gogd.vert_positions = BKE_mesh_vert_positions_for_write(result); diff --git a/source/blender/modifiers/intern/MOD_particleinstance.cc b/source/blender/modifiers/intern/MOD_particleinstance.cc index 49e8bf751ae..9948f300730 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.cc +++ b/source/blender/modifiers/intern/MOD_particleinstance.cc @@ -312,7 +312,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * max_co = max[track]; } - result = BKE_mesh_new_nomain_from_template(mesh, maxvert, maxedge, maxloop, maxpoly); + result = BKE_mesh_new_nomain_from_template(mesh, maxvert, maxedge, maxpoly, maxloop); const blender::OffsetIndices orig_polys = mesh->polys(); const blender::Span orig_corner_verts = mesh->corner_verts(); diff --git a/source/blender/modifiers/intern/MOD_particlesystem.cc b/source/blender/modifiers/intern/MOD_particlesystem.cc index 13220306d65..433e398a9f2 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.cc +++ b/source/blender/modifiers/intern/MOD_particlesystem.cc @@ -154,7 +154,7 @@ static void deformVerts(ModifierData *md, } /* make new mesh */ - psmd->mesh_final = BKE_mesh_copy_for_eval(mesh_src, false); + psmd->mesh_final = BKE_mesh_copy_for_eval(mesh_src); BKE_mesh_vert_coords_apply(psmd->mesh_final, vertexCos); BKE_mesh_tessface_ensure(psmd->mesh_final); @@ -185,7 +185,7 @@ static void deformVerts(ModifierData *md, /* Make a persistent copy of the mesh. We don't actually need * all this data, just some topology for remapping. Could be * optimized once. */ - psmd->mesh_original = BKE_mesh_copy_for_eval(mesh_original, false); + psmd->mesh_original = BKE_mesh_copy_for_eval(mesh_original); } BKE_mesh_tessface_ensure(psmd->mesh_original); diff --git a/source/blender/modifiers/intern/MOD_remesh.cc b/source/blender/modifiers/intern/MOD_remesh.cc index a867db11127..32589bae6e7 100644 --- a/source/blender/modifiers/intern/MOD_remesh.cc +++ b/source/blender/modifiers/intern/MOD_remesh.cc @@ -93,7 +93,7 @@ static void *dualcon_alloc_output(int totvert, int totquad) return nullptr; } - output->mesh = BKE_mesh_new_nomain(totvert, 0, 4 * totquad, totquad); + output->mesh = BKE_mesh_new_nomain(totvert, 0, totquad, 4 * totquad); output->vert_positions = BKE_mesh_vert_positions_for_write(output->mesh); output->poly_offsets = output->mesh->poly_offsets_for_write().data(); output->corner_verts = output->mesh->corner_verts_for_write().data(); diff --git a/source/blender/modifiers/intern/MOD_screw.cc b/source/blender/modifiers/intern/MOD_screw.cc index 00c850af1c2..17f21b6674e 100644 --- a/source/blender/modifiers/intern/MOD_screw.cc +++ b/source/blender/modifiers/intern/MOD_screw.cc @@ -390,7 +390,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * const bool do_remove_doubles = (ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f); result = BKE_mesh_new_nomain_from_template( - mesh, int(maxVerts), int(maxEdges), int(maxPolys) * 4, int(maxPolys)); + mesh, int(maxVerts), int(maxEdges), int(maxPolys), int(maxPolys) * 4); /* The modifier doesn't support original index mapping on the edge or face domains. Remove * original index layers, since otherwise edges aren't displayed at all in wireframe view. */ CustomData_free_layers(&result->edata, CD_ORIGINDEX, result->totedge); diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.cc b/source/blender/modifiers/intern/MOD_solidify_extrude.cc index 6314ec510ca..394fb1ffead 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.cc +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.cc @@ -321,8 +321,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex result = BKE_mesh_new_nomain_from_template(mesh, int((verts_num * stride) + newVerts), int((edges_num * stride) + newEdges + rimVerts), - int((loops_num * stride) + newLoops), - int((polys_num * stride) + newPolys)); + int((polys_num * stride) + newPolys), + int((loops_num * stride) + newLoops)); float(*vert_positions)[3] = BKE_mesh_vert_positions_for_write(result); blender::MutableSpan edges = result->edges_for_write(); diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc index 95f72f160d9..415334056e1 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc @@ -1982,7 +1982,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, /* Create Mesh *result with proper capacity. */ result = BKE_mesh_new_nomain_from_template( - mesh, int(new_verts_num), int(new_edges_num), int(new_loops_num), int(new_polys_num)); + mesh, int(new_verts_num), int(new_edges_num), int(new_polys_num), int(new_loops_num)); float(*vert_positions)[3] = BKE_mesh_vert_positions_for_write(result); blender::MutableSpan edges = result->edges_for_write(); diff --git a/source/blender/modifiers/intern/MOD_util.cc b/source/blender/modifiers/intern/MOD_util.cc index f1080f76d47..1e544875a7d 100644 --- a/source/blender/modifiers/intern/MOD_util.cc +++ b/source/blender/modifiers/intern/MOD_util.cc @@ -182,10 +182,8 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob, /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether * we really need a copy here. Maybe the CoW ob->data can be directly used. */ Mesh *mesh_prior_modifiers = BKE_object_get_pre_modified_mesh(ob); - mesh = (Mesh *)BKE_id_copy_ex(nullptr, - &mesh_prior_modifiers->id, - nullptr, - (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_CD_REFERENCE)); + mesh = (Mesh *)BKE_id_copy_ex( + nullptr, &mesh_prior_modifiers->id, nullptr, LIB_ID_COPY_LOCALIZE); mesh->runtime->deformed_only = true; } diff --git a/source/blender/nodes/NOD_add_node_search.hh b/source/blender/nodes/NOD_add_node_search.hh index b5b21cfe0d0..0fa5395a33c 100644 --- a/source/blender/nodes/NOD_add_node_search.hh +++ b/source/blender/nodes/NOD_add_node_search.hh @@ -25,18 +25,25 @@ struct AddNodeInfo { }; class GatherAddNodeSearchParams { + const bContext &C_; const bNodeType &node_type_; const bNodeTree &node_tree_; Vector &r_items; public: - GatherAddNodeSearchParams(const bNodeType &node_type, + GatherAddNodeSearchParams(const bContext &C, + const bNodeType &node_type, const bNodeTree &node_tree, Vector &r_items) - : node_type_(node_type), node_tree_(node_tree), r_items(r_items) + : C_(C), node_type_(node_type), node_tree_(node_tree), r_items(r_items) { } + const bContext &context() const + { + return C_; + } + const bNodeTree &node_tree() const { return node_tree_; diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index d9895d02e0b..1bd9896261e 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -41,7 +41,7 @@ DefNode(ShaderNode, SH_NODE_CLAMP, def_clamp, "CLAMP" DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "Perform math operations") DefNode(ShaderNode, SH_NODE_VECTOR_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "Perform vector math operation") DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "") -DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "Invert a color, producing a negative") +DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert Color", "Invert a color, producing a negative") DefNode(ShaderNode, SH_NODE_SEPRGB_LEGACY, 0, "SEPRGB", SeparateRGB, "Separate RGB", "Split a color into its red, green, and blue channels (Deprecated)") DefNode(ShaderNode, SH_NODE_COMBRGB_LEGACY, 0, "COMBRGB", CombineRGB, "Combine RGB", "Generate a color from its red, green, and blue channels (Deprecated)") DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation/Value","Apply a color transformation in the HSV color model") @@ -178,7 +178,7 @@ DefNode(CompositorNode, CMP_NODE_MATH, def_math, "MATH", DefNode(CompositorNode, CMP_NODE_LUMA_MATTE, def_cmp_luma_matte, "LUMA_MATTE", LumaMatte, "Luminance Key", "" ) DefNode(CompositorNode, CMP_NODE_BRIGHTCONTRAST, def_cmp_brightcontrast, "BRIGHTCONTRAST", BrightContrast, "Brightness/Contrast","" ) DefNode(CompositorNode, CMP_NODE_GAMMA, 0, "GAMMA", Gamma, "Gamma", "" ) -DefNode(CompositorNode, CMP_NODE_INVERT, def_cmp_invert, "INVERT", Invert, "Invert", "" ) +DefNode(CompositorNode, CMP_NODE_INVERT, def_cmp_invert, "INVERT", Invert, "Invert Color", "" ) DefNode(CompositorNode, CMP_NODE_NORMALIZE, 0, "NORMALIZE", Normalize, "Normalize", "" ) DefNode(CompositorNode, CMP_NODE_CROP, def_cmp_crop, "CROP", Crop, "Crop", "" ) DefNode(CompositorNode, CMP_NODE_DBLUR, def_cmp_dblur, "DBLUR", DBlur, "Directional Blur", "" ) @@ -234,7 +234,7 @@ DefNode(TextureNode, TEX_NODE_RGBTOBW, 0, "RGBTOB DefNode(TextureNode, TEX_NODE_VALTORGB, def_colorramp, "VALTORGB", ValToRGB, "Color Ramp", "" ) DefNode(TextureNode, TEX_NODE_IMAGE, def_tex_image, "IMAGE", Image, "Image", "" ) DefNode(TextureNode, TEX_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", CurveRGB, "RGB Curves", "" ) -DefNode(TextureNode, TEX_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" ) +DefNode(TextureNode, TEX_NODE_INVERT, 0, "INVERT", Invert, "Invert Color", "" ) DefNode(TextureNode, TEX_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation/Value", "" ) DefNode(TextureNode, TEX_NODE_CURVE_TIME, def_time, "CURVE_TIME", CurveTime, "Curve Time", "" ) DefNode(TextureNode, TEX_NODE_ROTATE, 0, "ROTATE", Rotate, "Rotate", "" ) @@ -399,7 +399,7 @@ DefNode(GeometryNode, GEO_NODE_ROTATE_INSTANCES, 0, "ROTATE_INSTANCES", RotateIn DefNode(GeometryNode, GEO_NODE_SAMPLE_CURVE, def_geo_curve_sample, "SAMPLE_CURVE", SampleCurve, "Sample Curve", "Retrieve data from a point on a curve at a certain distance from its start") DefNode(GeometryNode, GEO_NODE_SAMPLE_INDEX, def_geo_sample_index, "SAMPLE_INDEX", SampleIndex, "Sample Index", "Retrieve values from specific geometry elements") DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST_SURFACE, def_geo_sample_nearest_surface, "SAMPLE_NEAREST_SURFACE", SampleNearestSurface, "Sample Nearest Surface", "Calculate the interpolated value of a mesh attribute on the closest point of its surface") -DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST, def_geo_sample_nearest, "SAMPLE_NEAREST", SampleNearest, "Sample Nearest", "Find the element of a geometry closest to a position") +DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST, def_geo_sample_nearest, "SAMPLE_NEAREST", SampleNearest, "Sample Nearest", "Find the element of a geometry closest to a position. Similar to the \"Index of Nearest\" node") DefNode(GeometryNode, GEO_NODE_SAMPLE_UV_SURFACE, def_geo_sample_uv_surface, "SAMPLE_UV_SURFACE", SampleUVSurface, "Sample UV Surface", "Calculate the interpolated values of a mesh attribute at a UV coordinate") DefNode(GeometryNode, GEO_NODE_SCALE_ELEMENTS, def_geo_scale_elements, "SCALE_ELEMENTS", ScaleElements, "Scale Elements", "Scale groups of connected edges and faces") DefNode(GeometryNode, GEO_NODE_SCALE_INSTANCES, 0, "SCALE_INSTANCES", ScaleInstances, "Scale Instances", "Scale geometry instances in local or global space") diff --git a/source/blender/nodes/composite/nodes/node_composite_id_mask.cc b/source/blender/nodes/composite/nodes/node_composite_id_mask.cc index 1a0a200062d..1cf97682b2f 100644 --- a/source/blender/nodes/composite/nodes/node_composite_id_mask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_id_mask.cc @@ -5,12 +5,18 @@ * \ingroup cmpnodes */ +#include + #include "BLT_translation.h" #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_shader.h" + +#include "COM_algorithm_smaa.hh" #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" @@ -20,7 +26,11 @@ namespace blender::nodes::node_composite_id_mask_cc { static void cmp_node_idmask_declare(NodeDeclarationBuilder &b) { - b.add_input(N_("ID value")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_input(N_("ID value")) + .default_value(1.0f) + .min(0.0f) + .max(1.0f) + .compositor_domain_priority(0); b.add_output(N_("Alpha")); } @@ -38,8 +48,56 @@ class IDMaskOperation : public NodeOperation { void execute() override { - get_input("ID value").pass_through(get_result("Alpha")); - context().set_info_message("Viewport compositor setup not fully supported"); + const Result &input_mask = get_input("ID value"); + if (input_mask.is_single_value()) { + execute_single_value(); + return; + } + + GPUShader *shader = shader_manager().get("compositor_id_mask"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1i(shader, "index", get_index()); + + input_mask.bind_as_texture(shader, "input_mask_tx"); + + /* If anti-aliasing is disabled, write to the output directly, otherwise, write to a temporary + * result to later perform anti-aliasing. */ + Result non_anti_aliased_mask = Result::Temporary(ResultType::Float, texture_pool()); + Result &output_mask = use_anti_aliasing() ? non_anti_aliased_mask : get_result("Alpha"); + + const Domain domain = compute_domain(); + output_mask.allocate_texture(domain); + output_mask.bind_as_image(shader, "output_mask_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + input_mask.unbind_as_texture(); + output_mask.unbind_as_image(); + GPU_shader_unbind(); + + if (use_anti_aliasing()) { + smaa(context(), non_anti_aliased_mask, get_result("Alpha")); + non_anti_aliased_mask.release(); + } + } + + void execute_single_value() + { + const float input_mask_value = get_input("ID value").get_float_value(); + const float mask = int(round(input_mask_value)) == get_index() ? 1.0f : 0.0f; + get_result("Alpha").allocate_single_value(); + get_result("Alpha").set_float_value(mask); + } + + int get_index() + { + return bnode().custom1; + } + + bool use_anti_aliasing() + { + return bnode().custom2 != 0; } }; @@ -60,8 +118,6 @@ void register_node_type_cmp_idmask() ntype.declare = file_ns::cmp_node_idmask_declare; ntype.draw_buttons = file_ns::node_composit_buts_id_mask; ntype.get_compositor_operation = file_ns::get_compositor_operation; - ntype.realtime_compositor_unsupported_message = N_( - "Node not supported in the Viewport compositor"); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_invert.cc b/source/blender/nodes/composite/nodes/node_composite_invert.cc index 58732cb80f5..76cfbbc9ecd 100644 --- a/source/blender/nodes/composite/nodes/node_composite_invert.cc +++ b/source/blender/nodes/composite/nodes/node_composite_invert.cc @@ -93,7 +93,7 @@ void register_node_type_cmp_invert() static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR); + cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert Color", NODE_CLASS_OP_COLOR); ntype.declare = file_ns::cmp_node_invert_declare; ntype.draw_buttons = file_ns::node_composit_buts_invert; ntype.initfunc = file_ns::node_composit_init_invert; diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index 9073614b262..5636a17b82d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -37,10 +37,10 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span coords) /* Create Mesh *result with proper capacity. */ Mesh *result; if (mesh) { - result = BKE_mesh_new_nomain_from_template(mesh, verts_num, edges_num, loops_num, faces_num); + result = BKE_mesh_new_nomain_from_template(mesh, verts_num, edges_num, faces_num, loops_num); } else { - result = BKE_mesh_new_nomain(verts_num, edges_num, loops_num, faces_num); + result = BKE_mesh_new_nomain(verts_num, edges_num, faces_num, loops_num); BKE_id_material_eval_ensure_default_slot(&result->id); } BKE_mesh_smooth_flag_set(result, false); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc index 16a56539ef9..8f563fa52ad 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc @@ -79,7 +79,7 @@ static Mesh *cdt_to_mesh(const meshintersect::CDT_result &result) loop_len += face.size(); } - Mesh *mesh = BKE_mesh_new_nomain(vert_len, edge_len, loop_len, poly_len); + Mesh *mesh = BKE_mesh_new_nomain(vert_len, edge_len, poly_len, loop_len); MutableSpan positions = mesh->vert_positions_for_write(); mesh->edges_for_write().copy_from(result.edge.as_span().cast()); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index 2fdb9ff8d9b..222e8ac0d75 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -913,8 +913,8 @@ static void do_mesh_separation(GeometrySet &geometry_set, mesh_out = BKE_mesh_new_nomain_from_template(&mesh_in, selected_verts_num, selected_edges_num, - selected_loops_num, - selected_polys_num); + selected_polys_num, + selected_loops_num); /* Copy the selected parts of the mesh over to the new mesh. */ copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, vertex_map, edge_map); @@ -986,7 +986,7 @@ static void do_mesh_separation(GeometrySet &geometry_set, break; } mesh_out = BKE_mesh_new_nomain_from_template( - &mesh_in, mesh_in.totvert, selected_edges_num, selected_loops_num, selected_polys_num); + &mesh_in, mesh_in.totvert, selected_edges_num, selected_polys_num, selected_loops_num); /* Copy the selected parts of the mesh over to the new mesh. */ copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, edge_map); @@ -1049,7 +1049,7 @@ static void do_mesh_separation(GeometrySet &geometry_set, break; } mesh_out = BKE_mesh_new_nomain_from_template( - &mesh_in, mesh_in.totvert, mesh_in.totedge, selected_loops_num, selected_polys_num); + &mesh_in, mesh_in.totvert, mesh_in.totedge, selected_polys_num, selected_loops_num); /* Copy the selected parts of the mesh over to the new mesh. */ mesh_out->edges_for_write().copy_from(mesh_in.edges()); diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index 868ffaa5521..9eb00fd9d46 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -869,7 +869,7 @@ static Mesh *calc_dual_mesh(const Mesh &src_mesh, } } Mesh *mesh_out = BKE_mesh_new_nomain( - vert_positions.size(), new_edges.size(), loops.size(), loop_lengths.size()); + vert_positions.size(), new_edges.size(), loop_lengths.size(), loops.size()); BKE_mesh_smooth_flag_set(mesh_out, false); transfer_attributes(vertex_types, diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index 4f7d7d49fb3..23f55a6dd25 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -512,7 +512,7 @@ static void duplicate_faces(GeometrySet &geometry_set, const OffsetIndices duplicates(offset_data); - Mesh *new_mesh = BKE_mesh_new_nomain(total_loops, total_loops, total_loops, total_polys); + Mesh *new_mesh = BKE_mesh_new_nomain(total_loops, total_loops, total_polys, total_loops); MutableSpan new_edges = new_mesh->edges_for_write(); MutableSpan new_poly_offsets = new_mesh->poly_offsets_for_write(); MutableSpan new_corner_verts = new_mesh->corner_verts_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc index 772c4721284..ef1995e72b3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc @@ -61,7 +61,7 @@ static Curves *edge_paths_to_curves_convert( return nullptr; } Curves *curves_id = bke::curves_new_nomain(geometry::create_curve_from_vert_indices( - mesh, vert_indices, curve_offsets, IndexRange(0), propagation_info)); + mesh.attributes(), vert_indices, curve_offsets, IndexRange(0), propagation_info)); return curves_id; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_index_of_nearest.cc b/source/blender/nodes/geometry/nodes/node_geo_index_of_nearest.cc index 820f5219685..c2f624d462a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_index_of_nearest.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_index_of_nearest.cc @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BKE_attribute_math.hh" - #include "BLI_kdtree.h" #include "BLI_multi_value_map.hh" #include "BLI_task.hh" @@ -19,6 +17,55 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output(N_("Has Neighbor")).field_source(); } +static KDTree_3d *build_kdtree(const Span &positions, const IndexMask mask) +{ + KDTree_3d *tree = BLI_kdtree_3d_new(mask.size()); + for (const int i : mask) { + BLI_kdtree_3d_insert(tree, i, positions[i]); + } + BLI_kdtree_3d_balance(tree); + return tree; +} + +static int find_nearest_non_self(const KDTree_3d &tree, const float3 &position, const int index) +{ + return BLI_kdtree_3d_find_nearest_cb_cpp( + &tree, position, 0, [index](const int other, const float * /*co*/, const float /*dist_sq*/) { + return index == other ? 0 : 1; + }); +} + +static void find_neighbors(const KDTree_3d &tree, + const Span positions, + const IndexMask mask, + MutableSpan indices) +{ + threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) { + for (const int i : mask.slice(range)) { + indices[i] = find_nearest_non_self(tree, positions[i], i); + } + }); +} + +static Vector masks_from_group_ids(const Span group_ids, + const IndexMask mask, + MultiValueMap &storage) +{ + mask.foreach_index([&](const int i) { storage.add(group_ids[i], i); }); + Vector masks; + masks.reserve(storage.size()); + for (const Span indices : storage.values()) { + masks.append(indices); + } + return masks; +} + +static Vector masks_from_group_ids(const Span group_ids, + MultiValueMap &storage) +{ + return masks_from_group_ids(group_ids, group_ids.index_range(), storage); +} + class IndexOfNearestFieldInput final : public bke::GeometryFieldInput { private: const Field positions_field_; @@ -26,70 +73,70 @@ class IndexOfNearestFieldInput final : public bke::GeometryFieldInput { public: IndexOfNearestFieldInput(Field positions_field, Field group_field) - : bke::GeometryFieldInput(CPPType::get(), "Nearest to"), + : bke::GeometryFieldInput(CPPType::get(), "Index of Nearest"), positions_field_(std::move(positions_field)), group_field_(std::move(group_field)) { } GVArray get_varray_for_context(const bke::GeometryFieldContext &context, - IndexMask mask) const final + const IndexMask mask) const final { - fn::FieldEvaluator evaluator{context, &mask}; + if (!context.attributes()) { + return {}; + } + const int domain_size = context.attributes()->domain_size(context.domain()); + fn::FieldEvaluator evaluator{context, domain_size}; evaluator.add(positions_field_); evaluator.add(group_field_); evaluator.evaluate(); + const VArraySpan positions = evaluator.get_evaluated(0); + const VArray group = evaluator.get_evaluated(1); - const VArray &positions = evaluator.get_evaluated(0); - const VArray &group = evaluator.get_evaluated(1); + Array result(mask.min_array_size()); - MultiValueMap group_masks; - mask.foreach_index([&](const int index) { group_masks.add(group[index], index); }); - - Array indices(mask.min_array_size()); - - const auto nearest_for = [this, &positions](const IndexMask mask, MutableSpan r_indices) { - devirtualize_varray(positions, [mask, r_indices, this](const auto positions) { - KDTree_3d *tree = BLI_kdtree_3d_new(mask.size()); - mask.foreach_index([tree, positions](const int index) { - BLI_kdtree_3d_insert(tree, index, positions[index]); - }); - - BLI_kdtree_3d_balance(tree); - - threading::parallel_for(mask.index_range(), 512, [&](const IndexRange range) { - mask.slice(range).foreach_index([&](const auto index) { - r_indices[index] = this->kdtree_find_neighboard(tree, positions[index], index); - }); - }); - - BLI_kdtree_3d_free(tree); - }); - }; - - for (const Span mask_span : group_masks.values()) { - if (mask_span.size() == 1) { - indices[mask_span.first()] = -1; - } - nearest_for(mask_span, indices); + if (group.is_single()) { + const IndexMask full_mask = positions.index_range(); + KDTree_3d *tree = build_kdtree(positions, full_mask); + find_neighbors(*tree, positions, mask, result); + BLI_kdtree_3d_free(tree); } + else { + /* The goal is to build each tree and use it immediately, rather than building all trees and + * sampling them later. That should help to keep the tree in caches before balancing and when + * sampling many points. */ + const VArraySpan group_ids(group); + MultiValueMap group_mask_storage; + const Vector tree_masks = masks_from_group_ids(group_ids, group_mask_storage); - return VArray::ForContainer(std::move(indices)); - } + MultiValueMap evaluate_masks_storage; + Vector evaluate_masks; + if (mask.size() < domain_size) { + /* Separate masks for evaluation are only necessary if the mask mask + * for field input evaluation doesn't have every element selected. */ + evaluate_masks = masks_from_group_ids(group_ids, mask, evaluate_masks_storage); + } - protected: - static int kdtree_find_neighboard(KDTree_3d *tree, const float3 &position, const int &index) - { - return BLI_kdtree_3d_find_nearest_cb_cpp( - tree, - position, - 0, - [index](const int other_new_i, const float * /*co*/, const float /*dist_sq*/) { - if (index == other_new_i) { - return 0; + /* The grain size should be larger as each tree gets smaller. */ + const int avg_tree_size = group_ids.size() / group_mask_storage.size(); + const int grain_size = std::max(8192 / avg_tree_size, 1); + threading::parallel_for(tree_masks.index_range(), grain_size, [&](const IndexRange range) { + for (const int i : range) { + const IndexMask tree_mask = tree_masks[i]; + const IndexMask evaluate_mask = evaluate_masks.is_empty() ? tree_mask : + evaluate_masks[i]; + if (tree_masks[i].size() < 2) { + result.as_mutable_span().fill_indices(evaluate_mask.indices(), 0); } - return 1; - }); + else { + KDTree_3d *tree = build_kdtree(positions, tree_mask); + find_neighbors(*tree, positions, evaluate_mask, result); + BLI_kdtree_3d_free(tree); + } + } + }); + } + return VArray::ForContainer(std::move(result)); } public: @@ -99,53 +146,105 @@ class IndexOfNearestFieldInput final : public bke::GeometryFieldInput { group_field_.node().for_each_field_input_recursive(fn); } - uint64_t hash() const override + uint64_t hash() const final { return get_default_hash_2(positions_field_, group_field_); } - bool is_equal_to(const fn::FieldNode &other) const override + bool is_equal_to(const fn::FieldNode &other) const final { - if (const IndexOfNearestFieldInput *other_field = - dynamic_cast(&other)) { + if (const auto *other_field = dynamic_cast(&other)) { return positions_field_ == other_field->positions_field_ && group_field_ == other_field->group_field_; } return false; } - std::optional preferred_domain(const GeometryComponent &component) const override + std::optional preferred_domain(const GeometryComponent &component) const final { return bke::try_detect_field_domain(component, positions_field_); } }; +class HasNeighborFieldInput final : public bke::GeometryFieldInput { + private: + const Field group_field_; + + public: + HasNeighborFieldInput(Field group_field) + : bke::GeometryFieldInput(CPPType::get(), "Has Neighbor"), + group_field_(std::move(group_field)) + { + } + + GVArray get_varray_for_context(const bke::GeometryFieldContext &context, + const IndexMask mask) const final + { + if (!context.attributes()) { + return {}; + } + const int domain_size = context.attributes()->domain_size(context.domain()); + fn::FieldEvaluator evaluator{context, domain_size}; + evaluator.add(group_field_); + evaluator.evaluate(); + const VArray group = evaluator.get_evaluated(0); + + if (group.is_single()) { + return VArray::ForSingle(true, mask.min_array_size()); + } + + /* When a group ID is contained in the set, it means there is only one element with that ID. */ + Map counts; + const VArraySpan group_span(group); + mask.foreach_index([&](const int i) { + counts.add_or_modify( + group_span[i], [](int *count) { *count = 0; }, [](int *count) { (*count)++; }); + }); + Array result(mask.min_array_size()); + mask.foreach_index([&](const int i) { result[i] = counts.lookup(group_span[i]) > 1; }); + return VArray::ForContainer(std::move(result)); + } + + public: + void for_each_field_input_recursive(FunctionRef fn) const + { + group_field_.node().for_each_field_input_recursive(fn); + } + + uint64_t hash() const final + { + return get_default_hash_2(3984756934876, group_field_); + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (const auto *other_field = dynamic_cast(&other)) { + return group_field_ == other_field->group_field_; + } + return false; + } + + std::optional preferred_domain(const GeometryComponent &component) const final + { + return bke::try_detect_field_domain(component, group_field_); + } +}; + static void node_geo_exec(GeoNodeExecParams params) { Field position_field = params.extract_input>("Position"); Field group_field = params.extract_input>("Group ID"); - Field index_of_nearest_field(std::make_shared( - std::move(position_field), std::move(group_field))); - if (params.output_is_required("Index")) { - static auto clamp_fn = mf::build::SI1_SO( - "Index Clamping", - [](const int index) { return math::max(0, index); }, - mf::build::exec_presets::Materialized()); - auto clamp_op = std::make_shared( - FieldOperation(std::move(clamp_fn), {index_of_nearest_field})); - params.set_output("Index", Field(clamp_op, 0)); + params.set_output("Index", + Field(std::make_shared( + std::move(position_field), group_field))); } if (params.output_is_required("Has Neighbor")) { - static auto valid_fn = mf::build::SI1_SO( - "Index Validating", - [](const int index) { return index != -1; }, - mf::build::exec_presets::Materialized()); - auto valid_op = std::make_shared( - FieldOperation(std::move(valid_fn), {std::move(index_of_nearest_field)})); - params.set_output("Has Neighbor", Field(valid_op, 0)); + params.set_output( + "Has Neighbor", + Field(std::make_shared(std::move(group_field)))); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc index f846bc924e5..239077e0f44 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc @@ -110,8 +110,8 @@ static Mesh *create_circle_mesh(const float radius, { Mesh *mesh = BKE_mesh_new_nomain(circle_vert_total(fill_type, verts_num), circle_edge_total(fill_type, verts_num), - circle_corner_total(fill_type, verts_num), - circle_face_total(fill_type, verts_num)); + circle_face_total(fill_type, verts_num), + circle_corner_total(fill_type, verts_num)); BKE_id_material_eval_ensure_default_slot(&mesh->id); MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan edges = mesh->edges_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc index 7ea33b376ce..6ba771768f5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc @@ -704,7 +704,7 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, } Mesh *mesh = BKE_mesh_new_nomain( - config.tot_verts, config.tot_edges, config.tot_corners, config.tot_faces); + config.tot_verts, config.tot_edges, config.tot_faces, config.tot_corners); BKE_id_material_eval_ensure_default_slot(&mesh->id); MutableSpan positions = mesh->vert_positions_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index 0e7d78a25fd..5703eea738c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -51,8 +51,8 @@ Mesh *create_grid_mesh(const int verts_x, const int edges_y = verts_y - 1; Mesh *mesh = BKE_mesh_new_nomain(verts_x * verts_y, edges_x * verts_y + edges_y * verts_x, - edges_x * edges_y * 4, - edges_x * edges_y); + edges_x * edges_y, + edges_x * edges_y * 4); MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan edges = mesh->edges_for_write(); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc index 5d5f25a944f..d49ddb439ba 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc @@ -306,8 +306,8 @@ static Mesh *create_uv_sphere_mesh(const float radius, { Mesh *mesh = BKE_mesh_new_nomain(sphere_vert_total(segments, rings), sphere_edge_total(segments, rings), - sphere_corner_total(segments, rings), - sphere_face_total(segments, rings)); + sphere_face_total(segments, rings), + sphere_corner_total(segments, rings)); BKE_id_material_eval_ensure_default_slot(&mesh->id); MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan edges = mesh->edges_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc index f6b44a9ac47..c4c0d4b1517 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc @@ -7,6 +7,7 @@ #include "DNA_pointcloud_types.h" #include "BKE_attribute_math.hh" +#include "BKE_mesh.hh" #include "BKE_pointcloud.h" #include "UI_interface.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index 8686832e38b..5ba2ebcc9d1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -123,7 +123,7 @@ static Mesh *create_mesh_from_volume_grids(Span gri loop_offset += (3 * data.tris.size() + 4 * data.quads.size()); } - Mesh *mesh = BKE_mesh_new_nomain(vert_offset, 0, loop_offset, poly_offset); + Mesh *mesh = BKE_mesh_new_nomain(vert_offset, 0, poly_offset, loop_offset); BKE_id_material_eval_ensure_default_slot(&mesh->id); MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan dst_poly_offsets = mesh->poly_offsets_for_write(); diff --git a/source/blender/nodes/shader/node_shader_util.cc b/source/blender/nodes/shader/node_shader_util.cc index a47934bda39..a16f5545a66 100644 --- a/source/blender/nodes/shader/node_shader_util.cc +++ b/source/blender/nodes/shader/node_shader_util.cc @@ -6,7 +6,9 @@ */ #include "DNA_node_types.h" +#include "DNA_space_types.h" +#include "BKE_context.h" #include "BKE_node_runtime.hh" #include "node_shader_util.hh" @@ -14,6 +16,8 @@ #include "NOD_add_node_search.hh" #include "NOD_socket_search_link.hh" +#include "RE_engine.h" + #include "node_exec.h" bool sh_node_poll_default(const bNodeType * /*ntype*/, @@ -56,6 +60,42 @@ void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nc ntype->gather_add_node_search_ops = blender::nodes::search_node_add_ops_for_basic_node; } +bool line_style_shader_nodes_poll(const bContext *C) +{ + const SpaceNode *snode = CTX_wm_space_node(C); + return snode->shaderfrom == SNODE_SHADER_LINESTYLE; +} + +bool world_shader_nodes_poll(const bContext *C) +{ + const SpaceNode *snode = CTX_wm_space_node(C); + return snode->shaderfrom == SNODE_SHADER_WORLD; +} + +bool object_shader_nodes_poll(const bContext *C) +{ + const SpaceNode *snode = CTX_wm_space_node(C); + return snode->shaderfrom == SNODE_SHADER_OBJECT; +} + +bool object_cycles_shader_nodes_poll(const bContext *C) +{ + if (!object_shader_nodes_poll(C)) { + return false; + } + const RenderEngineType *engine_type = CTX_data_engine_type(C); + return STREQ(engine_type->idname, "CYCLES"); +} + +bool object_eevee_shader_nodes_poll(const bContext *C) +{ + if (!object_shader_nodes_poll(C)) { + return false; + } + const RenderEngineType *engine_type = CTX_data_engine_type(C); + return STREQ(engine_type->idname, "BLENDER_EEVEE"); +} + /* ****** */ static void nodestack_get_vec(float *in, short type_in, bNodeStack *ns) diff --git a/source/blender/nodes/shader/node_shader_util.hh b/source/blender/nodes/shader/node_shader_util.hh index 46454fe645e..6ebfd441405 100644 --- a/source/blender/nodes/shader/node_shader_util.hh +++ b/source/blender/nodes/shader/node_shader_util.hh @@ -68,6 +68,11 @@ bool sh_node_poll_default(const struct bNodeType *ntype, const char **r_disabled_hint); void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); void sh_fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); +bool line_style_shader_nodes_poll(const struct bContext *C); +bool world_shader_nodes_poll(const struct bContext *C); +bool object_shader_nodes_poll(const struct bContext *C); +bool object_cycles_shader_nodes_poll(const struct bContext *C); +bool object_eevee_shader_nodes_poll(const struct bContext *C); /* ********* exec data struct, remains internal *********** */ diff --git a/source/blender/nodes/shader/nodes/node_shader_background.cc b/source/blender/nodes/shader/nodes/node_shader_background.cc index 7ac6b63e7c8..b360f585c89 100644 --- a/source/blender/nodes/shader/nodes/node_shader_background.cc +++ b/source/blender/nodes/shader/nodes/node_shader_background.cc @@ -33,6 +33,7 @@ void register_node_type_sh_background() sh_node_type_base(&ntype, SH_NODE_BACKGROUND, "Background", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = world_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_background; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc index f80f99dc174..f28c31d0288 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc @@ -67,6 +67,7 @@ void register_node_type_sh_bsdf_anisotropic() sh_node_type_base(&ntype, SH_NODE_BSDF_ANISOTROPIC, "Anisotropic BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_cycles_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_anisotropic; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.initfunc = file_ns::node_shader_init_anisotropic; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc index 21978c0da02..ba0ccb21720 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc @@ -44,6 +44,7 @@ void register_node_type_sh_bsdf_diffuse() sh_node_type_base(&ntype, SH_NODE_BSDF_DIFFUSE, "Diffuse BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_diffuse; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc index 52ffacf22d5..f243ccd3e41 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc @@ -56,6 +56,7 @@ void register_node_type_sh_bsdf_glass() sh_node_type_base(&ntype, SH_NODE_BSDF_GLASS, "Glass BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.initfunc = file_ns::node_shader_init_glass; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_glass; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc index 4352a9b4a71..c2a4d1d3501 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc @@ -55,6 +55,7 @@ void register_node_type_sh_bsdf_glossy() sh_node_type_base(&ntype, SH_NODE_BSDF_GLOSSY, "Glossy BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.initfunc = file_ns::node_shader_init_glossy; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_glossy; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc index 8e127350e5a..b167fb979e2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc @@ -56,6 +56,7 @@ void register_node_type_sh_bsdf_hair() sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_cycles_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_hair; node_type_size(&ntype, 150, 60, 200); ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_hair; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc index 3c4b6ae5ee9..3712c53d2a3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc @@ -127,6 +127,7 @@ void register_node_type_sh_bsdf_hair_principled() sh_node_type_base( &ntype, SH_NODE_BSDF_HAIR_PRINCIPLED, "Principled Hair BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_cycles_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_principled_hair; node_type_size_preset(&ntype, NODE_SIZE_LARGE); ntype.initfunc = file_ns::node_shader_init_hair_principled; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index f0fcc82d4c1..8cb4e3ad632 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -245,6 +245,7 @@ void register_node_type_sh_bsdf_principled() sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_principled; node_type_size_preset(&ntype, NODE_SIZE_LARGE); ntype.initfunc = file_ns::node_shader_init_principled; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc index 18352f1132a..21cfe4eb6af 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc @@ -54,6 +54,7 @@ void register_node_type_sh_bsdf_refraction() sh_node_type_base(&ntype, SH_NODE_BSDF_REFRACTION, "Refraction BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.initfunc = file_ns::node_shader_init_refraction; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_refraction; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc index c45e497c8e0..adc02379926 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc @@ -57,6 +57,7 @@ void register_node_type_sh_bsdf_toon() sh_node_type_base(&ntype, SH_NODE_BSDF_TOON, "Toon BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_cycles_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_toon; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_toon; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc index ebaf95056cc..2d5ea718e11 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc @@ -39,6 +39,7 @@ void register_node_type_sh_bsdf_translucent() sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSLUCENT, "Translucent BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_translucent; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc index 05b371407ab..9eb11a66ef7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc @@ -34,6 +34,7 @@ void register_node_type_sh_bsdf_transparent() static bNodeType ntype; sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSPARENT, "Transparent BSDF", NODE_CLASS_SHADER); + ntype.add_ui_poll = object_shader_nodes_poll; ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_transparent; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc index 36bd1031db3..2df2de229db 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc @@ -43,6 +43,7 @@ void register_node_type_sh_bsdf_velvet() static bNodeType ntype; sh_node_type_base(&ntype, SH_NODE_BSDF_VELVET, "Velvet BSDF", NODE_CLASS_SHADER); + ntype.add_ui_poll = object_cycles_shader_nodes_poll; ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_velvet; diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc index d8e341f2b2e..67b9a873a49 100644 --- a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc +++ b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc @@ -80,6 +80,7 @@ void register_node_type_sh_eevee_specular() sh_node_type_base(&ntype, SH_NODE_EEVEE_SPECULAR, "Specular BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_eevee_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_eevee_specular; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/shader/nodes/node_shader_holdout.cc b/source/blender/nodes/shader/nodes/node_shader_holdout.cc index f5d8f9b5548..b8e4ef38e72 100644 --- a/source/blender/nodes/shader/nodes/node_shader_holdout.cc +++ b/source/blender/nodes/shader/nodes/node_shader_holdout.cc @@ -30,6 +30,7 @@ void register_node_type_sh_holdout() static bNodeType ntype; sh_node_type_base(&ntype, SH_NODE_HOLDOUT, "Holdout", NODE_CLASS_SHADER); + ntype.add_ui_poll = object_shader_nodes_poll; ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::gpu_shader_rgb; diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.cc b/source/blender/nodes/shader/nodes/node_shader_invert.cc index 3a3cebde7e0..32161030bad 100644 --- a/source/blender/nodes/shader/nodes/node_shader_invert.cc +++ b/source/blender/nodes/shader/nodes/node_shader_invert.cc @@ -33,7 +33,7 @@ void register_node_type_sh_invert() static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR); + sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert Color", NODE_CLASS_OP_COLOR); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::gpu_shader_invert; diff --git a/source/blender/nodes/shader/nodes/node_shader_output_light.cc b/source/blender/nodes/shader/nodes/node_shader_output_light.cc index 81cc1e35820..b55eeb13afa 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_light.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_light.cc @@ -37,6 +37,7 @@ void register_node_type_sh_output_light() sh_node_type_base(&ntype, SH_NODE_OUTPUT_LIGHT, "Light Output", NODE_CLASS_OUTPUT); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_cycles_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_output_light; ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc index 475dc9d1e17..6e7dd1cef30 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc @@ -49,6 +49,7 @@ void register_node_type_sh_output_linestyle() sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = line_style_shader_nodes_poll; ntype.draw_buttons = file_ns::node_buts_output_linestyle; ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.cc b/source/blender/nodes/shader/nodes/node_shader_output_material.cc index 6fb5e30d834..98df8d52ab9 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc @@ -54,6 +54,7 @@ void register_node_type_sh_output_material() sh_node_type_base(&ntype, SH_NODE_OUTPUT_MATERIAL, "Material Output", NODE_CLASS_OUTPUT); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_output_material; ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.cc b/source/blender/nodes/shader/nodes/node_shader_output_world.cc index 0d2cca1927d..738ef6f5be8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_world.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_world.cc @@ -41,6 +41,7 @@ void register_node_type_sh_output_world() sh_node_type_base(&ntype, SH_NODE_OUTPUT_WORLD, "World Output", NODE_CLASS_OUTPUT); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = world_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_output_world; ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc index 815671b8284..bf8fbf6bcf7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc @@ -34,6 +34,7 @@ void register_node_type_sh_shadertorgb() sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_eevee_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_shadertorgb; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc index 94fcdb73c78..3278907b9b8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc +++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc @@ -87,6 +87,7 @@ void register_node_type_sh_subsurface_scattering() sh_node_type_base( &ntype, SH_NODE_SUBSURFACE_SCATTERING, "Subsurface Scattering", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_subsurface; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.initfunc = file_ns::node_shader_init_subsurface_scattering; diff --git a/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc index 4a3aed67b11..738b0cf488c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc +++ b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc @@ -29,6 +29,7 @@ void register_node_type_sh_uvalongstroke() sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = line_style_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_uvalongstroke; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/texture/nodes/node_texture_invert.cc b/source/blender/nodes/texture/nodes/node_texture_invert.cc index 9253a2701d3..46e29a63b3a 100644 --- a/source/blender/nodes/texture/nodes/node_texture_invert.cc +++ b/source/blender/nodes/texture/nodes/node_texture_invert.cc @@ -47,7 +47,7 @@ void register_node_type_tex_invert() { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR); + tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert Color", NODE_CLASS_OP_COLOR); node_type_socket_templates(&ntype, inputs, outputs); ntype.exec_fn = exec; diff --git a/source/blender/render/intern/bake.cc b/source/blender/render/intern/bake.cc index b6600a43d9e..3cffb99078b 100644 --- a/source/blender/render/intern/bake.cc +++ b/source/blender/render/intern/bake.cc @@ -579,7 +579,7 @@ bool RE_bake_pixels_populate_from_objects(Mesh *me_low, treeData = MEM_cnew_array(tot_highpoly, "Highpoly BVH Trees"); if (!is_cage) { - me_eval_low = BKE_mesh_copy_for_eval(me_low, false); + me_eval_low = BKE_mesh_copy_for_eval(me_low); tris_low = mesh_calc_tri_tessface(me_low, true, me_eval_low); } else if (is_custom_cage) { @@ -854,7 +854,7 @@ void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[], TriTessFace *triangles; - Mesh *me_eval = BKE_mesh_copy_for_eval(me, false); + Mesh *me_eval = BKE_mesh_copy_for_eval(me); triangles = mesh_calc_tri_tessface(me, true, me_eval); diff --git a/source/blender/render/intern/multires_bake.cc b/source/blender/render/intern/multires_bake.cc index fedddec9025..097fad22b45 100644 --- a/source/blender/render/intern/multires_bake.cc +++ b/source/blender/render/intern/multires_bake.cc @@ -492,7 +492,7 @@ static void do_multires_bake(MultiresBakeRender *bkr, void *bake_data = nullptr; Mesh *temp_mesh = BKE_mesh_new_nomain( - dm->getNumVerts(dm), dm->getNumEdges(dm), dm->getNumLoops(dm), dm->getNumPolys(dm)); + dm->getNumVerts(dm), dm->getNumEdges(dm), dm->getNumPolys(dm), dm->getNumLoops(dm)); temp_mesh->vert_positions_for_write().copy_from( {reinterpret_cast(dm->getVertArray(dm)), temp_mesh->totvert}); temp_mesh->edges_for_write().copy_from( diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc index 8b1175a06c8..309d9c36b04 100644 --- a/source/blender/render/intern/texture_margin.cc +++ b/source/blender/render/intern/texture_margin.cc @@ -476,11 +476,12 @@ static void generate_margin(ImBuf *ibuf, const int edges_num, const OffsetIndices polys, const Span corner_edges, + const Span corner_verts, const Span mloopuv, const float uv_offset[2]) { Array looptris(poly_to_tri_count(polys.size(), corner_edges.size())); - bke::mesh::looptris_calc(vert_positions, polys, corner_edges, looptris); + bke::mesh::looptris_calc(vert_positions, polys, corner_verts, looptris); TextureMarginMap map(ibuf->x, ibuf->y, uv_offset, edges_num, polys, corner_edges, mloopuv); @@ -563,6 +564,7 @@ void RE_generate_texturemargin_adjacentfaces(ImBuf *ibuf, mesh->totedge, mesh->polys(), mesh->corner_edges(), + mesh->corner_verts(), {mloopuv, mesh->totloop}, uv_offset); } @@ -581,6 +583,7 @@ void RE_generate_texturemargin_adjacentfaces_dm( dm->getNumEdges(dm), blender::Span(dm->getPolyArray(dm), dm->getNumPolys(dm) + 1), {dm->getCornerEdgeArray(dm), dm->getNumLoops(dm)}, + {dm->getCornerVertArray(dm), dm->getNumLoops(dm)}, {mloopuv, dm->getNumLoops(dm)}, uv_offset); } diff --git a/source/blender/windowmanager/intern/wm_init_exit.cc b/source/blender/windowmanager/intern/wm_init_exit.cc index 7da2a8fb963..764177fcc18 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.cc +++ b/source/blender/windowmanager/intern/wm_init_exit.cc @@ -375,7 +375,7 @@ static bool wm_init_splash_show_on_startup_check() else { /* A less common case, if there is no user preferences, show the splash screen * so the user has the opportunity to restore settings from a previous version. */ - const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); + const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr); if (cfgdir) { char userpref[FILE_MAX]; BLI_path_join(userpref, sizeof(userpref), cfgdir, BLENDER_USERPREF_FILE); diff --git a/tools/utils_maintenance/autopep8_format_paths.py b/tools/utils_maintenance/autopep8_format_paths.py index 2412aad2bfd..7b8c9c036c7 100755 --- a/tools/utils_maintenance/autopep8_format_paths.py +++ b/tools/utils_maintenance/autopep8_format_paths.py @@ -48,6 +48,7 @@ def compute_paths(paths: List[str], use_default_paths: bool) -> List[str]: "build_files", "intern", "release", + "scripts", "doc", "source", "tests",